souleyez 2.43.29__py3-none-any.whl → 2.43.32__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. souleyez/__init__.py +1 -2
  2. souleyez/ai/__init__.py +21 -15
  3. souleyez/ai/action_mapper.py +249 -150
  4. souleyez/ai/chain_advisor.py +116 -100
  5. souleyez/ai/claude_provider.py +29 -28
  6. souleyez/ai/context_builder.py +80 -62
  7. souleyez/ai/executor.py +158 -117
  8. souleyez/ai/feedback_handler.py +136 -121
  9. souleyez/ai/llm_factory.py +27 -20
  10. souleyez/ai/llm_provider.py +4 -2
  11. souleyez/ai/ollama_provider.py +6 -9
  12. souleyez/ai/ollama_service.py +44 -37
  13. souleyez/ai/path_scorer.py +91 -76
  14. souleyez/ai/recommender.py +176 -144
  15. souleyez/ai/report_context.py +74 -73
  16. souleyez/ai/report_service.py +84 -66
  17. souleyez/ai/result_parser.py +222 -229
  18. souleyez/ai/safety.py +67 -44
  19. souleyez/auth/__init__.py +23 -22
  20. souleyez/auth/audit.py +36 -26
  21. souleyez/auth/engagement_access.py +65 -48
  22. souleyez/auth/permissions.py +14 -3
  23. souleyez/auth/session_manager.py +54 -37
  24. souleyez/auth/user_manager.py +109 -64
  25. souleyez/commands/audit.py +40 -43
  26. souleyez/commands/auth.py +35 -15
  27. souleyez/commands/deliverables.py +55 -50
  28. souleyez/commands/engagement.py +47 -28
  29. souleyez/commands/license.py +32 -23
  30. souleyez/commands/screenshots.py +36 -32
  31. souleyez/commands/user.py +82 -36
  32. souleyez/config.py +52 -44
  33. souleyez/core/credential_tester.py +87 -81
  34. souleyez/core/cve_mappings.py +179 -192
  35. souleyez/core/cve_matcher.py +162 -148
  36. souleyez/core/msf_auto_mapper.py +100 -83
  37. souleyez/core/msf_chain_engine.py +294 -256
  38. souleyez/core/msf_database.py +153 -70
  39. souleyez/core/msf_integration.py +679 -673
  40. souleyez/core/msf_rpc_client.py +40 -42
  41. souleyez/core/msf_rpc_manager.py +77 -79
  42. souleyez/core/msf_sync_manager.py +241 -181
  43. souleyez/core/network_utils.py +22 -15
  44. souleyez/core/parser_handler.py +34 -25
  45. souleyez/core/pending_chains.py +114 -63
  46. souleyez/core/templates.py +158 -107
  47. souleyez/core/tool_chaining.py +9592 -2879
  48. souleyez/core/version_utils.py +79 -94
  49. souleyez/core/vuln_correlation.py +136 -89
  50. souleyez/core/web_utils.py +33 -32
  51. souleyez/data/wordlists/ad_users.txt +378 -0
  52. souleyez/data/wordlists/api_endpoints_large.txt +769 -0
  53. souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
  54. souleyez/data/wordlists/lfi_payloads.txt +82 -0
  55. souleyez/data/wordlists/passwords_brute.txt +1548 -0
  56. souleyez/data/wordlists/passwords_crack.txt +2479 -0
  57. souleyez/data/wordlists/passwords_spray.txt +386 -0
  58. souleyez/data/wordlists/subdomains_large.txt +5057 -0
  59. souleyez/data/wordlists/usernames_common.txt +694 -0
  60. souleyez/data/wordlists/web_dirs_large.txt +4769 -0
  61. souleyez/detection/__init__.py +1 -1
  62. souleyez/detection/attack_signatures.py +12 -17
  63. souleyez/detection/mitre_mappings.py +61 -55
  64. souleyez/detection/validator.py +97 -86
  65. souleyez/devtools.py +23 -10
  66. souleyez/docs/README.md +4 -4
  67. souleyez/docs/api-reference/cli-commands.md +2 -2
  68. souleyez/docs/developer-guide/adding-new-tools.md +562 -0
  69. souleyez/docs/user-guide/auto-chaining.md +30 -8
  70. souleyez/docs/user-guide/getting-started.md +1 -1
  71. souleyez/docs/user-guide/installation.md +26 -3
  72. souleyez/docs/user-guide/metasploit-integration.md +2 -2
  73. souleyez/docs/user-guide/rbac.md +1 -1
  74. souleyez/docs/user-guide/scope-management.md +1 -1
  75. souleyez/docs/user-guide/siem-integration.md +1 -1
  76. souleyez/docs/user-guide/tools-reference.md +1 -8
  77. souleyez/docs/user-guide/worker-management.md +1 -1
  78. souleyez/engine/background.py +1238 -535
  79. souleyez/engine/base.py +4 -1
  80. souleyez/engine/job_status.py +17 -49
  81. souleyez/engine/log_sanitizer.py +103 -77
  82. souleyez/engine/manager.py +38 -7
  83. souleyez/engine/result_handler.py +2198 -1550
  84. souleyez/engine/worker_manager.py +50 -41
  85. souleyez/export/evidence_bundle.py +72 -62
  86. souleyez/feature_flags/features.py +16 -20
  87. souleyez/feature_flags.py +5 -9
  88. souleyez/handlers/__init__.py +11 -0
  89. souleyez/handlers/base.py +188 -0
  90. souleyez/handlers/bash_handler.py +277 -0
  91. souleyez/handlers/bloodhound_handler.py +243 -0
  92. souleyez/handlers/certipy_handler.py +311 -0
  93. souleyez/handlers/crackmapexec_handler.py +486 -0
  94. souleyez/handlers/dnsrecon_handler.py +344 -0
  95. souleyez/handlers/enum4linux_handler.py +400 -0
  96. souleyez/handlers/evil_winrm_handler.py +493 -0
  97. souleyez/handlers/ffuf_handler.py +815 -0
  98. souleyez/handlers/gobuster_handler.py +1114 -0
  99. souleyez/handlers/gpp_extract_handler.py +334 -0
  100. souleyez/handlers/hashcat_handler.py +444 -0
  101. souleyez/handlers/hydra_handler.py +563 -0
  102. souleyez/handlers/impacket_getuserspns_handler.py +343 -0
  103. souleyez/handlers/impacket_psexec_handler.py +222 -0
  104. souleyez/handlers/impacket_secretsdump_handler.py +426 -0
  105. souleyez/handlers/john_handler.py +286 -0
  106. souleyez/handlers/katana_handler.py +425 -0
  107. souleyez/handlers/kerbrute_handler.py +298 -0
  108. souleyez/handlers/ldapsearch_handler.py +636 -0
  109. souleyez/handlers/lfi_extract_handler.py +464 -0
  110. souleyez/handlers/msf_auxiliary_handler.py +408 -0
  111. souleyez/handlers/msf_exploit_handler.py +380 -0
  112. souleyez/handlers/nikto_handler.py +413 -0
  113. souleyez/handlers/nmap_handler.py +821 -0
  114. souleyez/handlers/nuclei_handler.py +359 -0
  115. souleyez/handlers/nxc_handler.py +371 -0
  116. souleyez/handlers/rdp_sec_check_handler.py +353 -0
  117. souleyez/handlers/registry.py +288 -0
  118. souleyez/handlers/responder_handler.py +232 -0
  119. souleyez/handlers/service_explorer_handler.py +434 -0
  120. souleyez/handlers/smbclient_handler.py +344 -0
  121. souleyez/handlers/smbmap_handler.py +510 -0
  122. souleyez/handlers/smbpasswd_handler.py +296 -0
  123. souleyez/handlers/sqlmap_handler.py +1116 -0
  124. souleyez/handlers/theharvester_handler.py +601 -0
  125. souleyez/handlers/whois_handler.py +277 -0
  126. souleyez/handlers/wpscan_handler.py +554 -0
  127. souleyez/history.py +32 -16
  128. souleyez/importers/msf_importer.py +106 -75
  129. souleyez/importers/smart_importer.py +208 -147
  130. souleyez/integrations/siem/__init__.py +10 -10
  131. souleyez/integrations/siem/base.py +17 -18
  132. souleyez/integrations/siem/elastic.py +108 -122
  133. souleyez/integrations/siem/factory.py +207 -80
  134. souleyez/integrations/siem/googlesecops.py +146 -154
  135. souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
  136. souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
  137. souleyez/integrations/siem/sentinel.py +107 -109
  138. souleyez/integrations/siem/splunk.py +246 -212
  139. souleyez/integrations/siem/wazuh.py +65 -71
  140. souleyez/integrations/wazuh/__init__.py +5 -5
  141. souleyez/integrations/wazuh/client.py +70 -93
  142. souleyez/integrations/wazuh/config.py +85 -57
  143. souleyez/integrations/wazuh/host_mapper.py +28 -36
  144. souleyez/integrations/wazuh/sync.py +78 -68
  145. souleyez/intelligence/__init__.py +4 -5
  146. souleyez/intelligence/correlation_analyzer.py +309 -295
  147. souleyez/intelligence/exploit_knowledge.py +661 -623
  148. souleyez/intelligence/exploit_suggestions.py +159 -139
  149. souleyez/intelligence/gap_analyzer.py +132 -97
  150. souleyez/intelligence/gap_detector.py +251 -214
  151. souleyez/intelligence/sensitive_tables.py +266 -129
  152. souleyez/intelligence/service_parser.py +137 -123
  153. souleyez/intelligence/surface_analyzer.py +407 -268
  154. souleyez/intelligence/target_parser.py +159 -162
  155. souleyez/licensing/__init__.py +6 -6
  156. souleyez/licensing/validator.py +17 -19
  157. souleyez/log_config.py +79 -54
  158. souleyez/main.py +1505 -687
  159. souleyez/migrations/fix_job_counter.py +16 -14
  160. souleyez/parsers/bloodhound_parser.py +41 -39
  161. souleyez/parsers/crackmapexec_parser.py +178 -111
  162. souleyez/parsers/dalfox_parser.py +72 -77
  163. souleyez/parsers/dnsrecon_parser.py +103 -91
  164. souleyez/parsers/enum4linux_parser.py +183 -153
  165. souleyez/parsers/ffuf_parser.py +29 -25
  166. souleyez/parsers/gobuster_parser.py +301 -41
  167. souleyez/parsers/hashcat_parser.py +324 -79
  168. souleyez/parsers/http_fingerprint_parser.py +350 -103
  169. souleyez/parsers/hydra_parser.py +131 -111
  170. souleyez/parsers/impacket_parser.py +231 -178
  171. souleyez/parsers/john_parser.py +98 -86
  172. souleyez/parsers/katana_parser.py +316 -0
  173. souleyez/parsers/msf_parser.py +943 -498
  174. souleyez/parsers/nikto_parser.py +346 -65
  175. souleyez/parsers/nmap_parser.py +262 -174
  176. souleyez/parsers/nuclei_parser.py +40 -44
  177. souleyez/parsers/responder_parser.py +26 -26
  178. souleyez/parsers/searchsploit_parser.py +74 -74
  179. souleyez/parsers/service_explorer_parser.py +279 -0
  180. souleyez/parsers/smbmap_parser.py +180 -124
  181. souleyez/parsers/sqlmap_parser.py +434 -308
  182. souleyez/parsers/theharvester_parser.py +75 -57
  183. souleyez/parsers/whois_parser.py +135 -94
  184. souleyez/parsers/wpscan_parser.py +278 -190
  185. souleyez/plugins/afp.py +44 -36
  186. souleyez/plugins/afp_brute.py +114 -46
  187. souleyez/plugins/ard.py +48 -37
  188. souleyez/plugins/bloodhound.py +95 -61
  189. souleyez/plugins/certipy.py +303 -0
  190. souleyez/plugins/crackmapexec.py +186 -85
  191. souleyez/plugins/dalfox.py +120 -59
  192. souleyez/plugins/dns_hijack.py +146 -41
  193. souleyez/plugins/dnsrecon.py +97 -61
  194. souleyez/plugins/enum4linux.py +91 -66
  195. souleyez/plugins/evil_winrm.py +291 -0
  196. souleyez/plugins/ffuf.py +166 -90
  197. souleyez/plugins/firmware_extract.py +133 -29
  198. souleyez/plugins/gobuster.py +387 -190
  199. souleyez/plugins/gpp_extract.py +393 -0
  200. souleyez/plugins/hashcat.py +100 -73
  201. souleyez/plugins/http_fingerprint.py +854 -267
  202. souleyez/plugins/hydra.py +566 -200
  203. souleyez/plugins/impacket_getnpusers.py +117 -69
  204. souleyez/plugins/impacket_psexec.py +84 -64
  205. souleyez/plugins/impacket_secretsdump.py +103 -69
  206. souleyez/plugins/impacket_smbclient.py +89 -75
  207. souleyez/plugins/john.py +86 -69
  208. souleyez/plugins/katana.py +313 -0
  209. souleyez/plugins/kerbrute.py +237 -0
  210. souleyez/plugins/lfi_extract.py +541 -0
  211. souleyez/plugins/macos_ssh.py +117 -48
  212. souleyez/plugins/mdns.py +35 -30
  213. souleyez/plugins/msf_auxiliary.py +253 -130
  214. souleyez/plugins/msf_exploit.py +239 -161
  215. souleyez/plugins/nikto.py +134 -78
  216. souleyez/plugins/nmap.py +275 -91
  217. souleyez/plugins/nuclei.py +180 -89
  218. souleyez/plugins/nxc.py +285 -0
  219. souleyez/plugins/plugin_base.py +35 -36
  220. souleyez/plugins/plugin_template.py +13 -5
  221. souleyez/plugins/rdp_sec_check.py +130 -0
  222. souleyez/plugins/responder.py +112 -71
  223. souleyez/plugins/router_http_brute.py +76 -65
  224. souleyez/plugins/router_ssh_brute.py +118 -41
  225. souleyez/plugins/router_telnet_brute.py +124 -42
  226. souleyez/plugins/routersploit.py +91 -59
  227. souleyez/plugins/routersploit_exploit.py +77 -55
  228. souleyez/plugins/searchsploit.py +91 -77
  229. souleyez/plugins/service_explorer.py +1160 -0
  230. souleyez/plugins/smbmap.py +122 -72
  231. souleyez/plugins/smbpasswd.py +215 -0
  232. souleyez/plugins/sqlmap.py +301 -113
  233. souleyez/plugins/theharvester.py +127 -75
  234. souleyez/plugins/tr069.py +79 -57
  235. souleyez/plugins/upnp.py +65 -47
  236. souleyez/plugins/upnp_abuse.py +73 -55
  237. souleyez/plugins/vnc_access.py +129 -42
  238. souleyez/plugins/vnc_brute.py +109 -38
  239. souleyez/plugins/whois.py +77 -58
  240. souleyez/plugins/wpscan.py +173 -69
  241. souleyez/reporting/__init__.py +2 -1
  242. souleyez/reporting/attack_chain.py +411 -346
  243. souleyez/reporting/charts.py +436 -501
  244. souleyez/reporting/compliance_mappings.py +334 -201
  245. souleyez/reporting/detection_report.py +126 -125
  246. souleyez/reporting/formatters.py +828 -591
  247. souleyez/reporting/generator.py +386 -302
  248. souleyez/reporting/metrics.py +72 -75
  249. souleyez/scanner.py +35 -29
  250. souleyez/security/__init__.py +37 -11
  251. souleyez/security/scope_validator.py +175 -106
  252. souleyez/security/validation.py +223 -149
  253. souleyez/security.py +22 -6
  254. souleyez/storage/credentials.py +247 -186
  255. souleyez/storage/crypto.py +296 -129
  256. souleyez/storage/database.py +73 -50
  257. souleyez/storage/db.py +58 -36
  258. souleyez/storage/deliverable_evidence.py +177 -128
  259. souleyez/storage/deliverable_exporter.py +282 -246
  260. souleyez/storage/deliverable_templates.py +134 -116
  261. souleyez/storage/deliverables.py +135 -130
  262. souleyez/storage/engagements.py +109 -56
  263. souleyez/storage/evidence.py +181 -152
  264. souleyez/storage/execution_log.py +31 -17
  265. souleyez/storage/exploit_attempts.py +93 -57
  266. souleyez/storage/exploits.py +67 -36
  267. souleyez/storage/findings.py +48 -61
  268. souleyez/storage/hosts.py +176 -144
  269. souleyez/storage/migrate_to_engagements.py +43 -19
  270. souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
  271. souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
  272. souleyez/storage/migrations/_003_add_execution_log.py +14 -8
  273. souleyez/storage/migrations/_005_screenshots.py +13 -5
  274. souleyez/storage/migrations/_006_deliverables.py +13 -5
  275. souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
  276. souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
  277. souleyez/storage/migrations/_010_evidence_linking.py +17 -10
  278. souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
  279. souleyez/storage/migrations/_012_team_collaboration.py +34 -21
  280. souleyez/storage/migrations/_013_add_host_tags.py +12 -6
  281. souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
  282. souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
  283. souleyez/storage/migrations/_016_add_domain_field.py +10 -4
  284. souleyez/storage/migrations/_017_msf_sessions.py +16 -8
  285. souleyez/storage/migrations/_018_add_osint_target.py +10 -6
  286. souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
  287. souleyez/storage/migrations/_020_add_rbac.py +36 -15
  288. souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
  289. souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
  290. souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
  291. souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
  292. souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
  293. souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
  294. souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
  295. souleyez/storage/migrations/__init__.py +26 -26
  296. souleyez/storage/migrations/migration_manager.py +19 -19
  297. souleyez/storage/msf_sessions.py +100 -65
  298. souleyez/storage/osint.py +17 -24
  299. souleyez/storage/recommendation_engine.py +269 -235
  300. souleyez/storage/screenshots.py +33 -32
  301. souleyez/storage/smb_shares.py +136 -92
  302. souleyez/storage/sqlmap_data.py +183 -128
  303. souleyez/storage/team_collaboration.py +135 -141
  304. souleyez/storage/timeline_tracker.py +122 -94
  305. souleyez/storage/wazuh_vulns.py +64 -66
  306. souleyez/storage/web_paths.py +33 -37
  307. souleyez/testing/credential_tester.py +221 -205
  308. souleyez/ui/__init__.py +1 -1
  309. souleyez/ui/ai_quotes.py +12 -12
  310. souleyez/ui/attack_surface.py +2439 -1516
  311. souleyez/ui/chain_rules_view.py +914 -382
  312. souleyez/ui/correlation_view.py +312 -230
  313. souleyez/ui/dashboard.py +2382 -1130
  314. souleyez/ui/deliverables_view.py +148 -62
  315. souleyez/ui/design_system.py +13 -13
  316. souleyez/ui/errors.py +49 -49
  317. souleyez/ui/evidence_linking_view.py +284 -179
  318. souleyez/ui/evidence_vault.py +393 -285
  319. souleyez/ui/exploit_suggestions_view.py +555 -349
  320. souleyez/ui/export_view.py +100 -66
  321. souleyez/ui/gap_analysis_view.py +315 -171
  322. souleyez/ui/help_system.py +105 -97
  323. souleyez/ui/intelligence_view.py +436 -293
  324. souleyez/ui/interactive.py +22783 -10678
  325. souleyez/ui/interactive_selector.py +75 -68
  326. souleyez/ui/log_formatter.py +47 -39
  327. souleyez/ui/menu_components.py +22 -13
  328. souleyez/ui/msf_auxiliary_menu.py +184 -133
  329. souleyez/ui/pending_chains_view.py +336 -172
  330. souleyez/ui/progress_indicators.py +5 -3
  331. souleyez/ui/recommendations_view.py +195 -137
  332. souleyez/ui/rule_builder.py +343 -225
  333. souleyez/ui/setup_wizard.py +678 -284
  334. souleyez/ui/shortcuts.py +217 -165
  335. souleyez/ui/splunk_gap_analysis_view.py +452 -270
  336. souleyez/ui/splunk_vulns_view.py +139 -86
  337. souleyez/ui/team_dashboard.py +498 -335
  338. souleyez/ui/template_selector.py +196 -105
  339. souleyez/ui/terminal.py +6 -6
  340. souleyez/ui/timeline_view.py +198 -127
  341. souleyez/ui/tool_setup.py +264 -164
  342. souleyez/ui/tutorial.py +202 -72
  343. souleyez/ui/tutorial_state.py +40 -40
  344. souleyez/ui/wazuh_vulns_view.py +235 -141
  345. souleyez/ui/wordlist_browser.py +260 -107
  346. souleyez/ui.py +464 -312
  347. souleyez/utils/tool_checker.py +427 -367
  348. souleyez/utils.py +33 -29
  349. souleyez/wordlists.py +134 -167
  350. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/METADATA +1 -1
  351. souleyez-2.43.32.dist-info/RECORD +441 -0
  352. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/WHEEL +1 -1
  353. souleyez-2.43.29.dist-info/RECORD +0 -379
  354. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/entry_points.txt +0 -0
  355. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/licenses/LICENSE +0 -0
  356. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/top_level.txt +0 -0
