souleyez 2.43.29__py3-none-any.whl → 3.0.0__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.

Potentially problematic release.


This version of souleyez might be problematic. Click here for more details.

Files changed (358) 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 +9564 -2881
  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 +1239 -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 +2200 -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 +564 -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 +409 -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 +417 -0
  116. souleyez/handlers/rdp_sec_check_handler.py +353 -0
  117. souleyez/handlers/registry.py +292 -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/web_login_test_handler.py +327 -0
  126. souleyez/handlers/whois_handler.py +277 -0
  127. souleyez/handlers/wpscan_handler.py +554 -0
  128. souleyez/history.py +32 -16
  129. souleyez/importers/msf_importer.py +106 -75
  130. souleyez/importers/smart_importer.py +208 -147
  131. souleyez/integrations/siem/__init__.py +10 -10
  132. souleyez/integrations/siem/base.py +17 -18
  133. souleyez/integrations/siem/elastic.py +108 -122
  134. souleyez/integrations/siem/factory.py +207 -80
  135. souleyez/integrations/siem/googlesecops.py +146 -154
  136. souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
  137. souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
  138. souleyez/integrations/siem/sentinel.py +107 -109
  139. souleyez/integrations/siem/splunk.py +246 -212
  140. souleyez/integrations/siem/wazuh.py +65 -71
  141. souleyez/integrations/wazuh/__init__.py +5 -5
  142. souleyez/integrations/wazuh/client.py +70 -93
  143. souleyez/integrations/wazuh/config.py +85 -57
  144. souleyez/integrations/wazuh/host_mapper.py +28 -36
  145. souleyez/integrations/wazuh/sync.py +78 -68
  146. souleyez/intelligence/__init__.py +4 -5
  147. souleyez/intelligence/correlation_analyzer.py +309 -295
  148. souleyez/intelligence/exploit_knowledge.py +661 -623
  149. souleyez/intelligence/exploit_suggestions.py +159 -139
  150. souleyez/intelligence/gap_analyzer.py +132 -97
  151. souleyez/intelligence/gap_detector.py +251 -214
  152. souleyez/intelligence/sensitive_tables.py +266 -129
  153. souleyez/intelligence/service_parser.py +137 -123
  154. souleyez/intelligence/surface_analyzer.py +407 -268
  155. souleyez/intelligence/target_parser.py +159 -162
  156. souleyez/licensing/__init__.py +6 -6
  157. souleyez/licensing/validator.py +17 -19
  158. souleyez/log_config.py +79 -54
  159. souleyez/main.py +1505 -687
  160. souleyez/migrations/fix_job_counter.py +16 -14
  161. souleyez/parsers/bloodhound_parser.py +41 -39
  162. souleyez/parsers/crackmapexec_parser.py +178 -111
  163. souleyez/parsers/dalfox_parser.py +72 -77
  164. souleyez/parsers/dnsrecon_parser.py +103 -91
  165. souleyez/parsers/enum4linux_parser.py +183 -153
  166. souleyez/parsers/ffuf_parser.py +29 -25
  167. souleyez/parsers/gobuster_parser.py +301 -41
  168. souleyez/parsers/hashcat_parser.py +324 -79
  169. souleyez/parsers/http_fingerprint_parser.py +350 -103
  170. souleyez/parsers/hydra_parser.py +131 -111
  171. souleyez/parsers/impacket_parser.py +231 -178
  172. souleyez/parsers/john_parser.py +98 -86
  173. souleyez/parsers/katana_parser.py +316 -0
  174. souleyez/parsers/msf_parser.py +943 -498
  175. souleyez/parsers/nikto_parser.py +346 -65
  176. souleyez/parsers/nmap_parser.py +262 -174
  177. souleyez/parsers/nuclei_parser.py +40 -44
  178. souleyez/parsers/responder_parser.py +26 -26
  179. souleyez/parsers/searchsploit_parser.py +74 -74
  180. souleyez/parsers/service_explorer_parser.py +279 -0
  181. souleyez/parsers/smbmap_parser.py +180 -124
  182. souleyez/parsers/sqlmap_parser.py +434 -308
  183. souleyez/parsers/theharvester_parser.py +75 -57
  184. souleyez/parsers/whois_parser.py +135 -94
  185. souleyez/parsers/wpscan_parser.py +278 -190
  186. souleyez/plugins/afp.py +44 -36
  187. souleyez/plugins/afp_brute.py +114 -46
  188. souleyez/plugins/ard.py +48 -37
  189. souleyez/plugins/bloodhound.py +95 -61
  190. souleyez/plugins/certipy.py +303 -0
  191. souleyez/plugins/crackmapexec.py +186 -85
  192. souleyez/plugins/dalfox.py +120 -59
  193. souleyez/plugins/dns_hijack.py +146 -41
  194. souleyez/plugins/dnsrecon.py +97 -61
  195. souleyez/plugins/enum4linux.py +91 -66
  196. souleyez/plugins/evil_winrm.py +291 -0
  197. souleyez/plugins/ffuf.py +166 -90
  198. souleyez/plugins/firmware_extract.py +133 -29
  199. souleyez/plugins/gobuster.py +387 -190
  200. souleyez/plugins/gpp_extract.py +393 -0
  201. souleyez/plugins/hashcat.py +100 -73
  202. souleyez/plugins/http_fingerprint.py +913 -267
  203. souleyez/plugins/hydra.py +566 -200
  204. souleyez/plugins/impacket_getnpusers.py +117 -69
  205. souleyez/plugins/impacket_psexec.py +84 -64
  206. souleyez/plugins/impacket_secretsdump.py +103 -69
  207. souleyez/plugins/impacket_smbclient.py +89 -75
  208. souleyez/plugins/john.py +86 -69
  209. souleyez/plugins/katana.py +313 -0
  210. souleyez/plugins/kerbrute.py +237 -0
  211. souleyez/plugins/lfi_extract.py +541 -0
  212. souleyez/plugins/macos_ssh.py +117 -48
  213. souleyez/plugins/mdns.py +35 -30
  214. souleyez/plugins/msf_auxiliary.py +253 -130
  215. souleyez/plugins/msf_exploit.py +239 -161
  216. souleyez/plugins/nikto.py +134 -78
  217. souleyez/plugins/nmap.py +275 -91
  218. souleyez/plugins/nuclei.py +180 -89
  219. souleyez/plugins/nxc.py +285 -0
  220. souleyez/plugins/plugin_base.py +35 -36
  221. souleyez/plugins/plugin_template.py +13 -5
  222. souleyez/plugins/rdp_sec_check.py +130 -0
  223. souleyez/plugins/responder.py +112 -71
  224. souleyez/plugins/router_http_brute.py +76 -65
  225. souleyez/plugins/router_ssh_brute.py +118 -41
  226. souleyez/plugins/router_telnet_brute.py +124 -42
  227. souleyez/plugins/routersploit.py +91 -59
  228. souleyez/plugins/routersploit_exploit.py +77 -55
  229. souleyez/plugins/searchsploit.py +91 -77
  230. souleyez/plugins/service_explorer.py +1160 -0
  231. souleyez/plugins/smbmap.py +122 -72
  232. souleyez/plugins/smbpasswd.py +215 -0
  233. souleyez/plugins/sqlmap.py +301 -113
  234. souleyez/plugins/theharvester.py +127 -75
  235. souleyez/plugins/tr069.py +79 -57
  236. souleyez/plugins/upnp.py +65 -47
  237. souleyez/plugins/upnp_abuse.py +73 -55
  238. souleyez/plugins/vnc_access.py +129 -42
  239. souleyez/plugins/vnc_brute.py +109 -38
  240. souleyez/plugins/web_login_test.py +417 -0
  241. souleyez/plugins/whois.py +77 -58
  242. souleyez/plugins/wpscan.py +219 -69
  243. souleyez/reporting/__init__.py +2 -1
  244. souleyez/reporting/attack_chain.py +411 -346
  245. souleyez/reporting/charts.py +436 -501
  246. souleyez/reporting/compliance_mappings.py +334 -201
  247. souleyez/reporting/detection_report.py +126 -125
  248. souleyez/reporting/formatters.py +828 -591
  249. souleyez/reporting/generator.py +386 -302
  250. souleyez/reporting/metrics.py +72 -75
  251. souleyez/scanner.py +35 -29
  252. souleyez/security/__init__.py +37 -11
  253. souleyez/security/scope_validator.py +175 -106
  254. souleyez/security/validation.py +237 -149
  255. souleyez/security.py +22 -6
  256. souleyez/storage/credentials.py +247 -186
  257. souleyez/storage/crypto.py +296 -129
  258. souleyez/storage/database.py +73 -50
  259. souleyez/storage/db.py +58 -36
  260. souleyez/storage/deliverable_evidence.py +177 -128
  261. souleyez/storage/deliverable_exporter.py +282 -246
  262. souleyez/storage/deliverable_templates.py +134 -116
  263. souleyez/storage/deliverables.py +135 -130
  264. souleyez/storage/engagements.py +109 -56
  265. souleyez/storage/evidence.py +181 -152
  266. souleyez/storage/execution_log.py +31 -17
  267. souleyez/storage/exploit_attempts.py +93 -57
  268. souleyez/storage/exploits.py +67 -36
  269. souleyez/storage/findings.py +48 -61
  270. souleyez/storage/hosts.py +176 -144
  271. souleyez/storage/migrate_to_engagements.py +43 -19
  272. souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
  273. souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
  274. souleyez/storage/migrations/_003_add_execution_log.py +14 -8
  275. souleyez/storage/migrations/_005_screenshots.py +13 -5
  276. souleyez/storage/migrations/_006_deliverables.py +13 -5
  277. souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
  278. souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
  279. souleyez/storage/migrations/_010_evidence_linking.py +17 -10
  280. souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
  281. souleyez/storage/migrations/_012_team_collaboration.py +34 -21
  282. souleyez/storage/migrations/_013_add_host_tags.py +12 -6
  283. souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
  284. souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
  285. souleyez/storage/migrations/_016_add_domain_field.py +10 -4
  286. souleyez/storage/migrations/_017_msf_sessions.py +16 -8
  287. souleyez/storage/migrations/_018_add_osint_target.py +10 -6
  288. souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
  289. souleyez/storage/migrations/_020_add_rbac.py +36 -15
  290. souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
  291. souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
  292. souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
  293. souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
  294. souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
  295. souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
  296. souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
  297. souleyez/storage/migrations/__init__.py +26 -26
  298. souleyez/storage/migrations/migration_manager.py +19 -19
  299. souleyez/storage/msf_sessions.py +100 -65
  300. souleyez/storage/osint.py +17 -24
  301. souleyez/storage/recommendation_engine.py +269 -235
  302. souleyez/storage/screenshots.py +33 -32
  303. souleyez/storage/smb_shares.py +136 -92
  304. souleyez/storage/sqlmap_data.py +183 -128
  305. souleyez/storage/team_collaboration.py +135 -141
  306. souleyez/storage/timeline_tracker.py +122 -94
  307. souleyez/storage/wazuh_vulns.py +64 -66
  308. souleyez/storage/web_paths.py +33 -37
  309. souleyez/testing/credential_tester.py +221 -205
  310. souleyez/ui/__init__.py +1 -1
  311. souleyez/ui/ai_quotes.py +12 -12
  312. souleyez/ui/attack_surface.py +2439 -1516
  313. souleyez/ui/chain_rules_view.py +914 -382
  314. souleyez/ui/correlation_view.py +312 -230
  315. souleyez/ui/dashboard.py +2382 -1130
  316. souleyez/ui/deliverables_view.py +148 -62
  317. souleyez/ui/design_system.py +13 -13
  318. souleyez/ui/errors.py +49 -49
  319. souleyez/ui/evidence_linking_view.py +284 -179
  320. souleyez/ui/evidence_vault.py +393 -285
  321. souleyez/ui/exploit_suggestions_view.py +555 -349
  322. souleyez/ui/export_view.py +100 -66
  323. souleyez/ui/gap_analysis_view.py +315 -171
  324. souleyez/ui/help_system.py +105 -97
  325. souleyez/ui/intelligence_view.py +436 -293
  326. souleyez/ui/interactive.py +23034 -10679
  327. souleyez/ui/interactive_selector.py +75 -68
  328. souleyez/ui/log_formatter.py +47 -39
  329. souleyez/ui/menu_components.py +22 -13
  330. souleyez/ui/msf_auxiliary_menu.py +184 -133
  331. souleyez/ui/pending_chains_view.py +336 -172
  332. souleyez/ui/progress_indicators.py +5 -3
  333. souleyez/ui/recommendations_view.py +195 -137
  334. souleyez/ui/rule_builder.py +343 -225
  335. souleyez/ui/setup_wizard.py +678 -284
  336. souleyez/ui/shortcuts.py +217 -165
  337. souleyez/ui/splunk_gap_analysis_view.py +452 -270
  338. souleyez/ui/splunk_vulns_view.py +139 -86
  339. souleyez/ui/team_dashboard.py +498 -335
  340. souleyez/ui/template_selector.py +196 -105
  341. souleyez/ui/terminal.py +6 -6
  342. souleyez/ui/timeline_view.py +198 -127
  343. souleyez/ui/tool_setup.py +264 -164
  344. souleyez/ui/tutorial.py +202 -72
  345. souleyez/ui/tutorial_state.py +40 -40
  346. souleyez/ui/wazuh_vulns_view.py +235 -141
  347. souleyez/ui/wordlist_browser.py +260 -107
  348. souleyez/ui.py +464 -312
  349. souleyez/utils/tool_checker.py +427 -367
  350. souleyez/utils.py +33 -29
  351. souleyez/wordlists.py +134 -167
  352. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/METADATA +2 -2
  353. souleyez-3.0.0.dist-info/RECORD +443 -0
  354. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/WHEEL +1 -1
  355. souleyez-2.43.29.dist-info/RECORD +0 -379
  356. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/entry_points.txt +0 -0
  357. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/licenses/LICENSE +0 -0
  358. {souleyez-2.43.29.dist-info → souleyez-3.0.0.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