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.
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
@@ -16,6 +16,7 @@ import re
16
16
  @dataclass
17
17
  class CorrelatedFinding:
18
18
  """Represents a group of related findings from different tools."""
19
+
19
20
  cve_id: Optional[str] = None
20
21
  service: str = ""
21
22
  port: int = 0
@@ -29,8 +30,8 @@ class CorrelatedFinding:
29
30
 
30
31
  def add_finding(self, finding: Dict[str, Any]):
31
32
  """Add a finding to this correlation group."""
32
- finding_id = finding.get('id')
33
- tool = finding.get('tool', '')
33
+ finding_id = finding.get("id")
34
+ tool = finding.get("tool", "")
34
35
 
35
36
  if finding_id and finding_id not in self.finding_ids:
36
37
  self.finding_ids.append(finding_id)
@@ -39,9 +40,15 @@ class CorrelatedFinding:
39
40
  self.tools.append(tool)
40
41
 
41
42
  # Update severity to highest
42
- severities = ['critical', 'high', 'medium', 'low', 'info']
43
- current_idx = severities.index(self.severity) if self.severity in severities else 4
44
- new_idx = severities.index(finding.get('severity', 'info')) if finding.get('severity') in severities else 4
43
+ severities = ["critical", "high", "medium", "low", "info"]
44
+ current_idx = (
45
+ severities.index(self.severity) if self.severity in severities else 4
46
+ )
47
+ new_idx = (
48
+ severities.index(finding.get("severity", "info"))
49
+ if finding.get("severity") in severities
50
+ else 4
51
+ )
45
52
 
46
53
  if new_idx < current_idx:
47
54
  self.severity = severities[new_idx]
@@ -49,22 +56,23 @@ class CorrelatedFinding:
49
56
  def to_dict(self) -> Dict[str, Any]:
50
57
  """Convert to dictionary."""
51
58
  return {
52
- 'cve_id': self.cve_id,
53
- 'service': self.service,
54
- 'port': self.port,
55
- 'host_ip': self.host_ip,
56
- 'severity': self.severity,
57
- 'finding_ids': self.finding_ids,
58
- 'tools': self.tools,
59
- 'confidence': self.confidence,
60
- 'description': self.description,
61
- 'exploit_available': self.exploit_available
59
+ "cve_id": self.cve_id,
60
+ "service": self.service,
61
+ "port": self.port,
62
+ "host_ip": self.host_ip,
63
+ "severity": self.severity,
64
+ "finding_ids": self.finding_ids,
65
+ "tools": self.tools,
66
+ "confidence": self.confidence,
67
+ "description": self.description,
68
+ "exploit_available": self.exploit_available,
62
69
  }
63
70
 
64
71
 
65
72
  @dataclass
66
73
  class AttackPath:
67
74
  """Represents a potential attack path using multiple findings."""
75
+
68
76
  name: str
69
77
  findings: List[Dict[str, Any]] = field(default_factory=list)
70
78
  success_probability: float = 0.0
@@ -73,11 +81,11 @@ class AttackPath:
73
81
 
74
82
  def to_dict(self) -> Dict[str, Any]:
75
83
  return {
76
- 'name': self.name,
77
- 'finding_ids': [f.get('id') for f in self.findings],
78
- 'success_probability': self.success_probability,
79
- 'impact': self.impact,
80
- 'steps': self.steps
84
+ "name": self.name,
85
+ "finding_ids": [f.get("id") for f in self.findings],
86
+ "success_probability": self.success_probability,
87
+ "impact": self.impact,
88
+ "steps": self.steps,
81
89
  }
82
90
 
83
91
 
@@ -87,7 +95,9 @@ class VulnerabilityCorrelator:
87
95
  def __init__(self):
88
96
  """Initialize correlator."""
89
97
 