@@ -18,53 +18,56 @@ logger = logging.getLogger(__name__)
18
18
 
19
19
  class ChainAdvisorMode(Enum):
20
20
  """AI chain recommendation modes."""
21
- OFF = 'off' # No AI involvement
22
- SUGGEST = 'suggest' # Show recommendations, don't auto-queue
23
- AUTO = 'auto' # Auto-queue AI recommendations
21
+
22
+ OFF = "off" # No AI involvement
23
+ SUGGEST = "suggest" # Show recommendations, don't auto-queue
24
+ AUTO = "auto" # Auto-queue AI recommendations
24
25
 
25
26
 
26
27
  @dataclass
27
28
  class AIChainRecommendation:
28
29
  """Single tool recommendation from LLM."""
30
+
29
31
  tool: str
30
32
  target: str
31
33
  args: List[str] = field(default_factory=list)
32
- priority: int = 5 # 1-10
33
- rationale: str = ''
34
- confidence: float = 0.7 # 0.0-1.0
35
- expected_outcome: str = ''
36
- risk_level: str = 'medium' # low/medium/high
34
+ priority: int = 5 # 1-10
35
+ rationale: str = ""
36
+ confidence: float = 0.7 # 0.0-1.0
37
+ expected_outcome: str = ""
38
+ risk_level: str = "medium" # low/medium/high
37
39
 
