souleyez 2.43.26__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.

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 +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 +23434 -10286
  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.26.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.26.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
  355. souleyez-2.43.26.dist-info/RECORD +0 -379
  356. {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
  357. {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
  358. {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
@@ -28,11 +28,11 @@ class MSFImporter:
28
28
  self.fm = FindingsManager()
29
29
 
30
30
  self.stats = {
31
- 'hosts': 0,
32
- 'services': 0,
33
- 'credentials': 0,
34
- 'vulnerabilities': 0,
35
- 'skipped': 0
31
+ "hosts": 0,
32
+ "services": 0,
33
+ "credentials": 0,
34
+ "vulnerabilities": 0,
35
+ "skipped": 0,
36
36
  }
37
37
 
38
38
  def import_xml(self, xml_file: str, verbose: bool = False) -> Dict:
@@ -61,7 +61,7 @@ class MSFImporter:
61
61
  click.echo("XML parsed successfully")
62
62
 
63
63
  # Import hosts first
64
- hosts = root.findall('.//host')
64
+ hosts = root.findall(".//host")
65
65
  if verbose:
66
66
  click.echo(f"\nFound {len(hosts)} hosts")
67
67
 
@@ -70,7 +70,11 @@ class MSFImporter:
70
70
  for host_elem in hosts:
71
71
  host_id = self._import_host(host_elem, verbose)
72
72
  if host_id:
73
- address = host_elem.find('address').text if host_elem.find('address') is not None else None
73
+ address = (
74
+ host_elem.find("address").text
75
+ if host_elem.find("address") is not None
76
+ else None
77
+ )
74
78
  if address:
75
79
  host_mapping[address] = host_id
76
80
 
@@ -79,14 +83,18 @@ class MSFImporter:
79
83
  click.echo("\nImporting services...")
80
84
 
81
85
  for host_elem in hosts:
82
- address = host_elem.find('address').text if host_elem.find('address') is not None else None
86
+ address = (
87
+ host_elem.find("address").text
88
+ if host_elem.find("address") is not None
89
+ else None
90
+ )
83
91
  if address and address in host_mapping:
84
- services = host_elem.findall('.//service')
92
+ services = host_elem.findall(".//service")
85
93
  for svc_elem in services:
86
94
  self._import_service(svc_elem, host_mapping[address], verbose)
87
95
 
88
96
  # Import credentials
89
- creds = root.findall('.//cred')
97
+ creds = root.findall(".//cred")
90
98
  if verbose and creds:
91
99
  click.echo(f"\nFound {len(creds)} credentials")
92
100
 
@@ -94,8 +102,8 @@ class MSFImporter:
94
102
  self._import_credential(cred_elem, host_mapping, verbose)
95
103
 
96
104
  # Import vulnerabilities/notes as findings
97
- vulns = root.findall('.//vuln')
98
- notes = root.findall('.//note')
105
+ vulns = root.findall(".//vuln")
106
+ notes = root.findall(".//note")
99
107
 
100
108
  if verbose and (vulns or notes):
101
109
  click.echo(f"\nFound {len(vulns)} vulnerabilities and {len(notes)} notes")
@@ -105,20 +113,22 @@ class MSFImporter:
105
113
 
106
114
  return self.stats
107
115
 
108
- def _import_host(self, host_elem: 'Element', verbose: bool = False) -> Optional[int]:
116
+ def _import_host(
117
+ self, host_elem: "Element", verbose: bool = False
118
+ ) -> Optional[int]:
109
119
  """Import a single host."""
110
- address = host_elem.find('address')
120
+ address = host_elem.find("address")
111
121
  if address is None or not address.text:
112
- self.stats['skipped'] += 1
122
+ self.stats["skipped"] += 1
113
123
  return None
114
124
 
115
125
  ip_address = address.text
116
126
  # mac = host_elem.find('mac') # not used currently
117
127
 
118
128
  # Get OS info
119
- os_name_elem = host_elem.find('os-name')
120
- os_flavor_elem = host_elem.find('os-flavor')
121
- os_sp_elem = host_elem.find('os-sp')
129
+ os_name_elem = host_elem.find("os-name")
130
+ os_flavor_elem = host_elem.find("os-flavor")
131
+ os_sp_elem = host_elem.find("os-sp")
122
132
 
123
133
  os_parts = []
124
134
  if os_name_elem is not None and os_name_elem.text:
@@ -128,35 +138,37 @@ class MSFImporter:
128
138
  if os_sp_elem is not None and os_sp_elem.text:
129
139
  os_parts.append(os_sp_elem.text)
130
140
 
131
- os_name = ' '.join(os_parts) if os_parts else None
141
+ os_name = " ".join(os_parts) if os_parts else None
132
142
 
133
143
  # Get hostname
134
- name_elem = host_elem.find('name')
144
+ name_elem = host_elem.find("name")
135
145
  hostname = name_elem.text if name_elem is not None and name_elem.text else None
136
146
 
137
147
  # Check host state
138
- state_elem = host_elem.find('state')
139
- state = state_elem.text if state_elem is not None else 'up'
148
+ state_elem = host_elem.find("state")
149
+ state = state_elem.text if state_elem is not None else "up"
140
150
 
141
151
  if verbose:
142
152
  click.echo(f" Importing host: {ip_address} ({hostname or 'no hostname'})")
143
153
 
144
154
  # Add or update host
145
155
  host_data = {
146
- 'ip': ip_address,
147
- 'hostname': hostname,
148
- 'os': os_name,
149
- 'status': state
156
+ "ip": ip_address,
157
+ "hostname": hostname,
158
+ "os": os_name,
159
+ "status": state,
150
160
  }
151
161
 
152
162
  host_id = self.hm.add_or_update_host(self.engagement_id, host_data)
153
163
 
154
- self.stats['hosts'] += 1
164
+ self.stats["hosts"] += 1
155
165
  return host_id
156
166
 
157
- def _import_service(self, svc_elem: 'Element', host_id: int, verbose: bool = False) -> Optional[int]:
167
+ def _import_service(
168
+ self, svc_elem: "Element", host_id: int, verbose: bool = False
169
+ ) -> Optional[int]:
158
170
  """Import a single service."""
159
- port_elem = svc_elem.find('port')
171
+ port_elem = svc_elem.find("port")
160
172
  if port_elem is None or not port_elem.text:
161
173
  return None
162
174
 
@@ -165,41 +177,49 @@ class MSFImporter:
165
177
  except ValueError:
166
178
  return None
167
179
 
168
- proto_elem = svc_elem.find('proto')
169
- protocol = proto_elem.text if proto_elem is not None and proto_elem.text else 'tcp'
180
+ proto_elem = svc_elem.find("proto")
181
+ protocol = (
182
+ proto_elem.text if proto_elem is not None and proto_elem.text else "tcp"
183
+ )
170
184
 
171
- name_elem = svc_elem.find('name')
172
- service_name = name_elem.text if name_elem is not None and name_elem.text else 'unknown'
185
+ name_elem = svc_elem.find("name")
186
+ service_name = (
187
+ name_elem.text if name_elem is not None and name_elem.text else "unknown"
188
+ )
173
189
 
174
190
  # Get service info/version
175
- info_elem = svc_elem.find('info')
176
- service_version = info_elem.text if info_elem is not None and info_elem.text else None
191
+ info_elem = svc_elem.find("info")
192
+ service_version = (
193
+ info_elem.text if info_elem is not None and info_elem.text else None
194
+ )
177
195
 
178
- state_elem = svc_elem.find('state')
179
- state = state_elem.text if state_elem is not None else 'open'
196
+ state_elem = svc_elem.find("state")
197
+ state = state_elem.text if state_elem is not None else "open"
180
198
 
181
199
  if verbose:
182
200
  click.echo(f" Service: {port}/{protocol} ({service_name})")
183
201
 
184
202
  # Add service
185
203
  service_data = {
186
- 'port': port,
187
- 'protocol': protocol,
188
- 'state': state,
189
- 'service': service_name,
190
- 'version': service_version
204
+ "port": port,
205
+ "protocol": protocol,
206
+ "state": state,
207
+ "service": service_name,
208
+ "version": service_version,
191
209
  }
192
210
 
193
211
  self.hm.add_service(host_id, service_data)
194
212
 
195
- self.stats['services'] += 1
213
+ self.stats["services"] += 1
196
214
  return port
197
215
 
198
- def _import_credential(self, cred_elem: 'Element', host_mapping: Dict, verbose: bool = False):
216
+ def _import_credential(
217
+ self, cred_elem: "Element", host_mapping: Dict, verbose: bool = False
218
+ ):
199
219
  """Import a single credential."""
200
220
  # Get credential details
201
- user_elem = cred_elem.find('.//username')
202
- pass_elem = cred_elem.find('.//password')
221
+ user_elem = cred_elem.find(".//username")
222
+ pass_elem = cred_elem.find(".//password")
203
223
  # type_elem = cred_elem.find('.//type') # not used currently
204
224
 
205
225
  username = user_elem.text if user_elem is not None and user_elem.text else None
@@ -210,21 +230,21 @@ class MSFImporter:
210
230
  return
211
231
 
212
232
  # Try to get associated service info
213
- service_elem = cred_elem.find('.//service')
214
- host_elem = cred_elem.find('.//host')
233
+ service_elem = cred_elem.find(".//service")
234
+ host_elem = cred_elem.find(".//host")
215
235
 
216
236
  ip_address = None
217
237
  service_name = None
218
238
  port = None
219
239
 
220
240
  if host_elem is not None:
221
- address_elem = host_elem.find('address')
241
+ address_elem = host_elem.find("address")
222
242
  if address_elem is not None:
223
243
  ip_address = address_elem.text
224
244
 
225
245
  if service_elem is not None:
226
- name_elem = service_elem.find('name')
227
- port_elem = service_elem.find('port')
246
+ name_elem = service_elem.find("name")
247
+ port_elem = service_elem.find("port")
228
248
 
229
249
  if name_elem is not None:
230
250
  service_name = name_elem.text
@@ -235,7 +255,7 @@ class MSFImporter:
235
255
  pass
236
256
 
237
257
  # Determine status - if we have a password, assume it's valid
238
- status = 'valid' if password else 'discovered'
258
+ status = "valid" if password else "discovered"
239
259
 
240
260
  # Get host_id from IP
241
261
  host_id = None
@@ -263,26 +283,28 @@ class MSFImporter:
263
283
  service=service_name,
264
284
  port=port,
265
285
  status=status,
266
- tool='msf_import'
286
+ tool="msf_import",
267
287
  )
268
288
 
269
- self.stats['credentials'] += 1
289
+ self.stats["credentials"] += 1
270
290
 
271
- def _import_vulnerability(self, vuln_elem: 'Element', host_mapping: Dict, verbose: bool = False):
291
+ def _import_vulnerability(
292
+ self, vuln_elem: "Element", host_mapping: Dict, verbose: bool = False
293
+ ):
272
294
  """Import a vulnerability as a finding."""
273
- name_elem = vuln_elem.find('name')
295
+ name_elem = vuln_elem.find("name")
274
296
  if name_elem is None or not name_elem.text:
275
297
  return
276
298
 
277
299
  title = name_elem.text
278
300
 
279
301
  # Get host
280
- host_elem = vuln_elem.find('host')
302
+ host_elem = vuln_elem.find("host")
281
303
  ip_address = None
282
304
  host_id = None
283
305
 
284
306
  if host_elem is not None:
285
- address_elem = host_elem.find('address')
307
+ address_elem = host_elem.find("address")
286
308
  if address_elem is not None and address_elem.text:
287
309
  ip_address = address_elem.text
288
310
  host_id = host_mapping.get(ip_address)
@@ -291,7 +313,7 @@ class MSFImporter:
291
313
  return
292
314
 
293
315
  # Get port
294
- port_elem = vuln_elem.find('port')
316
+ port_elem = vuln_elem.find("port")
295
317
  port = None
296
318
  if port_elem is not None and port_elem.text:
297
319
  try:
@@ -300,18 +322,22 @@ class MSFImporter:
300
322
  pass
301
323
 
302
324
  # Get refs
303
- refs_elem = vuln_elem.find('refs')
325
+ refs_elem = vuln_elem.find("refs")
304
326
  refs = []
305
327
  if refs_elem is not None:
306
- for ref_elem in refs_elem.findall('ref'):
328
+ for ref_elem in refs_elem.findall("ref"):
307
329
  if ref_elem.text:
308
330
  refs.append(ref_elem.text)
309
331
 
310
- refs_text = '\n'.join(refs) if refs else None
332
+ refs_text = "\n".join(refs) if refs else None
311
333
 
312
334
  # Get info/description
313
- info_elem = vuln_elem.find('info')
314
- description = info_elem.text if info_elem is not None and info_elem.text else f"Vulnerability: {title}"
335
+ info_elem = vuln_elem.find("info")
336
+ description = (
337
+ info_elem.text
338
+ if info_elem is not None and info_elem.text
339
+ else f"Vulnerability: {title}"
340
+ )
315
341
 
316
342
  # Try to determine severity from name/refs
317
343
  severity = self._determine_severity(title, refs_text)
@@ -323,38 +349,43 @@ class MSFImporter:
323
349
  self.fm.add_finding(
324
350
  engagement_id=self.engagement_id,
325
351
  title=title,
326
- finding_type='vulnerability',
352
+ finding_type="vulnerability",
327
353
  severity=severity,
328
354
  description=description,
329
355
  host_id=host_id,
330
356
  port=port,
331
- tool='msf_import',
332
- refs=refs_text
357
+ tool="msf_import",
358
+ refs=refs_text,
333
359
  )
334
360
 
335
- self.stats['vulnerabilities'] += 1
361
+ self.stats["vulnerabilities"] += 1
336
362
 
337
363
  def _determine_severity(self, title: str, refs: Optional[str]) -> str:
338
364
  """Try to determine severity from vulnerability title and references."""
339
365
  title_lower = title.lower()
340
- refs_lower = refs.lower() if refs else ''
366
+ refs_lower = refs.lower() if refs else ""
341
367
 
342
368
  # Critical indicators
343
- critical_keywords = ['rce', 'remote code execution', 'unauthenticated', 'critical']
369
+ critical_keywords = [
370
+ "rce",
371
+ "remote code execution",
372
+ "unauthenticated",
373
+ "critical",
374
+ ]
344
375
  for keyword in critical_keywords:
345
376
  if keyword in title_lower:
346
- return 'critical'
377
+ return "critical"
347
378
 
348
379
  # High indicators
349
- high_keywords = ['exploit', 'overflow', 'injection', 'authentication bypass']
380
+ high_keywords = ["exploit", "overflow", "injection", "authentication bypass"]
350
381
  for keyword in high_keywords:
351
382
  if keyword in title_lower:
352
- return 'high'
383
+ return "high"
353
384
 
354
385
  # Check CVE scores (if available in refs)
355
- if 'cvss' in refs_lower:
386
+ if "cvss" in refs_lower:
356
387
  # Could parse CVSS scores here
357
388
  pass
358
389
 
359
390
  # Default to medium for vulnerabilities
360
- return 'medium'
391
+ return "medium"