90
- def correlate_by_cve(self, findings: List[Dict[str, Any]]) -> List[CorrelatedFinding]:
98
+ def correlate_by_cve(
99
+ self, findings: List[Dict[str, Any]]
100
+ ) -> List[CorrelatedFinding]:
91
101
  """
92
102
  Group findings by CVE ID.
93
103
 
@@ -97,14 +107,14 @@ class VulnerabilityCorrelator:
97
107
 
98
108
  for finding in findings:
99
109
  # Extract CVE from various fields
100
- cve_id = finding.get('cve_id')
110
+ cve_id = finding.get("cve_id")
101
111
  if not cve_id:
102
112
  # Try to extract from refs or description
103
- refs = finding.get('refs', '')
104
- desc = finding.get('description', '')
113
+ refs = finding.get("refs", "")
114
+ desc = finding.get("description", "")
105
115
  text = f"{refs} {desc}"
106
116
 
107
- cve_matches = re.findall(r'CVE-\d{4}-\d{4,7}', text, re.IGNORECASE)
117
+ cve_matches = re.findall(r"CVE-\d{4}-\d{4,7}", text, re.IGNORECASE)
108
118
  if cve_matches:
109
119
  cve_id = cve_matches[0].upper()
110
120
 
@@ -112,17 +122,19 @@ class VulnerabilityCorrelator:
112
122
  if cve_id not in cve_groups:
113
123
  cve_groups[cve_id] = CorrelatedFinding(
114
124
  cve_id=cve_id,
115
- service=finding.get('service', ''),
116
- port=finding.get('port', 0),
125
+ service=finding.get("service", ""),
126
+ port=finding.get("port", 0),
117
127
  host_ip=self._extract_host_ip(finding),
118
- confidence=0.95 # High confidence for CVE matching
128
+ confidence=0.95, # High confidence for CVE matching
119
129
  )
120
130
 
121
131
  cve_groups[cve_id].add_finding(finding)
122
132
 
123
133
  return list(cve_groups.values())
124
134
 
125
- def correlate_by_service(self, findings: List[Dict[str, Any]]) -> List[CorrelatedFinding]:
135
+ def correlate_by_service(
136
+ self, findings: List[Dict[str, Any]]
137
+ ) -> List[CorrelatedFinding]:
126
138
  """
127
139
  Group findings by service/port combination.
128
140
 
@@ -132,7 +144,7 @@ class VulnerabilityCorrelator:
132
144
 
133
145
  for finding in findings:
134
146
  host_ip = self._extract_host_ip(finding)
135
- port = finding.get('port', 0)
147
+ port = finding.get("port", 0)
136
148
 
137
149
  # Skip findings without port/host
138
150
  if not host_ip or not port:
@@ -145,7 +157,7 @@ class VulnerabilityCorrelator:
145
157
  service=self._extract_service_name(finding),
146
158
  port=port,
147
159
  host_ip=host_ip,
148
- confidence=0.7 # Medium-high confidence
160
+ confidence=0.7, # Medium-high confidence
149
161
  )
150
162
 
151
163
  service_groups[key].add_finding(finding)
@@ -153,24 +165,39 @@ class VulnerabilityCorrelator:
153
165
  # Only return groups with multiple findings
154
166
  return [g for g in service_groups.values() if len(g.finding_ids) > 1]
155
167
 
156
- def correlate_by_vulnerability_type(self, findings: List[Dict[str, Any]]) -> List[CorrelatedFinding]:
168
+ def correlate_by_vulnerability_type(
169
+ self, findings: List[Dict[str, Any]]
170
+ ) -> List[CorrelatedFinding]:
157
171
  """
158
172
  Group findings by vulnerability type (SQL injection, XSS, RCE, etc.).
159
173
  """
160
174
  vuln_types = {
161
- 'sqli': ['sql injection', 'sqlmap', 'blind sql'],
162
- 'xss': ['cross-site scripting', 'xss', 'reflected xss', 'stored xss'],
163
- 'rce': ['remote code execution', 'command injection', 'shell upload', 'arbitrary code'],
164
- 'lfi': ['local file inclusion', 'directory traversal', 'path traversal'],
165
- 'auth_bypass': ['authentication bypass', 'broken authentication', 'default credentials'],
166
- 'info_disclosure': ['information disclosure', 'sensitive data', 'directory listing']
175
+ "sqli": ["sql injection", "sqlmap", "blind sql"],
176
+ "xss": ["cross-site scripting", "xss", "reflected xss", "stored xss"],
177
+ "rce": [
178
+ "remote code execution",
179
+ "command injection",
180
+ "shell upload",
181
+ "arbitrary code",
182
+ ],
183
+ "lfi": ["local file inclusion", "directory traversal", "path traversal"],
184
+ "auth_bypass": [
185
+ "authentication bypass",
186
+ "broken authentication",
187
+ "default credentials",
188
+ ],
189
+ "info_disclosure": [
190
+ "information disclosure",
191
+ "sensitive data",
192
+ "directory listing",
193
+ ],
167
194
  }