38
40
 
39
41
  @dataclass
40
42
  class AIChainAnalysis:
41
43
  """Complete AI analysis of scan results."""
44
+
42
45
  recommendations: List[AIChainRecommendation]
43
- summary: str = ''
46
+ summary: str = ""
44
47
  static_rules_applied: List[str] = field(default_factory=list)
45
48
  analysis_time_ms: int = 0
46
- provider: str = ''
49
+ provider: str = ""
47
50
  error: Optional[str] = None
48
51
 
49
52
 
50
53
  # Available tools for recommendations (must match actual plugins in souleyez/plugins/)
51
54
  AVAILABLE_TOOLS = {
52
- 'nmap': 'Network scanning, service detection, OS fingerprinting',
53
- 'nuclei': 'Vulnerability scanning with templates (CVEs, misconfigs)',
54
- 'nikto': 'Web server vulnerability scanner',
55
- 'gobuster': 'Directory/file brute-forcing',
56
- 'ffuf': 'Web fuzzing (parameters, directories)',
57
- 'sqlmap': 'SQL injection detection and exploitation',
58
- 'wpscan': 'WordPress vulnerability scanner',
59
- 'hydra': 'Brute-force password cracking',
60
- 'enum4linux': 'SMB/NetBIOS enumeration',
61
- 'smbmap': 'SMB share enumeration',
62
- 'crackmapexec': 'Windows/AD enumeration and exploitation',
63
- 'dnsrecon': 'DNS enumeration and zone transfers',
64
- 'theharvester': 'OSINT - emails, subdomains, IPs',
65
- 'dalfox': 'XSS vulnerability scanner',
66
- 'searchsploit': 'Exploit database search',
67
- 'bloodhound': 'Active Directory attack path mapping',
55
+ "nmap": "Network scanning, service detection, OS fingerprinting",
56
+ "nuclei": "Vulnerability scanning with templates (CVEs, misconfigs)",
57
+ "nikto": "Web server vulnerability scanner",
58
+ "gobuster": "Directory/file brute-forcing",
59
+ "ffuf": "Web fuzzing (parameters, directories)",
60
+ "sqlmap": "SQL injection detection and exploitation",
61
+ "wpscan": "WordPress vulnerability scanner",
62
+ "hydra": "Brute-force password cracking",
63
+ "enum4linux": "SMB/NetBIOS enumeration",
64
+ "smbmap": "SMB share enumeration",
65
+ "crackmapexec": "Windows/AD enumeration and exploitation",
66
+ "dnsrecon": "DNS enumeration and zone transfers",
67
+ "theharvester": "OSINT - emails, subdomains, IPs",
68
+ "dalfox": "XSS vulnerability scanner",
69
+ "searchsploit": "Exploit database search",
70
+ "bloodhound": "Active Directory attack path mapping",
68
71
  }
