souleyez 2.43.29__py3-none-any.whl → 2.43.34__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 +9526 -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 +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 +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 +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 +854 -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 +173 -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 +223 -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 +22827 -10678
  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-2.43.34.dist-info}/METADATA +1 -1
  353. souleyez-2.43.34.dist-info/RECORD +443 -0
  354. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
  355. souleyez-2.43.29.dist-info/RECORD +0 -379
  356. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
  357. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
  358. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
@@ -13,12 +13,12 @@ class SmartImporter:
13
13
 
14
14
  def __init__(self):
15
15
  self.detected_types = {
16
- 'hosts': 0,
17
- 'services': 0,
18
- 'vulnerabilities': 0,
19
- 'credentials': 0,
20
- 'web_paths': 0,
21
- 'notes': 0
16
+ "hosts": 0,
17
+ "services": 0,
18
+ "vulnerabilities": 0,
19
+ "credentials": 0,
20
+ "web_paths": 0,
21
+ "notes": 0,
22
22
  }
23
23
 
24
24
  def analyze_msf_xml(self, xml_path: str) -> Dict[str, Any]:
@@ -33,103 +33,135 @@ class SmartImporter:
33
33
  root = tree.getroot()
34
34
 
35
35
  analysis = {
36
- 'file_type': 'msf_xml',
37
- 'hosts': {'count': 0, 'preview': []},
38
- 'services': {'count': 0, 'preview': []},
39
- 'vulnerabilities': {'count': 0, 'preview': []},
40
- 'credentials': {'count': 0, 'preview': []},
41
- 'web_paths': {'count': 0, 'preview': []},
42
- 'notes': {'count': 0, 'preview': []}
36
+ "file_type": "msf_xml",
37
+ "hosts": {"count": 0, "preview": []},
38
+ "services": {"count": 0, "preview": []},
39
+ "vulnerabilities": {"count": 0, "preview": []},
40
+ "credentials": {"count": 0, "preview": []},
41
+ "web_paths": {"count": 0, "preview": []},
42
+ "notes": {"count": 0, "preview": []},
43
43
  }
44
44
 
45
45
  # Analyze hosts
46
- hosts = root.findall('.//host')
47
- analysis['hosts']['count'] = len(hosts)
46
+ hosts = root.findall(".//host")
47
+ analysis["hosts"]["count"] = len(hosts)
48
48
  for host in hosts[:3]: # Preview first 3
49
- address = host.find('address')
50
- name = host.find('name')
51
- os_name = host.find('os-name')
52
- analysis['hosts']['preview'].append({
53
- 'address': address.text if address is not None else '',
54
- 'name': name.text if name is not None else '',
55
- 'os': os_name.text if os_name is not None else ''
56
- })
49
+ address = host.find("address")
50
+ name = host.find("name")
51
+ os_name = host.find("os-name")
52
+ analysis["hosts"]["preview"].append(
53
+ {
54
+ "address": address.text if address is not None else "",
55
+ "name": name.text if name is not None else "",
56
+ "os": os_name.text if os_name is not None else "",
57
+ }
58
+ )
57
59
 
58
60
  # Analyze services
59
- services = root.findall('.//service')
60
- analysis['services']['count'] = len(services)
61
+ services = root.findall(".//service")
62
+ analysis["services"]["count"] = len(services)
61
63
  for svc in services[:3]:
62
- port = svc.find('port')
63
- proto = svc.find('proto')
64
- name = svc.find('name')
65
- info = svc.find('info')
66
- analysis['services']['preview'].append({
67
- 'port': port.text if port is not None else '',
68
- 'proto': proto.text if proto is not None else '',
69
- 'name': name.text if name is not None else '',
70
- 'info': info.text if info is not None else ''
71
- })
64
+ port = svc.find("port")
65
+ proto = svc.find("proto")
66
+ name = svc.find("name")
67
+ info = svc.find("info")
68
+ analysis["services"]["preview"].append(
69
+ {
70
+ "port": port.text if port is not None else "",
71
+ "proto": proto.text if proto is not None else "",
72
+ "name": name.text if name is not None else "",
73
+ "info": info.text if info is not None else "",
74
+ }
75
+ )
72
76
 
73
77
  # Analyze vulnerabilities (notes with vuln refs)