168
195
 
169
196
  type_groups = {}
170
197
 
171
198
  for finding in findings:
172
- title = finding.get('title', '').lower()
173
- desc = finding.get('description', '').lower()
199
+ title = finding.get("title", "").lower()
200
+ desc = finding.get("description", "").lower()
174
201
  text = f"{title} {desc}"
175
202
 
176
203
  for vuln_type, keywords in vuln_types.items():
@@ -182,7 +209,7 @@ class VulnerabilityCorrelator:
182
209
  type_groups[key] = CorrelatedFinding(
183
210
  host_ip=host_ip,
184
211
  description=f"Multiple {vuln_type.upper()} vulnerabilities",
185
- confidence=0.6
212
+ confidence=0.6,
186
213
  )
187
214
 
188
215
  type_groups[key].add_finding(finding)
@@ -194,7 +221,7 @@ class VulnerabilityCorrelator:
194
221
  self,
195
222
  findings: List[Dict[str, Any]],
196
223
  credentials: List[Dict[str, Any]] = None,
197
- smb_shares: List[Dict[str, Any]] = None
224
+ smb_shares: List[Dict[str, Any]] = None,
198
225
  ) -> List[AttackPath]:
199
226
  """
200
227
  Identify potential attack paths by chaining vulnerabilities and access.
@@ -221,7 +248,11 @@ class VulnerabilityCorrelator:
221
248
  for host_ip, host_findings in by_host.items():
222
249
  # Path 1: RCE + Valid Credentials
223
250
  rce_findings = [f for f in host_findings if self._is_rce(f)]
224
- host_creds = [c for c in credentials if c.get('ip_address') == host_ip and c.get('status') == 'valid']
251
+ host_creds = [
252
+ c
253
+ for c in credentials
254
+ if c.get("ip_address") == host_ip and c.get("status") == "valid"
255
+ ]
225
256
 
226
257
  if rce_findings and host_creds:
227
258
  path = AttackPath(
@@ -233,13 +264,15 @@ class VulnerabilityCorrelator:
233
264
  f"1. Exploit {rce_findings[0].get('title')} for code execution",
234
265
  f"2. Use valid credentials: {host_creds[0].get('username')} / {host_creds[0].get('password')}",
235
266
  "3. Establish persistent access",
236
- "4. Escalate privileges if needed"
237
- ]
267
+ "4. Escalate privileges if needed",
268
+ ],
238
269
  )
239
270
  paths.append(path)
240
271
 
241
272
  # Path 2: SQL Injection + Database
242
- sqli_findings = [f for f in host_findings if 'sql' in f.get('title', '').lower()]
273
+ sqli_findings = [
274
+ f for f in host_findings if "sql" in f.get("title", "").lower()
275
+ ]
243
276
  if sqli_findings:
244
277
  path = AttackPath(
245
278
  name=f"SQL Injection on {host_ip}",
@@ -250,13 +283,17 @@ class VulnerabilityCorrelator:
250
283
  f"1. Exploit SQL injection: {sqli_findings[0].get('path', '')}",
251
284
  "2. Enumerate database schema",
252
285
  "3. Extract sensitive data (users, passwords, etc.)",
253
- "4. Attempt to read files or execute commands (if possible)"
254
- ]
286
+ "4. Attempt to read files or execute commands (if possible)",
287
+ ],
255
288
  )
256
289
  paths.append(path)
257
290
 
258
291
  # Path 3: Writable SMB + Any Access
259
- host_shares = [s for s in smb_shares if s.get('ip_address') == host_ip and s.get('writable')]
292
+ host_shares = [
293
+ s
294
+ for s in smb_shares
295
+ if s.get("ip_address") == host_ip and s.get("writable")
296
+ ]
260
297
  if host_shares:
261
298
  path = AttackPath(
262
299
  name=f"Writable SMB Share on {host_ip}",
@@ -267,13 +304,18 @@ class VulnerabilityCorrelator:
267
304
  f"1. Access writable share: \\\\{host_ip}\\{host_shares[0].get('share_name')}",
268
305
  "2. Upload malicious files (exe, dll, script)",
269
306
  "3. Wait for execution or trigger manually",
270
- "4. Gain code execution on the system"
271
- ]
307
+ "4. Gain code execution on the system",
308
+ ],
272
309
  )
273
310
  paths.append(path)
274
311
 
275
312
  # Path 4: Authentication Bypass + Service Access
276
- auth_bypass = [f for f in host_findings if 'auth' in f.get('title', '').lower() and 'bypass' in f.get('title', '').lower()]
313
+ auth_bypass = [
314
+ f
315
+ for f in host_findings
316
+ if "auth" in f.get("title", "").lower()
317
+ and "bypass" in f.get("title", "").lower()
318
+ ]
277
319
  if auth_bypass:
278
320
  path = AttackPath(
279
321
  name=f"Authentication Bypass on {host_ip}",
@@ -284,28 +326,31 @@ class VulnerabilityCorrelator:
284
326
  f"1. Exploit authentication bypass: {auth_bypass[0].get('title')}",
285
327
  "2. Gain unauthorized access to application",
286
328
  "3. Enumerate accessible functions",
287
- "4. Look for privilege escalation opportunities"
288
- ]
329
+ "4. Look for privilege escalation opportunities",
330
+ ],
289
331
  )
290
332
  paths.append(path)
291
333
 
292
334
  # Sort by impact and probability
293
- impact_order = {'critical': 0, 'high': 1, 'medium': 2, 'low': 3}
294
- paths.sort(key=lambda p: (impact_order.get(p.impact, 3), -p.success_probability))
335
+ impact_order = {"critical": 0, "high": 1, "medium": 2, "low": 3}
336
+ paths.sort(
337
+ key=lambda p: (impact_order.get(p.impact, 3), -p.success_probability)
338
+ )
295
339
 
296
340
  return paths
297
341
 
298
342
  def _extract_host_ip(self, finding: Dict[str, Any]) -> str:
299
343
  """Extract host IP from finding."""
300
344
  # Direct field
301
- if 'ip_address' in finding:
302
- return finding['ip_address']
345
+ if "ip_address" in finding:
346
+ return finding["ip_address"]
303
347
 
304
348
  # From target field
305
- target = finding.get('target', '')
349
+ target = finding.get("target", "")
306
350
  # Extract IP from URL or plain IP
307
351
  import re
308
- ip_match = re.search(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', target)
352
+
353
+ ip_match = re.search(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", target)
309
354
  if ip_match:
310
355
  return ip_match.group(0)
311
356
 
@@ -313,30 +358,30 @@ class VulnerabilityCorrelator:
313
358
 
314
359
  def _extract_service_name(self, finding: Dict[str, Any]) -> str:
315
360
  """Extract service name from finding."""
316
- if 'service' in finding:
317
- return finding['service']
361
+ if "service" in finding:
362
+ return finding["service"]
318
363
 
319
364
  # Try to infer from tool
320
- tool = finding.get('tool', '').lower()
321
- if tool == 'nuclei':
322
- return 'http'
323
- elif tool == 'smbmap':
324
- return 'smb'
325
- elif tool == 'sqlmap':
326
- return 'database'
365
+ tool = finding.get("tool", "").lower()
366
+ if tool == "nuclei":
367
+ return "http"
368
+ elif tool == "smbmap":
369
+ return "smb"
370
+ elif tool == "sqlmap":
371
+ return "database"
327
372
 
328
- return finding.get('finding_type', 'unknown')
373
+ return finding.get("finding_type", "unknown")
329
374
 
330
375
  def _is_rce(self, finding: Dict[str, Any]) -> bool:
331
376
  """Check if finding is related to RCE."""
332
377
  text = f"{finding.get('title', '')} {finding.get('description', '')}".lower()
333
378
  rce_keywords = [
334
- 'remote code execution',
335
- 'command injection',
336
- 'arbitrary code',
337
- 'shell upload',
338
- 'code exec',
339
- 'rce'
379
+ "remote code execution",
380
+ "command injection",
381
+ "arbitrary code",
382
+ "shell upload",
383
+ "code exec",
384
+ "rce",
340
385
  ]
341
386
  return any(kw in text for kw in rce_keywords)
342
387
 
@@ -344,7 +389,7 @@ class VulnerabilityCorrelator:
344
389
  self,
345
390
  findings: List[Dict[str, Any]],
346
391
  credentials: List[Dict[str, Any]] = None,
347
- smb_shares: List[Dict[str, Any]] = None
392
+ smb_shares: List[Dict[str, Any]] = None,
348
393
  ) -> Dict[str, Any]:
349
394
  """