69
72
 
70
73
 
@@ -121,7 +124,9 @@ Guidelines:
121
124
  - Focus on high-value services (databases, admin panels, etc.)
122
125
  """
123
126
 
124
- def __init__(self, provider=None, mode: ChainAdvisorMode = ChainAdvisorMode.SUGGEST):
127
+ def __init__(
128
+ self, provider=None, mode: ChainAdvisorMode = ChainAdvisorMode.SUGGEST
129
+ ):
125
130
  """
126
131
  Initialize chain advisor.
127
132
 
@@ -153,7 +158,7 @@ Guidelines:
153
158
  target: str,
154
159
  parse_results: Dict[str, Any],
155
160
  static_commands: List[Dict[str, Any]],
156
- engagement_id: Optional[int] = None
161
+ engagement_id: Optional[int] = None,
157
162
  ) -> AIChainAnalysis:
158
163
  """
159
164
  Analyze scan results and recommend next tools.
@@ -169,13 +174,13 @@ Guidelines:
169
174
  AIChainAnalysis with recommendations, or error if failed
170
175
  """
171
176
  import time
177
+
172
178
  start_time = time.time()
173
179
 
174
180
  # Check mode
175
181
  if self.mode == ChainAdvisorMode.OFF:
176
182
  return AIChainAnalysis(
177
- recommendations=[],
178
- error='AI chain analysis is disabled'
183
+ recommendations=[], error="AI chain analysis is disabled"
179
184
  )