74
- notes = root.findall('.//note')
78
+ notes = root.findall(".//note")
75
79
  for note in notes:
76
- ntype = note.find('ntype')
77
- data = note.find('data')
80
+ ntype = note.find("ntype")
81
+ data = note.find("data")
78
82
 
79
83
  if ntype is not None and data is not None:
80
84
  # Check if it's a vulnerability
81
- if 'vuln' in ntype.text.lower() or self._looks_like_vuln(data.text):
82
- analysis['vulnerabilities']['count'] += 1
83
- if len(analysis['vulnerabilities']['preview']) < 3:
84
- analysis['vulnerabilities']['preview'].append({
85
- 'type': ntype.text,
86
- 'data': data.text[:100] + '...' if len(data.text) > 100 else data.text
87
- })
85
+ if "vuln" in ntype.text.lower() or self._looks_like_vuln(data.text):
86
+ analysis["vulnerabilities"]["count"] += 1
87
+ if len(analysis["vulnerabilities"]["preview"]) < 3:
88
+ analysis["vulnerabilities"]["preview"].append(
89
+ {
90
+ "type": ntype.text,
91
+ "data": (
92
+ data.text[:100] + "..."
93
+ if len(data.text) > 100
94
+ else data.text
95
+ ),
96
+ }
97
+ )
88
98
  else:
89
- analysis['notes']['count'] += 1
90
- if len(analysis['notes']['preview']) < 3:
91
- analysis['notes']['preview'].append({
92
- 'type': ntype.text,
93
- 'data': data.text[:100] + '...' if len(data.text) > 100 else data.text
94
- })
99
+ analysis["notes"]["count"] += 1
100
+ if len(analysis["notes"]["preview"]) < 3:
101
+ analysis["notes"]["preview"].append(
102
+ {
103
+ "type": ntype.text,
104
+ "data": (
105
+ data.text[:100] + "..."
106
+ if len(data.text) > 100
107
+ else data.text
108
+ ),
109
+ }
110
+ )
95
111
 
96
112
  # Analyze credentials
97
- creds = root.findall('.//cred')
98
- analysis['credentials']['count'] = len(creds)
113
+ creds = root.findall(".//cred")
114
+ analysis["credentials"]["count"] = len(creds)
99
115
  for cred in creds[:3]:
100
- user = cred.find('user')
101
- pass_elem = cred.find('pass')
102
- service = cred.find('service')
103
- analysis['credentials']['preview'].append({
104
- 'username': user.text if user is not None else '',
105
- 'password': pass_elem.text[:20] + '...' if pass_elem is not None and len(pass_elem.text) > 20 else (pass_elem.text if pass_elem is not None else ''),
106
- 'service': service.text if service is not None else ''
107
- })
116
+ user = cred.find("user")
117
+ pass_elem = cred.find("pass")
118
+ service = cred.find("service")
119
+ analysis["credentials"]["preview"].append(
120
+ {
121
+ "username": user.text if user is not None else "",
122
+ "password": (
123
+ pass_elem.text[:20] + "..."
124
+ if pass_elem is not None and len(pass_elem.text) > 20
125
+ else (pass_elem.text if pass_elem is not None else "")
126
+ ),
127
+ "service": service.text if service is not None else "",
128
+ }
129
+ )
108
130
 
109
131
  # Analyze web paths/findings
110
- web_vulns = root.findall('.//web_vuln')
111
- analysis['web_paths']['count'] = len(web_vulns)
132
+ web_vulns = root.findall(".//web_vuln")
133
+ analysis["web_paths"]["count"] = len(web_vulns)
112
134
  for wv in web_vulns[:3]:
113
- path = wv.find('path')
114
- method = wv.find('method')
115
- pname = wv.find('pname')
116
- analysis['web_paths']['preview'].append({
117
- 'path': path.text if path is not None else '',
118
- 'method': method.text if method is not None else '',
119
- 'param': pname.text if pname is not None else ''
120
- })
135
+ path = wv.find("path")
136
+ method = wv.find("method")
137
+ pname = wv.find("pname")
138
+ analysis["web_paths"]["preview"].append(
139
+ {
140
+ "path": path.text if path is not None else "",
141
+ "method": method.text if method is not None else "",
142
+ "param": pname.text if pname is not None else "",
143
+ }
144
+ )
121
145
 
122
146
  return analysis