350
395
  Generate a comprehensive correlation report.
@@ -365,18 +410,20 @@ class VulnerabilityCorrelator:
365
410
  attack_paths = self.find_attack_paths(findings, credentials, smb_shares)
366
411
 
367
412
  return {
368
- 'cve_correlations': [c.to_dict() for c in cve_corr],
369
- 'service_correlations': [c.to_dict() for c in service_corr],
370
- 'type_correlations': [c.to_dict() for c in type_corr],
371
- 'attack_paths': [p.to_dict() for p in attack_paths],
372
- 'summary': {
373
- 'total_findings': len(findings),
374
- 'cve_groups': len(cve_corr),
375
- 'service_groups': len(service_corr),
376
- 'type_groups': len(type_corr),
377
- 'attack_paths': len(attack_paths),
378
- 'high_confidence_correlations': len([c for c in cve_corr if c.confidence > 0.8])
379
- }
413
+ "cve_correlations": [c.to_dict() for c in cve_corr],
414
+ "service_correlations": [c.to_dict() for c in service_corr],
415
+ "type_correlations": [c.to_dict() for c in type_corr],
416
+ "attack_paths": [p.to_dict() for p in attack_paths],
417
+ "summary": {
418
+ "total_findings": len(findings),
419
+ "cve_groups": len(cve_corr),
420
+ "service_groups": len(service_corr),
421
+ "type_groups": len(type_corr),
422
+ "attack_paths": len(attack_paths),
423
+ "high_confidence_correlations": len(
424
+ [c for c in cve_corr if c.confidence > 0.8]
425
+ ),
426
+ },
380
427
  }