180
185
 
181
186
  # Ensure provider is available
@@ -183,12 +188,13 @@ Guidelines:
183
188
  if not self.provider or not self.provider.is_available():
184
189
  logger.debug("AI provider not available for chain analysis")
185
190
  return AIChainAnalysis(
186
- recommendations=[],
187
- error='AI provider not available'
191
+ recommendations=[], error="AI provider not available"
188
192
  )
189
193
 
190
194
  # Build prompt
191
- prompt = self._build_analysis_prompt(tool, target, parse_results, static_commands)
195
+ prompt = self._build_analysis_prompt(
196
+ tool, target, parse_results, static_commands
197
+ )
192
198
 
193
199
  # Generate recommendations
194
200
  try:
@@ -196,14 +202,13 @@ Guidelines:
196
202
  prompt=prompt,
197
203
  system_prompt=self.SYSTEM_PROMPT,
198
204
  max_tokens=2000,
199
- temperature=0.3 # Lower for consistent tool recommendations
205
+ temperature=0.3, # Lower for consistent tool recommendations
200
206
  )
201
207
 
202
208
  if not response:
203
209
  logger.warning("AI returned empty chain analysis")
204
210
  return AIChainAnalysis(
205
- recommendations=[],
206
- error='Empty response from AI provider'
211
+ recommendations=[], error="Empty response from AI provider"
207
212
  )
208
213
 
209
214
  # Parse recommendations
@@ -211,98 +216,103 @@ Guidelines:
211
216
 
212
217
  # Filter out low-confidence recommendations
213
218
  min_confidence = 0.6
214
- recommendations = [r for r in recommendations if r.confidence >= min_confidence]
219
+ recommendations = [
220
+ r for r in recommendations if r.confidence >= min_confidence
221
+ ]
215
222
 
216
223
  # Filter duplicates with static commands
217
224
  recommendations = self._filter_duplicates(recommendations, static_commands)
218
225
 
219
226
  elapsed_ms = int((time.time() - start_time) * 1000)
220
- provider_name = getattr(self.provider, 'provider_type', 'unknown')
227
+ provider_name = getattr(self.provider, "provider_type", "unknown")
221
228
 
222
229
  return AIChainAnalysis(
223
230
  recommendations=recommendations,
224
231
  summary=f"AI suggested {len(recommendations)} additional tools",
225
- static_rules_applied=[cmd.get('description', '') for cmd in static_commands],
232
+ static_rules_applied=[
233
+ cmd.get("description", "") for cmd in static_commands
234
+ ],
226
235
  analysis_time_ms=elapsed_ms,
227
- provider=str(provider_name)
236
+ provider=str(provider_name),
228
237
  )
229
238
 
230
239
  except Exception as e:
231
240
  logger.error(f"AI chain analysis failed: {e}")