123
147
 
124
148
  except Exception as e:
125
- return {'error': str(e)}
149
+ return {"error": str(e)}
126
150
 
127
151
  def _looks_like_vuln(self, text: str) -> bool:
128
152
  """Check if text looks like vulnerability data."""
129
153
  vuln_keywords = [
130
- 'cve-', 'exploit', 'vulnerable', 'vulnerability',
131
- 'attack', 'injection', 'xss', 'sqli', 'rce',
132
- 'buffer overflow', 'authentication bypass'
154
+ "cve-",
155
+ "exploit",
156
+ "vulnerable",
157
+ "vulnerability",
158
+ "attack",
159
+ "injection",
160
+ "xss",
161
+ "sqli",
162
+ "rce",
163
+ "buffer overflow",
164
+ "authentication bypass",
133
165
  ]
134
166
  text_lower = text.lower()
135
167
  return any(keyword in text_lower for keyword in vuln_keywords)
@@ -142,8 +174,9 @@ class SmartImporter:
142
174
  """
143
175
  return self.analyze_msf_xml(xml_path)
144
176
 
145
- def selective_import(self, xml_path: str, engagement_id: int,
146
- import_types: List[str]) -> Dict[str, int]:
177
+ def selective_import(
178
+ self, xml_path: str, engagement_id: int, import_types: List[str]
179
+ ) -> Dict[str, int]:
147
180
  """
148
181
  Import only selected data types.
149
182
 
@@ -161,12 +194,12 @@ class SmartImporter:
161
194
  from souleyez.storage.credentials import CredentialsManager
162
195
 
163
196
  results = {
164
- 'hosts': 0,
165
- 'services': 0,
166
- 'vulnerabilities': 0,
167
- 'credentials': 0,
168
- 'web_paths': 0,
169
- 'notes': 0
197
+ "hosts": 0,
198
+ "services": 0,
199
+ "vulnerabilities": 0,
200
+ "credentials": 0,
201
+ "web_paths": 0,
202
+ "notes": 0,
170
203
  }
171
204
 
172
205
  try:
@@ -178,59 +211,67 @@ class SmartImporter:
178
211
  cm = CredentialsManager()
179
212
 
180
213
  # Import hosts
181
- if 'hosts' in import_types:
182
- hosts = root.findall('.//host')
214
+ if "hosts" in import_types:
215
+ hosts = root.findall(".//host")
183
216
  for host_elem in hosts:
184
- address = host_elem.find('address')
217
+ address = host_elem.find("address")
185
218
  if address is not None and address.text:
186
- host_data = {'ip': address.text}
219
+ host_data = {"ip": address.text}
187
220
 
188
- name = host_elem.find('name')
221
+ name = host_elem.find("name")
189
222
  if name is not None and name.text:
190
- host_data['hostname'] = name.text
223
+ host_data["hostname"] = name.text
191
224
 
192
- os_name = host_elem.find('os-name')
225
+ os_name = host_elem.find("os-name")
193
226
  if os_name is not None and os_name.text:
194
- host_data['os'] = os_name.text
227
+ host_data["os"] = os_name.text
195
228
 
196
- host_data['status'] = 'up'
229
+ host_data["status"] = "up"
197
230
  host_id = hm.add_or_update_host(engagement_id, host_data)
198
- results['hosts'] += 1
231
+ results["hosts"] += 1
199
232
 
200
233
  # Import services for this host
201
- if 'services' in import_types:
202
- for svc in host_elem.findall('.//service'):
203
- port = svc.find('port')
204
- proto = svc.find('proto')
205
- name = svc.find('name')
206
- info = svc.find('info')
207
- state = svc.find('state')
234
+ if "services" in import_types:
235
+ for svc in host_elem.findall(".//service"):
236
+ port = svc.find("port")
237
+ proto = svc.find("proto")
238
+ name = svc.find("name")
239
+ info = svc.find("info")
240
+ state = svc.find("state")
208
241
 
209
242
  if port is not None:
210
243
  hm.add_service(
211
244
  host_id=host_id,
212
245
  port=int(port.text),
213
- protocol=proto.text if proto is not None else 'tcp',
214
- state=state.text if state is not None else 'open',
215
- service_name=name.text if name is not None else None,
216
- service_version=info.text if info is not None else None
246
+ protocol=(
247
+ proto.text if proto is not None else "tcp"
248
+ ),
249
+ state=(
250
+ state.text if state is not None else "open"
251
+ ),
252
+ service_name=(
253
+ name.text if name is not None else None
254
+ ),
255
+ service_version=(
256
+ info.text if info is not None else None
257
+ ),
217
258
  )
218
- results['services'] += 1
259
+ results["services"] += 1
219
260
 
220
261
  # Import credentials
221
- if 'credentials' in import_types:
222
- creds = root.findall('.//cred')
262
+ if "credentials" in import_types:
263
+ creds = root.findall(".//cred")
223
264
  for cred in creds:
224
- user = cred.find('user')
225
- pass_elem = cred.find('pass')
226
- service_name = cred.find('service')
265
+ user = cred.find("user")
266
+ pass_elem = cred.find("pass")
267
+ service_name = cred.find("service")
227
268
 
228
269
  if user is not None:
229
270
  # Try to find associated host
230
- host_elem = cred.find('.//host')
271
+ host_elem = cred.find(".//host")
231
272
  target_host = None
232
273
  if host_elem is not None:
233
- addr = host_elem.find('address')
274
+ addr = host_elem.find("address")
234
275
  if addr is not None:
235
276
  target_host = addr.text
236
277
 
@@ -239,59 +280,65 @@ class SmartImporter:
239
280
  username=user.text,
240
281
  password=pass_elem.text if pass_elem is not None else None,
241
282
  host=target_host,
242
- service=service_name.text if service_name is not None else None,
243
- source='msf_import'
283
+ service=(
284
+ service_name.text if service_name is not None else None
285
+ ),
286
+ source="msf_import",
244
287
  )
245
- results['credentials'] += 1
288
+ results["credentials"] += 1
246
289
 
247
290
  # Import vulnerabilities as findings
248
- if 'vulnerabilities' in import_types:
249
- notes = root.findall('.//note')
291
+ if "vulnerabilities" in import_types:
292
+ notes = root.findall(".//note")
250
293
  for note in notes:
251
- ntype = note.find('ntype')
252
- data = note.find('data')
294
+ ntype = note.find("ntype")
295
+ data = note.find("data")
253
296
 
254
297
  if ntype is not None and data is not None:
255
- if 'vuln' in ntype.text.lower() or self._looks_like_vuln(data.text):
298
+ if "vuln" in ntype.text.lower() or self._looks_like_vuln(
299
+ data.text
300
+ ):
256
301
  # Extract host if available
257
- host_elem = note.find('.//host')
302
+ host_elem = note.find(".//host")
258
303
  host_ip = None
259
304
  host_id = None
260
305
 
261
306
  if host_elem is not None:
262
- addr = host_elem.find('address')
307
+ addr = host_elem.find("address")
263
308
  if addr is not None:
264
309
  host_ip = addr.text
265
310
  host_obj = hm.get_host_by_ip(engagement_id, host_ip)
266
311
  if host_obj:
267
- host_id = host_obj['id']
312
+ host_id = host_obj["id"]
268
313
 
269
314
  fm.add_finding(
270
315
  engagement_id=engagement_id,
271
316
  host_id=host_id,
272
317
  title=ntype.text,
273
- finding_type='vulnerability',
274
- severity='medium',
318
+ finding_type="vulnerability",
319
+ severity="medium",
275
320
  description=data.text,
276
- tool='msf_import'
321
+ tool="msf_import",
277
322
  )
278
- results['vulnerabilities'] += 1
323
+ results["vulnerabilities"] += 1
279
324
 
280
325
  # Import web vulnerabilities
281
- if 'web_paths' in import_types:
282
- web_vulns = root.findall('.//web_vuln')
326
+ if "web_paths" in import_types:
327
+ web_vulns = root.findall(".//web_vuln")
283
328
  for wv in web_vulns:
284
- path = wv.find('path')
285
- method = wv.find('method')
286
- pname = wv.find('pname')
287
- proof = wv.find('proof')
329
+ path = wv.find("path")
330
+ method = wv.find("method")
331
+ pname = wv.find("pname")
332
+ proof = wv.find("proof")
288
333
 
289
334
  if path is not None:
290
335
  title = f"Web vulnerability in {path.text}"
291
336
  if pname is not None:
292
337
  title += f" (parameter: {pname.text})"
293
338
 
294
- description = f"Method: {method.text if method is not None else 'N/A'}\n"
339
+ description = (
340
+ f"Method: {method.text if method is not None else 'N/A'}\n"
341
+ )
295
342
  description += f"Path: {path.text}\n"
296
343
  if proof is not None:
297
344
  description += f"Proof: {proof.text}\n"
@@ -300,23 +347,23 @@ class SmartImporter:
300
347
  engagement_id=engagement_id,
301
348
  host_id=None,
302
349
  title=title,
303
- finding_type='web_vulnerability',
304
- severity='medium',
350
+ finding_type="web_vulnerability",
351
+ severity="medium",
305
352
  description=description,
306
- tool='msf_import',
307
- path=path.text if path is not None else None
353
+ tool="msf_import",
354
+ path=path.text if path is not None else None,
308
355
  )
309
- results['web_paths'] += 1
356
+ results["web_paths"] += 1
310
357
 
311
358
  return results
312
359
 
313
360
  except Exception as e:
314
- return {'error': str(e)}
361
+ return {"error": str(e)}
315
362
 
316
363
 
317
364
  def format_preview_summary(analysis: Dict[str, Any]) -> str:
318
365
  """Format analysis results into readable summary."""
319
- if 'error' in analysis:
366
+ if "error" in analysis:
320
367
  return f"Error analyzing file: {analysis['error']}"
321
368
 
322
369
  lines = []
@@ -325,17 +372,31 @@ def format_preview_summary(analysis: Dict[str, Any]) -> str:
325
372
  lines.append("=" * 70 + "\n")
326
373
 
327
374
  total_items = sum(
328
- analysis[key]['count']
329
- for key in ['hosts', 'services', 'vulnerabilities', 'credentials', 'web_paths', 'notes']
375
+ analysis[key]["count"]
376
+ for key in [
377
+ "hosts",
378
+ "services",
379
+ "vulnerabilities",
380
+ "credentials",
381
+ "web_paths",
382
+ "notes",
383
+ ]
330
384
  if key in analysis
331
385
  )
332
386
 
333
387
  lines.append(f"Total items detected: {total_items}\n")
334
388
 
335
- for data_type in ['hosts', 'services', 'vulnerabilities', 'credentials', 'web_paths', 'notes']:
336
- if data_type in analysis and analysis[data_type]['count'] > 0:
337
- count = analysis[data_type]['count']
338
- preview = analysis[data_type]['preview']
389
+ for data_type in [
390
+ "hosts",
391
+ "services",
392
+ "vulnerabilities",
393
+ "credentials",
394
+ "web_paths",
395
+ "notes",
396
+ ]:
397
+ if data_type in analysis and analysis[data_type]["count"] > 0:
398
+ count = analysis[data_type]["count"]
399
+ preview = analysis[data_type]["preview"]
339
400
 
340
401
  lines.append(f" ✓ {data_type.upper()}: {count}")
341
402
 
@@ -35,16 +35,16 @@ from souleyez.integrations.siem.factory import SIEMFactory
35
35
 
36
36
  __all__ = [
37
37
  # Base classes
38
- 'SIEMClient',
39
- 'SIEMAlert',
40
- 'SIEMRule',
41
- 'SIEMConnectionStatus',
38
+ "SIEMClient",
39
+ "SIEMAlert",
40
+ "SIEMRule",
41
+ "SIEMConnectionStatus",
42
42
  # Factory
43
- 'SIEMFactory',
43
+ "SIEMFactory",
44
44
  # Implementations
45
- 'WazuhSIEMClient',
46
- 'SplunkSIEMClient',
47
- 'ElasticSIEMClient',
48
- 'SentinelSIEMClient',
49
- 'GoogleSecOpsSIEMClient',
45
+ "WazuhSIEMClient",
46
+ "SplunkSIEMClient",
47
+ "ElasticSIEMClient",
48
+ "SentinelSIEMClient",
49
+ "GoogleSecOpsSIEMClient",
50
50
  ]
@@ -35,7 +35,7 @@ class SIEMAlert:
35
35
  self,
36
36
  attack_type: str,
37
37
  source_ip: Optional[str] = None,
38
- dest_ip: Optional[str] = None
38
+ dest_ip: Optional[str] = None,
39
39
  ) -> bool:
40
40
  """Check if this alert matches an attack pattern.
41
41
 
@@ -55,7 +55,7 @@ class SIEMAlert:
55
55
 
56
56
  # Attack type is typically checked against rule patterns
57
57
  # This is a base implementation - subclasses may override
58
- attack_keywords = attack_type.lower().split('_')
58
+ attack_keywords = attack_type.lower().split("_")
59
59
  rule_text = f"{self.rule_name} {self.description}".lower()
60
60
 
61
61
  return any(kw in rule_text for kw in attack_keywords)
@@ -121,7 +121,7 @@ class SIEMClient(ABC):
121
121
  dest_ip: Optional[str] = None,
122
122
  rule_ids: Optional[List[str]] = None,
123
123
  search_text: Optional[str] = None,
124
- limit: int = 100
124
+ limit: int = 100,
125
125
  ) -> List[SIEMAlert]:
126
126
  """Query alerts from the SIEM.
127
127
 
@@ -141,9 +141,7 @@ class SIEMClient(ABC):
141
141
 
142
142
  @abstractmethod
143
143
  def get_rules(
144
- self,
145
- rule_ids: Optional[List[str]] = None,
146
- enabled_only: bool = True
144
+ self, rule_ids: Optional[List[str]] = None, enabled_only: bool = True
147
145
  ) -> List[SIEMRule]:
148
146
  """Get detection rules from the SIEM.
149
147
 
@@ -179,7 +177,7 @@ class SIEMClient(ABC):
179
177
  attack_time: datetime,
180
178
  source_ip: Optional[str] = None,
181
179
  target_ip: Optional[str] = None,
182
- time_window_minutes: int = 5
180
+ time_window_minutes: int = 5,
183
181
  ) -> List[SIEMAlert]:
184
182
  """Search for alerts related to a specific attack.
185
183
 
@@ -207,12 +205,13 @@ class SIEMClient(ABC):
207
205
  start_time=start_time,
208
206
  end_time=end_time,
209
207
  source_ip=source_ip,
210
- dest_ip=target_ip
208
+ dest_ip=target_ip,
211
209
  )
212
210
 
213
211
  # Filter by attack type patterns
214
212
  matching_alerts = [
215
- alert for alert in alerts
213
+ alert
214
+ for alert in alerts
216
215
  if alert.matches_attack(attack_type, source_ip, target_ip)
217
216
  ]
218
217
 
@@ -224,7 +223,7 @@ class SIEMClient(ABC):
224
223
  attack_time: datetime,
225
224
  source_ip: Optional[str] = None,
226
225
  target_ip: Optional[str] = None,
227
- expected_rule_ids: Optional[List[str]] = None
226
+ expected_rule_ids: Optional[List[str]] = None,
228
227
  ) -> Dict[str, Any]:
229
228
  """Check if an attack was detected by the SIEM.
230
229
 
@@ -247,23 +246,23 @@ class SIEMClient(ABC):
247
246
  attack_type=attack_type,
248
247
  attack_time=attack_time,
249
248
  source_ip=source_ip,
250
- target_ip=target_ip
249
+ target_ip=target_ip,
251
250
  )
252
251
 
253
252
  matched_rules = list(set(alert.rule_id for alert in alerts))
254
253
 
255
254
  result = {
256
- 'detected': len(alerts) > 0,
257
- 'alerts': alerts,
258
- 'alert_count': len(alerts),
259
- 'matched_rules': matched_rules,
260
- 'matched_rule_count': len(matched_rules),
255
+ "detected": len(alerts) > 0,
256
+ "alerts": alerts,
257
+ "alert_count": len(alerts),
258
+ "matched_rules": matched_rules,
259
+ "matched_rule_count": len(matched_rules),
261
260
  }
262
261
 
263
262
  if expected_rule_ids:
264
263
  expected_set = set(str(r) for r in expected_rule_ids)
265
264
  matched_set = set(str(r) for r in matched_rules)
266
- result['expected_rules_matched'] = list(expected_set & matched_set)
267
- result['expected_rules_missed'] = list(expected_set - matched_set)
265
+ result["expected_rules_matched"] = list(expected_set & matched_set)
266
+ result["expected_rules_missed"] = list(expected_set - matched_set)
268
267
 
269
268
  return result