381
428
 
382
429
 
@@ -38,11 +38,11 @@ def check_http_redirect(ip: str, port: int = 80, timeout: int = 3) -> Dict[str,
38
38
  'final_url': 'https://example.com/', 'status_code': 200, 'error': None}
39
39
  """
40
40
  result = {
41
- 'redirects_to_https': False,
42
- 'final_scheme': 'http',
43
- 'final_url': None,
44
- 'status_code': None,
45
- 'error': None
41
+ "redirects_to_https": False,
42
+ "final_scheme": "http",
43
+ "final_url": None,
44
+ "status_code": None,
45
+ "error": None,
46
46
  }
47
47
 
48
48
  url = f"http://{ip}:{port}/"
@@ -56,32 +56,32 @@ def check_http_redirect(ip: str, port: int = 80, timeout: int = 3) -> Dict[str,
56
56
  timeout=timeout,
57
57
  verify=False, # nosec B501 - pentesting tool needs to handle self-signed certs
58
58
  allow_redirects=True,
59
- headers={'User-Agent': 'SoulEyez/1.0'}
59
+ headers={"User-Agent": "SoulEyez/1.0"},
60
60
  )
61
61
 
62
62
  # Get final URL after all redirects
63
63
  final_url = response.url
64
- result['final_url'] = final_url
65
- result['status_code'] = response.status_code
64
+ result["final_url"] = final_url
65
+ result["status_code"] = response.status_code
66
66
 
67
67
  # Parse final URL to get scheme
68
68
  parsed = urlparse(final_url)
69
- result['final_scheme'] = parsed.scheme
69
+ result["final_scheme"] = parsed.scheme
70
70
 
71
71
  # Check if we ended up on HTTPS
72
- if parsed.scheme == 'https':
73
- result['redirects_to_https'] = True
72
+ if parsed.scheme == "https":
73
+ result["redirects_to_https"] = True
74
74
 
75
75
  except requests.exceptions.Timeout:
76
- result['error'] = f'Timeout after {timeout}s'
76
+ result["error"] = f"Timeout after {timeout}s"
77
77
  except requests.exceptions.SSLError as e:
78
- result['error'] = f'SSL error: {str(e)[:100]}'
78
+ result["error"] = f"SSL error: {str(e)[:100]}"
79
79
  except requests.exceptions.ConnectionError as e:
80
- result['error'] = f'Connection error: {str(e)[:100]}'
80
+ result["error"] = f"Connection error: {str(e)[:100]}"
81
81
  except requests.exceptions.RequestException as e:
82
- result['error'] = f'Request error: {str(e)[:100]}'
82
+ result["error"] = f"Request error: {str(e)[:100]}"
83
83
  except Exception as e:
84
- result['error'] = f'Unexpected error: {str(e)[:100]}'
84
+ result["error"] = f"Unexpected error: {str(e)[:100]}"
85
85
 
86
86
  return result
87
87
 
@@ -101,11 +101,11 @@ def check_https_redirect(ip: str, port: int = 443, timeout: int = 3) -> Dict[str
101
101
  Dictionary with redirect information (same format as check_http_redirect)
102
102
  """