232
- return AIChainAnalysis(
233
- recommendations=[],
234
- error=str(e)
235
- )
241
+ return AIChainAnalysis(recommendations=[], error=str(e))
236
242
 
237
243
  def _build_analysis_prompt(
238
244
  self,
239
245
  tool: str,
240
246
  target: str,
241
247
  parse_results: Dict[str, Any],
242
- static_commands: List[Dict[str, Any]]
248
+ static_commands: List[Dict[str, Any]],
243
249
  ) -> str:
244
250
  """Build LLM prompt for chain analysis."""
245
251
  # Format results summary
246
252
  results_lines = []
247
253
 
248
254
  # Add hosts
249
- hosts = parse_results.get('hosts', [])
255
+ hosts = parse_results.get("hosts", [])
250
256
  if hosts:
251
257
  results_lines.append(f"Hosts discovered: {len(hosts)}")
252
258
  for host in hosts[:5]: # Limit to first 5
253
- ip = host.get('ip', 'unknown')
254
- os_name = host.get('os', 'unknown')
259
+ ip = host.get("ip", "unknown")
260
+ os_name = host.get("os", "unknown")
255
261
  results_lines.append(f" - {ip} (OS: {os_name})")
256
262
 
257
263
  # Add services
258
- services = parse_results.get('services', [])
264
+ services = parse_results.get("services", [])
259
265
  if services:
260
266
  results_lines.append(f"\nServices found: {len(services)}")
261
267
  for svc in services[:10]: # Limit to first 10
262
- ip = svc.get('ip', target)
263
- port = svc.get('port', '?')
264
- name = svc.get('service_name', svc.get('service', 'unknown'))
265
- product = svc.get('product', '')
266
- version = svc.get('version', '')
267
- ver_str = f" {product} {version}".strip() if product or version else ''
268
+ ip = svc.get("ip", target)
269
+ port = svc.get("port", "?")
270
+ name = svc.get("service_name", svc.get("service", "unknown"))
271
+ product = svc.get("product", "")
272
+ version = svc.get("version", "")
273
+ ver_str = f" {product} {version}".strip() if product or version else ""
268
274
  results_lines.append(f" - {ip}:{port} - {name}{ver_str}")
269
275
 
270
276
  # Add findings
271
- findings = parse_results.get('findings', [])
277
+ findings = parse_results.get("findings", [])
272
278
  if findings:
273
279
  results_lines.append(f"\nFindings: {len(findings)}")
274
280
  for finding in findings[:5]: # Limit to first 5
275
- title = finding.get('title', 'unknown')
276
- severity = finding.get('severity', 'info')
281
+ title = finding.get("title", "unknown")
282
+ severity = finding.get("severity", "info")
277
283
  results_lines.append(f" - [{severity.upper()}] {title}")
278
284
 
279
285
  # Add credentials
280
- credentials = parse_results.get('credentials', [])
286
+ credentials = parse_results.get("credentials", [])
281
287
  if credentials:
282
288
  results_lines.append(f"\nCredentials found: {len(credentials)}")
283
289
 
284
- results_summary = '\n'.join(results_lines) if results_lines else 'No structured results parsed.'
290
+ results_summary = (
291
+ "\n".join(results_lines)
292
+ if results_lines
293
+ else "No structured results parsed."
294
+ )
285
295
 
286
296
  # Format static commands
287
297
  static_lines = []
288
298
  for cmd in static_commands:
289
- tool_name = cmd.get('tool', 'unknown')
290
- desc = cmd.get('description', '')
299
+ tool_name = cmd.get("tool", "unknown")
300
+ desc = cmd.get("description", "")
291
301
  static_lines.append(f" - {tool_name}: {desc}")
292
- static_summary = '\n'.join(static_lines) if static_lines else ' (none)'
302
+ static_summary = "\n".join(static_lines) if static_lines else " (none)"
293
303
 
294
304
  # Format available tools
295
305
  tools_lines = []
296
306
  for tool_name, desc in AVAILABLE_TOOLS.items():
297
307
  tools_lines.append(f" - {tool_name}: {desc}")
298
- tools_summary = '\n'.join(tools_lines)
308
+ tools_summary = "\n".join(tools_lines)
299
309
 
300
310
  return self.ANALYSIS_TEMPLATE.format(
301
311
  tool=tool,
302
312
  target=target,
303
313
  results_summary=results_summary,
304
314
  static_commands=static_summary,
305
- available_tools=tools_summary
315
+ available_tools=tools_summary,
306
316
  )
307
317
 
308
318
  def _parse_recommendations(self, response: str) -> List[AIChainRecommendation]:
@@ -310,11 +320,11 @@ Guidelines:
310
320
  recommendations = []
311
321
 
312
322
  # Check for no recommendations response
313
- if 'NO_RECOMMENDATIONS' in response.upper():
323
+ if "NO_RECOMMENDATIONS" in response.upper():
314
324
  return []
315
325
 
316
326
  # Split by separator
317
- sections = response.split('---')
327
+ sections = response.split("---")
318
328
 
319
329
  for section in sections:
320
330
  section = section.strip()
@@ -331,17 +341,23 @@ Guidelines:
331
341
 
332
342
  return recommendations
333
343
 
334
- def _parse_single_recommendation(self, section: str) -> Optional[AIChainRecommendation]:
344
+ def _parse_single_recommendation(
345
+ self, section: str
346
+ ) -> Optional[AIChainRecommendation]:
335
347
  """Parse a single recommendation section."""
336
348
  # Extract fields