103
103
  result = {
104
- 'redirects_to_http': False,
105
- 'final_scheme': 'https',
106
- 'final_url': None,
107
- 'status_code': None,
108
- 'error': None
104
+ "redirects_to_http": False,
105
+ "final_scheme": "https",
106
+ "final_url": None,
107
+ "status_code": None,
108
+ "error": None,
109
109
  }
110
110
 
111
111
  url = f"https://{ip}:{port}/"
@@ -116,33 +116,34 @@ def check_https_redirect(ip: str, port: int = 443, timeout: int = 3) -> Dict[str
116
116
  timeout=timeout,
117
117
  verify=False, # nosec B501 - pentesting tool needs to handle self-signed certs
118
118
  allow_redirects=True,
119
- headers={'User-Agent': 'SoulEyez/1.0'}
119
+ headers={"User-Agent": "SoulEyez/1.0"},
120
120
  )
121
121
 
122
122
  final_url = response.url
123
- result['final_url'] = final_url
124
- result['status_code'] = response.status_code
123
+ result["final_url"] = final_url
124
+ result["status_code"] = response.status_code
125
125
 
126
126
  parsed = urlparse(final_url)
127
- result['final_scheme'] = parsed.scheme
127
+ result["final_scheme"] = parsed.scheme
128
128
 
129
- if parsed.scheme == 'http':
130
- result['redirects_to_http'] = True
129
+ if parsed.scheme == "http":
130
+ result["redirects_to_http"] = True
131
131
 
132
132
  except requests.exceptions.Timeout:
133
- result['error'] = f'Timeout after {timeout}s'
133
+ result["error"] = f"Timeout after {timeout}s"
134
134
  except requests.exceptions.SSLError as e:
135
- result['error'] = f'SSL error: {str(e)[:100]}'
135
+ result["error"] = f"SSL error: {str(e)[:100]}"
136
136
  except requests.exceptions.ConnectionError as e:
137
- result['error'] = f'Connection error: {str(e)[:100]}'
137
+ result["error"] = f"Connection error: {str(e)[:100]}"
138
138
  except requests.exceptions.RequestException as e:
139
- result['error'] = f'Request error: {str(e)[:100]}'
139
+ result["error"] = f"Request error: {str(e)[:100]}"
140
140
  except Exception as e:
141
- result['error'] = f'Unexpected error: {str(e)[:100]}'
141
+ result["error"] = f"Unexpected error: {str(e)[:100]}"
142
142
 
143
143
  return result
144
144
 
145
145
 
146
146
  # Suppress SSL warnings for pentesting context
147
147
  import urllib3
148
+
148
149
  urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)