337
- tool_match = re.search(r'TOOL:\s*(.+?)(?=\n|$)', section, re.IGNORECASE)
338
- target_match = re.search(r'TARGET:\s*(.+?)(?=\n|$)', section, re.IGNORECASE)
339
- args_match = re.search(r'ARGS:\s*(.+?)(?=\n|$)', section, re.IGNORECASE)
340
- priority_match = re.search(r'PRIORITY:\s*(\d+)', section, re.IGNORECASE)
341
- rationale_match = re.search(r'RATIONALE:\s*(.+?)(?=\n[A-Z]+:|$)', section, re.DOTALL | re.IGNORECASE)
342
- confidence_match = re.search(r'CONFIDENCE:\s*([\d.]+)', section, re.IGNORECASE)
343
- expected_match = re.search(r'EXPECTED:\s*(.+?)(?=\n[A-Z]+:|$)', section, re.DOTALL | re.IGNORECASE)
344
- risk_match = re.search(r'RISK:\s*(\w+)', section, re.IGNORECASE)
349
+ tool_match = re.search(r"TOOL:\s*(.+?)(?=\n|$)", section, re.IGNORECASE)
350
+ target_match = re.search(r"TARGET:\s*(.+?)(?=\n|$)", section, re.IGNORECASE)
351
+ args_match = re.search(r"ARGS:\s*(.+?)(?=\n|$)", section, re.IGNORECASE)
352
+ priority_match = re.search(r"PRIORITY:\s*(\d+)", section, re.IGNORECASE)
353
+ rationale_match = re.search(
354
+ r"RATIONALE:\s*(.+?)(?=\n[A-Z]+:|$)", section, re.DOTALL | re.IGNORECASE
355
+ )
356
+ confidence_match = re.search(r"CONFIDENCE:\s*([\d.]+)", section, re.IGNORECASE)
357
+ expected_match = re.search(
358
+ r"EXPECTED:\s*(.+?)(?=\n[A-Z]+:|$)", section, re.DOTALL | re.IGNORECASE
359
+ )
360
+ risk_match = re.search(r"RISK:\s*(\w+)", section, re.IGNORECASE)
345
361
 
346
362
  # Require at least tool and target
347
363
  if not tool_match or not target_match:
@@ -359,9 +375,9 @@ Guidelines:
359
375
  args = []
360
376
  if args_match:
361
377
  args_str = args_match.group(1).strip()
362
- if args_str and args_str.lower() not in ['none', 'n/a', '-']:
378
+ if args_str and args_str.lower() not in ["none", "n/a", "-"]:
363
379
  # Split by comma or space
364
- args = [a.strip() for a in re.split(r'[,\s]+', args_str) if a.strip()]
380
+ args = [a.strip() for a in re.split(r"[,\s]+", args_str) if a.strip()]
365
381
 
366
382
  # Parse priority (default 5)
367
383
  priority = 5
@@ -380,21 +396,21 @@ Guidelines:
380
396
  pass
381
397
 
382
398
  # Parse rationale
383
- rationale = ''
399
+ rationale = ""
384
400
  if rationale_match:
385
401
  rationale = rationale_match.group(1).strip()
386
402
 
387
403
  # Parse expected
388
- expected = ''
404
+ expected = ""
389
405
  if expected_match:
390
406
  expected = expected_match.group(1).strip()
391
407
 
392
408
  # Parse risk
393
- risk = 'medium'
409
+ risk = "medium"
394
410
  if risk_match:
395
411
  risk = risk_match.group(1).strip().lower()
396
- if risk not in ['low', 'medium', 'high']:
397
- risk = 'medium'
412
+ if risk not in ["low", "medium", "high"]:
413
+ risk = "medium"
398
414
 
399
415
  return AIChainRecommendation(
400
416
  tool=tool,
@@ -404,20 +420,20 @@ Guidelines:
404
420
  rationale=rationale,
405
421
  confidence=confidence,
406
422
  expected_outcome=expected,
407
- risk_level=risk
423
+ risk_level=risk,
408
424
  )
409
425
 
410
426
  def _filter_duplicates(
411
427
  self,
412
428
  recommendations: List[AIChainRecommendation],
413
- static_commands: List[Dict[str, Any]]
429
+ static_commands: List[Dict[str, Any]],
414
430
  ) -> List[AIChainRecommendation]:
415
431
  """Remove AI recommendations that duplicate static rules."""
416
432
  # Build set of (tool, target) pairs from static commands
417
433
  static_pairs = set()
418
434
  for cmd in static_commands:
419
- tool = cmd.get('tool', '').lower()
420
- target = cmd.get('target', '').lower()
435
+ tool = cmd.get("tool", "").lower()
436
+ target = cmd.get("target", "").lower()
421
437
  static_pairs.add((tool, target))
422
438
 
423
439
  # Filter recommendations
@@ -427,14 +443,14 @@ Guidelines:
427
443
  if pair not in static_pairs:
428
444
  filtered.append(rec)
429
445
  else:
430
- logger.debug(f"Filtered duplicate AI recommendation: {rec.tool} -> {rec.target}")
446
+ logger.debug(
447
+ f"Filtered duplicate AI recommendation: {rec.tool} -> {rec.target}"
448
+ )
431
449
 
432
450
  return filtered
433
451
 
434
452
  def to_chain_commands(
435
- self,
436
- recommendations: List[AIChainRecommendation],
437
- context: Dict[str, Any]
453
+ self, recommendations: List[AIChainRecommendation], context: Dict[str, Any]
438
454
  ) -> List[Dict[str, Any]]:
439
455
  """
440
456
  Convert AI recommendations to chain command format.
@@ -449,17 +465,17 @@ Guidelines:
449
465
  commands = []
450
466
  for rec in recommendations:
451
467
  cmd = {
452
- 'tool': rec.tool,
453
- 'target': rec.target,
454
- 'args': rec.args,
455
- 'priority': rec.priority,
456
- 'description': f"[AI] {rec.rationale[:100]}",
457
- 'source': 'ai_advisor',
458
- 'confidence': rec.confidence,
459
- 'risk_level': rec.risk_level
468
+ "tool": rec.tool,
469
+ "target": rec.target,
470
+ "args": rec.args,
471
+ "priority": rec.priority,
472
+ "description": f"[AI] {rec.rationale[:100]}",
473
+ "source": "ai_advisor",
474
+ "confidence": rec.confidence,
475
+ "risk_level": rec.risk_level,
460
476
  }
461
477
  commands.append(cmd)
462
478
 
463
479
  # Sort by priority (highest first)
464
- commands.sort(key=lambda c: c['priority'], reverse=True)
480
+ commands.sort(key=lambda c: c["priority"], reverse=True)
465
481
  return commands
@@ -4,6 +4,7 @@ souleyez.ai.claude_provider - Anthropic Claude API provider implementation
4
4
  Provides Claude LLM integration for high-quality AI report generation.
5
5
  Requires API key stored securely via CryptoManager.
6
6
  """
7
+
7
8
  import logging
8
9
  from typing import Optional, Dict, Any
9
10
 
@@ -14,6 +15,7 @@ logger = logging.getLogger(__name__)
14
15
  # Check if anthropic package is available
15
16
  try:
16
17
  import anthropic
18
+
17
19
  ANTHROPIC_AVAILABLE = True
18
20
  except ImportError:
19
21
  anthropic = None
@@ -30,11 +32,7 @@ class ClaudeProvider(LLMProvider):
30
32
 
31
33
  DEFAULT_MODEL = "claude-sonnet-4-20250514"
32
34
 
33
- def __init__(
34
- self,
35
- api_key: Optional[str] = None,
36
- model: Optional[str] = None
37
- ):
35
+ def __init__(self, api_key: Optional[str] = None, model: Optional[str] = None):
38
36
  """
39
37
  Initialize Claude provider.
40
38
 
@@ -54,7 +52,7 @@ class ClaudeProvider(LLMProvider):
54
52
  from souleyez.config import get
55
53
  from souleyez.storage.crypto import get_crypto_manager
56
54
 
57
- encrypted_key = get('ai.claude_api_key')
55
+ encrypted_key = get("ai.claude_api_key")
58
56
  if not encrypted_key:
59
57
  logger.debug("No Claude API key configured")
60
58
  return None
@@ -74,7 +72,8 @@ class ClaudeProvider(LLMProvider):
74
72
  def _load_model(self) -> str:
75
73
  """Load model from config."""
76
74
  from souleyez.config import get
77
- return get('ai.claude_model', self.DEFAULT_MODEL)
75
+
76
+ return get("ai.claude_model", self.DEFAULT_MODEL)
78
77
 
79
78
  def _get_client(self):
80
79
  """Get or create Anthropic client."""
@@ -86,7 +85,9 @@ class ClaudeProvider(LLMProvider):
86
85
  return None
87
86
 
88
87
  if not ANTHROPIC_AVAILABLE:
89
- logger.error("anthropic package not installed. Install with: pip install anthropic")
88
+ logger.error(
89
+ "anthropic package not installed. Install with: pip install anthropic"
90
+ )
90
91
  return None
91
92
 
92
93
  try:
@@ -131,7 +132,7 @@ class ClaudeProvider(LLMProvider):
131
132
  prompt: str,
132
133
  system_prompt: Optional[str] = None,
133
134
  max_tokens: int = 4096,
134
- temperature: float = 0.3
135
+ temperature: float = 0.3,
135
136
  ) -> Optional[str]:
136
137
  """
137
138
  Generate text using Claude API.
@@ -159,7 +160,7 @@ class ClaudeProvider(LLMProvider):
159
160
  "model": self._model,
160
161
  "max_tokens": max_tokens,
161
162
  "temperature": temperature,
162
- "messages": messages
163
+ "messages": messages,
163
164
  }
164
165
 
165
166
  if system_prompt:
@@ -198,33 +199,33 @@ class ClaudeProvider(LLMProvider):
198
199
  has_key = api_key is not None
199
200
 
200
201
  status = {
201
- 'provider_type': self.provider_type.value,
202
- 'provider': 'Claude',
203
- 'provider_name': 'Claude (Anthropic)',
204
- 'model': self._model,
205
- 'api_key_configured': has_key,
206
- 'package_installed': ANTHROPIC_AVAILABLE,
207
- 'connected': False,
208
- 'error': None
202
+ "provider_type": self.provider_type.value,
203
+ "provider": "Claude",
204
+ "provider_name": "Claude (Anthropic)",
205
+ "model": self._model,
206
+ "api_key_configured": has_key,
207
+ "package_installed": ANTHROPIC_AVAILABLE,
208
+ "connected": False,
209
+ "error": None,
209
210
  }
210
211
 
211
212
  if not ANTHROPIC_AVAILABLE:
212
- status['error'] = 'anthropic package not installed'
213
+ status["error"] = "anthropic package not installed"
213
214
  return status
214
215
 
215
216
  if not has_key:
216
- status['error'] = 'No API key configured'
217
+ status["error"] = "No API key configured"
217
218
  return status
218
219
 
219
220
  # Test connection
220
221
  try:
221
222
  client = self._get_client()
222
223
  if client:
223
- status['connected'] = True
224
+ status["connected"] = True
224
225
  else:
225
- status['error'] = 'Failed to create client'
226
+ status["error"] = "Failed to create client"
226
227
  except Exception as e:
227
- status['error'] = str(e)
228
+ status["error"] = str(e)
228
229
 
229
230
  return status
230
231
 
@@ -254,9 +255,9 @@ def set_claude_api_key(api_key: str) -> bool:
254
255
  return False
255
256
 
256
257
  cfg = read_config()
257
- if 'ai' not in cfg:
258
- cfg['ai'] = {}
259
- cfg['ai']['claude_api_key'] = encrypted_key
258
+ if "ai" not in cfg:
259
+ cfg["ai"] = {}
260
+ cfg["ai"]["claude_api_key"] = encrypted_key
260
261
  write_config(cfg)
261
262
 
262
263
  logger.info("Claude API key stored successfully")
@@ -277,8 +278,8 @@ def clear_claude_api_key() -> bool:
277
278
 
278
279
  try:
279
280
  cfg = read_config()
280
- if 'ai' in cfg and 'claude_api_key' in cfg['ai']:
281
- del cfg['ai']['claude_api_key']
281
+ if "ai" in cfg and "claude_api_key" in cfg["ai"]:
282
+ del cfg["ai"]["claude_api_key"]
282
283
  write_config(cfg)
283
284
  logger.info("Claude API key removed")
284
285
  return True