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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. souleyez/__init__.py +1 -2
  2. souleyez/ai/__init__.py +21 -15
  3. souleyez/ai/action_mapper.py +249 -150
  4. souleyez/ai/chain_advisor.py +116 -100
  5. souleyez/ai/claude_provider.py +29 -28
  6. souleyez/ai/context_builder.py +80 -62
  7. souleyez/ai/executor.py +158 -117
  8. souleyez/ai/feedback_handler.py +136 -121
  9. souleyez/ai/llm_factory.py +27 -20
  10. souleyez/ai/llm_provider.py +4 -2
  11. souleyez/ai/ollama_provider.py +6 -9
  12. souleyez/ai/ollama_service.py +44 -37
  13. souleyez/ai/path_scorer.py +91 -76
  14. souleyez/ai/recommender.py +176 -144
  15. souleyez/ai/report_context.py +74 -73
  16. souleyez/ai/report_service.py +84 -66
  17. souleyez/ai/result_parser.py +222 -229
  18. souleyez/ai/safety.py +67 -44
  19. souleyez/auth/__init__.py +23 -22
  20. souleyez/auth/audit.py +36 -26
  21. souleyez/auth/engagement_access.py +65 -48
  22. souleyez/auth/permissions.py +14 -3
  23. souleyez/auth/session_manager.py +54 -37
  24. souleyez/auth/user_manager.py +109 -64
  25. souleyez/commands/audit.py +40 -43
  26. souleyez/commands/auth.py +35 -15
  27. souleyez/commands/deliverables.py +55 -50
  28. souleyez/commands/engagement.py +47 -28
  29. souleyez/commands/license.py +32 -23
  30. souleyez/commands/screenshots.py +36 -32
  31. souleyez/commands/user.py +82 -36
  32. souleyez/config.py +52 -44
  33. souleyez/core/credential_tester.py +87 -81
  34. souleyez/core/cve_mappings.py +179 -192
  35. souleyez/core/cve_matcher.py +162 -148
  36. souleyez/core/msf_auto_mapper.py +100 -83
  37. souleyez/core/msf_chain_engine.py +294 -256
  38. souleyez/core/msf_database.py +153 -70
  39. souleyez/core/msf_integration.py +679 -673
  40. souleyez/core/msf_rpc_client.py +40 -42
  41. souleyez/core/msf_rpc_manager.py +77 -79
  42. souleyez/core/msf_sync_manager.py +241 -181
  43. souleyez/core/network_utils.py +22 -15
  44. souleyez/core/parser_handler.py +34 -25
  45. souleyez/core/pending_chains.py +114 -63
  46. souleyez/core/templates.py +158 -107
  47. souleyez/core/tool_chaining.py +9592 -2879
  48. souleyez/core/version_utils.py +79 -94
  49. souleyez/core/vuln_correlation.py +136 -89
  50. souleyez/core/web_utils.py +33 -32
  51. souleyez/data/wordlists/ad_users.txt +378 -0
  52. souleyez/data/wordlists/api_endpoints_large.txt +769 -0
  53. souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
  54. souleyez/data/wordlists/lfi_payloads.txt +82 -0
  55. souleyez/data/wordlists/passwords_brute.txt +1548 -0
  56. souleyez/data/wordlists/passwords_crack.txt +2479 -0
  57. souleyez/data/wordlists/passwords_spray.txt +386 -0
  58. souleyez/data/wordlists/subdomains_large.txt +5057 -0
  59. souleyez/data/wordlists/usernames_common.txt +694 -0
  60. souleyez/data/wordlists/web_dirs_large.txt +4769 -0
  61. souleyez/detection/__init__.py +1 -1
  62. souleyez/detection/attack_signatures.py +12 -17
  63. souleyez/detection/mitre_mappings.py +61 -55
  64. souleyez/detection/validator.py +97 -86
  65. souleyez/devtools.py +23 -10
  66. souleyez/docs/README.md +4 -4
  67. souleyez/docs/api-reference/cli-commands.md +2 -2
  68. souleyez/docs/developer-guide/adding-new-tools.md +562 -0
  69. souleyez/docs/user-guide/auto-chaining.md +30 -8
  70. souleyez/docs/user-guide/getting-started.md +1 -1
  71. souleyez/docs/user-guide/installation.md +26 -3
  72. souleyez/docs/user-guide/metasploit-integration.md +2 -2
  73. souleyez/docs/user-guide/rbac.md +1 -1
  74. souleyez/docs/user-guide/scope-management.md +1 -1
  75. souleyez/docs/user-guide/siem-integration.md +1 -1
  76. souleyez/docs/user-guide/tools-reference.md +1 -8
  77. souleyez/docs/user-guide/worker-management.md +1 -1
  78. souleyez/engine/background.py +1238 -535
  79. souleyez/engine/base.py +4 -1
  80. souleyez/engine/job_status.py +17 -49
  81. souleyez/engine/log_sanitizer.py +103 -77
  82. souleyez/engine/manager.py +38 -7
  83. souleyez/engine/result_handler.py +2198 -1550
  84. souleyez/engine/worker_manager.py +50 -41
  85. souleyez/export/evidence_bundle.py +72 -62
  86. souleyez/feature_flags/features.py +16 -20
  87. souleyez/feature_flags.py +5 -9
  88. souleyez/handlers/__init__.py +11 -0
  89. souleyez/handlers/base.py +188 -0
  90. souleyez/handlers/bash_handler.py +277 -0
  91. souleyez/handlers/bloodhound_handler.py +243 -0
  92. souleyez/handlers/certipy_handler.py +311 -0
  93. souleyez/handlers/crackmapexec_handler.py +486 -0
  94. souleyez/handlers/dnsrecon_handler.py +344 -0
  95. souleyez/handlers/enum4linux_handler.py +400 -0
  96. souleyez/handlers/evil_winrm_handler.py +493 -0
  97. souleyez/handlers/ffuf_handler.py +815 -0
  98. souleyez/handlers/gobuster_handler.py +1114 -0
  99. souleyez/handlers/gpp_extract_handler.py +334 -0
  100. souleyez/handlers/hashcat_handler.py +444 -0
  101. souleyez/handlers/hydra_handler.py +563 -0
  102. souleyez/handlers/impacket_getuserspns_handler.py +343 -0
  103. souleyez/handlers/impacket_psexec_handler.py +222 -0
  104. souleyez/handlers/impacket_secretsdump_handler.py +426 -0
  105. souleyez/handlers/john_handler.py +286 -0
  106. souleyez/handlers/katana_handler.py +425 -0
  107. souleyez/handlers/kerbrute_handler.py +298 -0
  108. souleyez/handlers/ldapsearch_handler.py +636 -0
  109. souleyez/handlers/lfi_extract_handler.py +464 -0
  110. souleyez/handlers/msf_auxiliary_handler.py +408 -0
  111. souleyez/handlers/msf_exploit_handler.py +380 -0
  112. souleyez/handlers/nikto_handler.py +413 -0
  113. souleyez/handlers/nmap_handler.py +821 -0
  114. souleyez/handlers/nuclei_handler.py +359 -0
  115. souleyez/handlers/nxc_handler.py +371 -0
  116. souleyez/handlers/rdp_sec_check_handler.py +353 -0
  117. souleyez/handlers/registry.py +288 -0
  118. souleyez/handlers/responder_handler.py +232 -0
  119. souleyez/handlers/service_explorer_handler.py +434 -0
  120. souleyez/handlers/smbclient_handler.py +344 -0
  121. souleyez/handlers/smbmap_handler.py +510 -0
  122. souleyez/handlers/smbpasswd_handler.py +296 -0
  123. souleyez/handlers/sqlmap_handler.py +1116 -0
  124. souleyez/handlers/theharvester_handler.py +601 -0
  125. souleyez/handlers/whois_handler.py +277 -0
  126. souleyez/handlers/wpscan_handler.py +554 -0
  127. souleyez/history.py +32 -16
  128. souleyez/importers/msf_importer.py +106 -75
  129. souleyez/importers/smart_importer.py +208 -147
  130. souleyez/integrations/siem/__init__.py +10 -10
  131. souleyez/integrations/siem/base.py +17 -18
  132. souleyez/integrations/siem/elastic.py +108 -122
  133. souleyez/integrations/siem/factory.py +207 -80
  134. souleyez/integrations/siem/googlesecops.py +146 -154
  135. souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
  136. souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
  137. souleyez/integrations/siem/sentinel.py +107 -109
  138. souleyez/integrations/siem/splunk.py +246 -212
  139. souleyez/integrations/siem/wazuh.py +65 -71
  140. souleyez/integrations/wazuh/__init__.py +5 -5
  141. souleyez/integrations/wazuh/client.py +70 -93
  142. souleyez/integrations/wazuh/config.py +85 -57
  143. souleyez/integrations/wazuh/host_mapper.py +28 -36
  144. souleyez/integrations/wazuh/sync.py +78 -68
  145. souleyez/intelligence/__init__.py +4 -5
  146. souleyez/intelligence/correlation_analyzer.py +309 -295
  147. souleyez/intelligence/exploit_knowledge.py +661 -623
  148. souleyez/intelligence/exploit_suggestions.py +159 -139
  149. souleyez/intelligence/gap_analyzer.py +132 -97
  150. souleyez/intelligence/gap_detector.py +251 -214
  151. souleyez/intelligence/sensitive_tables.py +266 -129
  152. souleyez/intelligence/service_parser.py +137 -123
  153. souleyez/intelligence/surface_analyzer.py +407 -268
  154. souleyez/intelligence/target_parser.py +159 -162
  155. souleyez/licensing/__init__.py +6 -6
  156. souleyez/licensing/validator.py +17 -19
  157. souleyez/log_config.py +79 -54
  158. souleyez/main.py +1505 -687
  159. souleyez/migrations/fix_job_counter.py +16 -14
  160. souleyez/parsers/bloodhound_parser.py +41 -39
  161. souleyez/parsers/crackmapexec_parser.py +178 -111
  162. souleyez/parsers/dalfox_parser.py +72 -77
  163. souleyez/parsers/dnsrecon_parser.py +103 -91
  164. souleyez/parsers/enum4linux_parser.py +183 -153
  165. souleyez/parsers/ffuf_parser.py +29 -25
  166. souleyez/parsers/gobuster_parser.py +301 -41
  167. souleyez/parsers/hashcat_parser.py +324 -79
  168. souleyez/parsers/http_fingerprint_parser.py +350 -103
  169. souleyez/parsers/hydra_parser.py +131 -111
  170. souleyez/parsers/impacket_parser.py +231 -178
  171. souleyez/parsers/john_parser.py +98 -86
  172. souleyez/parsers/katana_parser.py +316 -0
  173. souleyez/parsers/msf_parser.py +943 -498
  174. souleyez/parsers/nikto_parser.py +346 -65
  175. souleyez/parsers/nmap_parser.py +262 -174
  176. souleyez/parsers/nuclei_parser.py +40 -44
  177. souleyez/parsers/responder_parser.py +26 -26
  178. souleyez/parsers/searchsploit_parser.py +74 -74
  179. souleyez/parsers/service_explorer_parser.py +279 -0
  180. souleyez/parsers/smbmap_parser.py +180 -124
  181. souleyez/parsers/sqlmap_parser.py +434 -308
  182. souleyez/parsers/theharvester_parser.py +75 -57
  183. souleyez/parsers/whois_parser.py +135 -94
  184. souleyez/parsers/wpscan_parser.py +278 -190
  185. souleyez/plugins/afp.py +44 -36
  186. souleyez/plugins/afp_brute.py +114 -46
  187. souleyez/plugins/ard.py +48 -37
  188. souleyez/plugins/bloodhound.py +95 -61
  189. souleyez/plugins/certipy.py +303 -0
  190. souleyez/plugins/crackmapexec.py +186 -85
  191. souleyez/plugins/dalfox.py +120 -59
  192. souleyez/plugins/dns_hijack.py +146 -41
  193. souleyez/plugins/dnsrecon.py +97 -61
  194. souleyez/plugins/enum4linux.py +91 -66
  195. souleyez/plugins/evil_winrm.py +291 -0
  196. souleyez/plugins/ffuf.py +166 -90
  197. souleyez/plugins/firmware_extract.py +133 -29
  198. souleyez/plugins/gobuster.py +387 -190
  199. souleyez/plugins/gpp_extract.py +393 -0
  200. souleyez/plugins/hashcat.py +100 -73
  201. souleyez/plugins/http_fingerprint.py +854 -267
  202. souleyez/plugins/hydra.py +566 -200
  203. souleyez/plugins/impacket_getnpusers.py +117 -69
  204. souleyez/plugins/impacket_psexec.py +84 -64
  205. souleyez/plugins/impacket_secretsdump.py +103 -69
  206. souleyez/plugins/impacket_smbclient.py +89 -75
  207. souleyez/plugins/john.py +86 -69
  208. souleyez/plugins/katana.py +313 -0
  209. souleyez/plugins/kerbrute.py +237 -0
  210. souleyez/plugins/lfi_extract.py +541 -0
  211. souleyez/plugins/macos_ssh.py +117 -48
  212. souleyez/plugins/mdns.py +35 -30
  213. souleyez/plugins/msf_auxiliary.py +253 -130
  214. souleyez/plugins/msf_exploit.py +239 -161
  215. souleyez/plugins/nikto.py +134 -78
  216. souleyez/plugins/nmap.py +275 -91
  217. souleyez/plugins/nuclei.py +180 -89
  218. souleyez/plugins/nxc.py +285 -0
  219. souleyez/plugins/plugin_base.py +35 -36
  220. souleyez/plugins/plugin_template.py +13 -5
  221. souleyez/plugins/rdp_sec_check.py +130 -0
  222. souleyez/plugins/responder.py +112 -71
  223. souleyez/plugins/router_http_brute.py +76 -65
  224. souleyez/plugins/router_ssh_brute.py +118 -41
  225. souleyez/plugins/router_telnet_brute.py +124 -42
  226. souleyez/plugins/routersploit.py +91 -59
  227. souleyez/plugins/routersploit_exploit.py +77 -55
  228. souleyez/plugins/searchsploit.py +91 -77
  229. souleyez/plugins/service_explorer.py +1160 -0
  230. souleyez/plugins/smbmap.py +122 -72
  231. souleyez/plugins/smbpasswd.py +215 -0
  232. souleyez/plugins/sqlmap.py +301 -113
  233. souleyez/plugins/theharvester.py +127 -75
  234. souleyez/plugins/tr069.py +79 -57
  235. souleyez/plugins/upnp.py +65 -47
  236. souleyez/plugins/upnp_abuse.py +73 -55
  237. souleyez/plugins/vnc_access.py +129 -42
  238. souleyez/plugins/vnc_brute.py +109 -38
  239. souleyez/plugins/whois.py +77 -58
  240. souleyez/plugins/wpscan.py +173 -69
  241. souleyez/reporting/__init__.py +2 -1
  242. souleyez/reporting/attack_chain.py +411 -346
  243. souleyez/reporting/charts.py +436 -501
  244. souleyez/reporting/compliance_mappings.py +334 -201
  245. souleyez/reporting/detection_report.py +126 -125
  246. souleyez/reporting/formatters.py +828 -591
  247. souleyez/reporting/generator.py +386 -302
  248. souleyez/reporting/metrics.py +72 -75
  249. souleyez/scanner.py +35 -29
  250. souleyez/security/__init__.py +37 -11
  251. souleyez/security/scope_validator.py +175 -106
  252. souleyez/security/validation.py +223 -149
  253. souleyez/security.py +22 -6
  254. souleyez/storage/credentials.py +247 -186
  255. souleyez/storage/crypto.py +296 -129
  256. souleyez/storage/database.py +73 -50
  257. souleyez/storage/db.py +58 -36
  258. souleyez/storage/deliverable_evidence.py +177 -128
  259. souleyez/storage/deliverable_exporter.py +282 -246
  260. souleyez/storage/deliverable_templates.py +134 -116
  261. souleyez/storage/deliverables.py +135 -130
  262. souleyez/storage/engagements.py +109 -56
  263. souleyez/storage/evidence.py +181 -152
  264. souleyez/storage/execution_log.py +31 -17
  265. souleyez/storage/exploit_attempts.py +93 -57
  266. souleyez/storage/exploits.py +67 -36
  267. souleyez/storage/findings.py +48 -61
  268. souleyez/storage/hosts.py +176 -144
  269. souleyez/storage/migrate_to_engagements.py +43 -19
  270. souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
  271. souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
  272. souleyez/storage/migrations/_003_add_execution_log.py +14 -8
  273. souleyez/storage/migrations/_005_screenshots.py +13 -5
  274. souleyez/storage/migrations/_006_deliverables.py +13 -5
  275. souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
  276. souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
  277. souleyez/storage/migrations/_010_evidence_linking.py +17 -10
  278. souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
  279. souleyez/storage/migrations/_012_team_collaboration.py +34 -21
  280. souleyez/storage/migrations/_013_add_host_tags.py +12 -6
  281. souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
  282. souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
  283. souleyez/storage/migrations/_016_add_domain_field.py +10 -4
  284. souleyez/storage/migrations/_017_msf_sessions.py +16 -8
  285. souleyez/storage/migrations/_018_add_osint_target.py +10 -6
  286. souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
  287. souleyez/storage/migrations/_020_add_rbac.py +36 -15
  288. souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
  289. souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
  290. souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
  291. souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
  292. souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
  293. souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
  294. souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
  295. souleyez/storage/migrations/__init__.py +26 -26
  296. souleyez/storage/migrations/migration_manager.py +19 -19
  297. souleyez/storage/msf_sessions.py +100 -65
  298. souleyez/storage/osint.py +17 -24
  299. souleyez/storage/recommendation_engine.py +269 -235
  300. souleyez/storage/screenshots.py +33 -32
  301. souleyez/storage/smb_shares.py +136 -92
  302. souleyez/storage/sqlmap_data.py +183 -128
  303. souleyez/storage/team_collaboration.py +135 -141
  304. souleyez/storage/timeline_tracker.py +122 -94
  305. souleyez/storage/wazuh_vulns.py +64 -66
  306. souleyez/storage/web_paths.py +33 -37
  307. souleyez/testing/credential_tester.py +221 -205
  308. souleyez/ui/__init__.py +1 -1
  309. souleyez/ui/ai_quotes.py +12 -12
  310. souleyez/ui/attack_surface.py +2439 -1516
  311. souleyez/ui/chain_rules_view.py +914 -382
  312. souleyez/ui/correlation_view.py +312 -230
  313. souleyez/ui/dashboard.py +2382 -1130
  314. souleyez/ui/deliverables_view.py +148 -62
  315. souleyez/ui/design_system.py +13 -13
  316. souleyez/ui/errors.py +49 -49
  317. souleyez/ui/evidence_linking_view.py +284 -179
  318. souleyez/ui/evidence_vault.py +393 -285
  319. souleyez/ui/exploit_suggestions_view.py +555 -349
  320. souleyez/ui/export_view.py +100 -66
  321. souleyez/ui/gap_analysis_view.py +315 -171
  322. souleyez/ui/help_system.py +105 -97
  323. souleyez/ui/intelligence_view.py +436 -293
  324. souleyez/ui/interactive.py +22783 -10678
  325. souleyez/ui/interactive_selector.py +75 -68
  326. souleyez/ui/log_formatter.py +47 -39
  327. souleyez/ui/menu_components.py +22 -13
  328. souleyez/ui/msf_auxiliary_menu.py +184 -133
  329. souleyez/ui/pending_chains_view.py +336 -172
  330. souleyez/ui/progress_indicators.py +5 -3
  331. souleyez/ui/recommendations_view.py +195 -137
  332. souleyez/ui/rule_builder.py +343 -225
  333. souleyez/ui/setup_wizard.py +678 -284
  334. souleyez/ui/shortcuts.py +217 -165
  335. souleyez/ui/splunk_gap_analysis_view.py +452 -270
  336. souleyez/ui/splunk_vulns_view.py +139 -86
  337. souleyez/ui/team_dashboard.py +498 -335
  338. souleyez/ui/template_selector.py +196 -105
  339. souleyez/ui/terminal.py +6 -6
  340. souleyez/ui/timeline_view.py +198 -127
  341. souleyez/ui/tool_setup.py +264 -164
  342. souleyez/ui/tutorial.py +202 -72
  343. souleyez/ui/tutorial_state.py +40 -40
  344. souleyez/ui/wazuh_vulns_view.py +235 -141
  345. souleyez/ui/wordlist_browser.py +260 -107
  346. souleyez/ui.py +464 -312
  347. souleyez/utils/tool_checker.py +427 -367
  348. souleyez/utils.py +33 -29
  349. souleyez/wordlists.py +134 -167
  350. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/METADATA +1 -1
  351. souleyez-2.43.32.dist-info/RECORD +441 -0
  352. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/WHEEL +1 -1
  353. souleyez-2.43.29.dist-info/RECORD +0 -379
  354. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/entry_points.txt +0 -0
  355. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/licenses/LICENSE +0 -0
  356. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/top_level.txt +0 -0
@@ -15,7 +15,7 @@ from typing import Dict, Any, List
15
15
  def parse_secretsdump(log_path: str, target: str) -> Dict[str, Any]:
16
16
  """
17
17
  Parse secretsdump output for credentials and hashes.
18
-
18
+
19
19
  Output format:
20
20
  [*] Dumping local SAM hashes
21
21
  Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
@@ -25,11 +25,13 @@ def parse_secretsdump(log_path: str, target: str) -> Dict[str, Any]:
25
25
  credentials = []
26
26
  hashes = []
27
27
  tickets = []
28
-
28
+ lsa_secrets = []
29
+ kerberos_keys = []
30
+
29
31
  try:
30
- with open(log_path, 'r', encoding='utf-8') as f:
32
+ with open(log_path, "r", encoding="utf-8") as f:
31
33
  content = f.read()
32
-
34
+
33
35
  # Parse NTLM hashes with multiple format support
34
36
  # Format 1: username:RID:LM:NT::: (standard secretsdump)
35
37
  # Format 2: username:RID:LM:NT:: (without trailing colon)
@@ -38,10 +40,11 @@ def parse_secretsdump(log_path: str, target: str) -> Dict[str, Any]:
38
40
 
39
41
  # Standard format with 32-char hashes and trailing colons
40
42
  hash_patterns = [
41
- r'([^:\s\\]+):(\d+):([0-9a-fA-F]{32}):([0-9a-fA-F]{32}):::?', # Standard
42
- r'([^:\s]+)\\([^:\s]+):(\d+):([0-9a-fA-F]{32}):([0-9a-fA-F]{32}):::?', # Domain\user
43
+ r"([^:\s\\]+):(\d+):([0-9a-fA-F]{32}):([0-9a-fA-F]{32}):::?", # Standard
44
+ r"([^:\s]+)\\([^:\s]+):(\d+):([0-9a-fA-F]{32}):([0-9a-fA-F]{32}):::?", # Domain\user
43
45
  ]
44
46
 
47
+ seen_hashes = set() # Deduplicate hashes
45
48
  for pattern in hash_patterns:
46
49
  for match in re.finditer(pattern, content):
47
50
  groups = match.groups()
@@ -54,18 +57,60 @@ def parse_secretsdump(log_path: str, target: str) -> Dict[str, Any]:
54
57
  else:
55
58
  continue
56
59
 
57
- # Skip empty hashes (blank password indicator)
58
- if nt_hash.lower() == '31d6cfe0d16ae931b73c59d7e0c089c0':
60
+ # Skip empty hashes (blank password indicator) - but keep Guest for completeness
61
+ if (
62
+ nt_hash.lower() == "31d6cfe0d16ae931b73c59d7e0c089c0"
63
+ and username.lower() != "guest"
64
+ ):
65
+ continue
66
+
67
+ # Deduplicate by username:nt_hash
68
+ hash_key = f"{username}:{nt_hash}"
69
+ if hash_key in seen_hashes:
59
70
  continue
71
+ seen_hashes.add(hash_key)
72
+
73
+ hashes.append(
74
+ {
75
+ "username": username,
76
+ "rid": rid,
77
+ "lm_hash": lm_hash,
78
+ "nt_hash": nt_hash,
79
+ "hash_type": "NTLM",
80
+ }
81
+ )
82
+
83
+ # Parse LSA secrets (DefaultPassword, etc.)
84
+ # Format: [*] DefaultPassword
85
+ # (Unknown User):ROOT#123
86
+ lsa_pattern = r"\[\*\]\s*DefaultPassword\s*\n\s*\([^)]*\):([^\n]+)"
87
+ for match in re.finditer(lsa_pattern, content):
88
+ password = match.group(1).strip()
89
+ if password and not password.startswith("(null)"):
90
+ lsa_secrets.append(
91
+ {"secret_type": "DefaultPassword", "value": password}
92
+ )
93
+ # Also add as credential
94
+ credentials.append(
95
+ {
96
+ "domain": "",
97
+ "username": "(DefaultPassword)",
98
+ "password": password,
99
+ "credential_type": "lsa_secret",
100
+ }
101
+ )
102
+
103
+ # Parse Kerberos keys (AES, DES formats)
104
+ # Format: username:aes256-cts-hmac-sha1-96:hexkey
105
+ kerb_key_pattern = (
106
+ r"([^:\s]+):(aes\d+-cts-hmac-sha1-\d+|des-cbc-md5):([0-9a-fA-F]+)"
107
+ )
108
+ for match in re.finditer(kerb_key_pattern, content):
109
+ username, key_type, key_value = match.groups()
110
+ kerberos_keys.append(
111
+ {"username": username, "key_type": key_type, "key": key_value}
112
+ )
60
113
 
61
- hashes.append({
62
- 'username': username,
63
- 'rid': rid,
64
- 'lm_hash': lm_hash,
65
- 'nt_hash': nt_hash,
66
- 'hash_type': 'NTLM'
67
- })
68
-
69
114
  # Parse plaintext passwords with multiple format support
70
115
  # Format 1: DOMAIN\username:password
71
116
  # Format 2: DOMAIN\\username:password (escaped backslash)
@@ -73,9 +118,9 @@ def parse_secretsdump(log_path: str, target: str) -> Dict[str, Any]:
73
118
  # Format 4: [*] DOMAIN\username:password (with prefix)
74
119
 
75
120
  plaintext_patterns = [
76
- r'([^\\:\s]+)[\\]+([^:\s]+):([^\n\r]+)', # DOMAIN\user:pass
77
- r'([^@:\s]+)@([^:\s]+):([^\n\r]+)', # user@DOMAIN:pass
78
- r'\[\*\]\s*([^\\:\s]+)[\\]+([^:\s]+):([^\n\r]+)', # [*] DOMAIN\user:pass
121
+ r"([^\\:\s]+)[\\]+([^:\s]+):([^\n\r]+)", # DOMAIN\user:pass
122
+ r"([^@:\s]+)@([^:\s]+):([^\n\r]+)", # user@DOMAIN:pass
123
+ r"\[\*\]\s*([^\\:\s]+)[\\]+([^:\s]+):([^\n\r]+)", # [*] DOMAIN\user:pass
79
124
  ]
80
125
 
81
126
  for pattern in plaintext_patterns:
@@ -86,78 +131,85 @@ def parse_secretsdump(log_path: str, target: str) -> Dict[str, Any]:
86
131
  password = password.strip()
87
132
 
88
133
  # Skip null/empty passwords and hash-like values
89
- if not password or password.startswith('(null)'):
134
+ if not password or password.startswith("(null)"):
90
135
  continue
91
136
  # Skip if password looks like a hash (32+ hex chars)
92
- if re.match(r'^[0-9a-fA-F]{32,}$', password):
137
+ if re.match(r"^[0-9a-fA-F]{32,}$", password):
138
+ continue
139
+ # Skip Kerberos key formats
140
+ if re.match(r"^(aes\d+|des)-", password):
93
141
  continue
94
142
 
95
143
  # Determine domain/username based on pattern
96
- if '@' in match.group(0):
144
+ if "@" in match.group(0):
97
145
  username, domain = part1, part2
98
146
  else:
99
147
  domain, username = part1, part2
100
148
 
101
- credentials.append({
102
- 'domain': domain,
103
- 'username': username,
104
- 'password': password,
105
- 'credential_type': 'plaintext'
106
- })
107
-
108
- # Parse Kerberos keys (format: username:$krb5...)
109
- krb_pattern = r'([^:\s]+):(\$krb5[^\s]+)'
149
+ credentials.append(
150
+ {
151
+ "domain": domain,
152
+ "username": username,
153
+ "password": password,
154
+ "credential_type": "plaintext",
155
+ }
156
+ )
157
+
158
+ # Parse Kerberos tickets (format: username:$krb5...)
159
+ krb_pattern = r"([^:\s]+):(\$krb5[^\s]+)"
110
160
  for match in re.finditer(krb_pattern, content):
111
161
  username, krb_key = match.groups()
112
-
113
- tickets.append({
114
- 'username': username,
115
- 'ticket': krb_key,
116
- 'ticket_type': 'Kerberos'
117
- })
118
-
162
+
163
+ tickets.append(
164
+ {"username": username, "ticket": krb_key, "ticket_type": "Kerberos"}
165
+ )
166
+
119
167
  except FileNotFoundError:
120
168
  return {
121
- 'tool': 'secretsdump',
122
- 'target': target,
123
- 'error': 'Log file not found',
124
- 'credentials_count': 0,
125
- 'hashes_count': 0
169
+ "tool": "secretsdump",
170
+ "target": target,
171
+ "error": "Log file not found",
172
+ "credentials_count": 0,
173
+ "hashes_count": 0,
126
174
  }
127
175
  except Exception as e:
128
176
  return {
129
- 'tool': 'secretsdump',
130
- 'target': target,
131
- 'error': str(e),
132
- 'credentials_count': 0,
133
- 'hashes_count': 0
177
+ "tool": "secretsdump",
178
+ "target": target,
179
+ "error": str(e),
180
+ "credentials_count": 0,
181
+ "hashes_count": 0,
134
182
  }
135
-
183
+
136
184
  return {
137
- 'tool': 'secretsdump',
138
- 'target': target,
139
- 'credentials_count': len(credentials),
140
- 'hashes_count': len(hashes),
141
- 'tickets_count': len(tickets),
142
- 'credentials': credentials,
143
- 'hashes': hashes,
144
- 'tickets': tickets
185
+ "tool": "secretsdump",
186
+ "target": target,
187
+ "credentials_count": len(credentials),
188
+ "hashes_count": len(hashes),
189
+ "tickets_count": len(tickets),
190
+ "lsa_secrets_count": len(lsa_secrets),
191
+ "kerberos_keys_count": len(kerberos_keys),
192
+ "credentials": credentials,
193
+ "hashes": hashes,
194
+ "tickets": tickets,
195
+ "lsa_secrets": lsa_secrets,
196
+ "kerberos_keys": kerberos_keys,
145
197
  }
146
198
 
147
199
 
148
200
  def parse_getnpusers(log_path: str, target: str) -> Dict[str, Any]:
149
201
  """
150
202
  Parse GetNPUsers output for AS-REP roastable hashes.
151
-
203
+
152
204
  Output format:
153
205
  $krb5asrep$23$user@DOMAIN:hash...
154
206
  """
155
207
  hashes = []
156
-
208
+
157
209
  try:
158
- with open(log_path, 'r', encoding='utf-8') as f:
210
+ with open(log_path, "r", encoding="utf-8") as f:
159
211
  content = f.read()
160
-
212
+
161
213
  # Parse AS-REP hashes with multiple format support
162
214
  # Format 1: $krb5asrep$23$user@DOMAIN:hash (etype 23)
163
215
  # Format 2: $krb5asrep$18$user@DOMAIN:hash (etype 18)
@@ -166,8 +218,8 @@ def parse_getnpusers(log_path: str, target: str) -> Dict[str, Any]:
166
218
 
167
219
  # Full format with etype: $krb5asrep$ETYPE$user@DOMAIN:hash
168
220
  hash_patterns = [
169
- r'\$krb5asrep\$(\d+)\$([^@]+)@([^:]+):([^\s]+)', # With etype
170
- r'\$krb5asrep\$([^@$]+)@([^:]+):([^\s]+)', # Without etype
221
+ r"\$krb5asrep\$(\d+)\$([^@]+)@([^:]+):([^\s]+)", # With etype
222
+ r"\$krb5asrep\$([^@$]+)@([^:]+):([^\s]+)", # Without etype
171
223
  ]
172
224
 
173
225
  for pattern in hash_patterns:
@@ -175,57 +227,61 @@ def parse_getnpusers(log_path: str, target: str) -> Dict[str, Any]:
175
227
  groups = match.groups()
176
228
  if len(groups) == 4:
177
229
  etype, username, domain, hash_value = groups
178
- full_hash = f'$krb5asrep${etype}${username}@{domain}:{hash_value}'
230
+ full_hash = f"$krb5asrep${etype}${username}@{domain}:{hash_value}"
179
231
  elif len(groups) == 3:
180
232
  username, domain, hash_value = groups
181
- etype = '23' # Default etype
182
- full_hash = f'$krb5asrep${username}@{domain}:{hash_value}'
233
+ etype = "23" # Default etype
234
+ full_hash = f"$krb5asrep${username}@{domain}:{hash_value}"
183
235
  else:
184
236
  continue
185
237
 
186
- hashes.append({
187
- 'username': username,
188
- 'domain': domain,
189
- 'hash': full_hash,
190
- 'hash_type': 'AS-REP',
191
- 'etype': etype,
192
- 'crackable': True
193
- })
238
+ hashes.append(
239
+ {
240
+ "username": username,
241
+ "domain": domain,
242
+ "hash": full_hash,
243
+ "hash_type": "AS-REP",
244
+ "etype": etype,
245
+ "crackable": True,
246
+ }
247
+ )
194
248
 
195
249
  # Also check for simple format (username:hash)
196
250
  if not hashes:
197
- simple_pattern = r'^([^:\s]+):(\$krb5asrep[^\s]+)'
251
+ simple_pattern = r"^([^:\s]+):(\$krb5asrep[^\s]+)"
198
252
  for match in re.finditer(simple_pattern, content, re.MULTILINE):
199
253
  username, hash_value = match.groups()
200
254
 
201
- hashes.append({
202
- 'username': username,
203
- 'hash': hash_value,
204
- 'hash_type': 'AS-REP',
205
- 'crackable': True
206
- })
207
-
255
+ hashes.append(
256
+ {
257
+ "username": username,
258
+ "hash": hash_value,
259
+ "hash_type": "AS-REP",
260
+ "crackable": True,
261
+ }
262
+ )
263
+
208
264
  except FileNotFoundError:
209
265
  return {
210
- 'tool': 'GetNPUsers',
211
- 'target': target,
212
- 'error': 'Log file not found',
213
- 'hashes_count': 0
266
+ "tool": "GetNPUsers",
267
+ "target": target,
268
+ "error": "Log file not found",
269
+ "hashes_count": 0,
214
270
  }
215
271
  except Exception as e:
216
272
  return {
217
- 'tool': 'GetNPUsers',
218
- 'target': target,
219
- 'error': str(e),
220
- 'hashes_count': 0
273
+ "tool": "GetNPUsers",
274
+ "target": target,
275
+ "error": str(e),
276
+ "hashes_count": 0,
221
277
  }
222
-
278
+
223
279
  return {
224
- 'tool': 'GetNPUsers',
225
- 'target': target,
226
- 'hashes_count': len(hashes),
227
- 'hashes': hashes,
228
- 'asrep_hashes': hashes # For auto-chaining to hashcat
280
+ "tool": "GetNPUsers",
281
+ "target": target,
282
+ "hashes_count": len(hashes),
283
+ "hashes": hashes,
284
+ "asrep_hashes": hashes, # For auto-chaining to hashcat
229
285
  }
230
286
 
231
287
 
@@ -235,52 +291,49 @@ def parse_psexec(log_path: str, target: str) -> Dict[str, Any]:
235
291
  """
236
292
  output_lines = []
237
293
  success = False
238
-
294
+
239
295
  try:
240
- with open(log_path, 'r', encoding='utf-8') as f:
296
+ with open(log_path, "r", encoding="utf-8") as f:
241
297
  content = f.read()
242
-
298
+
243
299
  # Check for successful connection with multiple indicators
244
- success_indicators = [
245
- '[*] Requesting shares on',
246
- 'C:\\Windows\\system32>',
247
- 'C:\\WINDOWS\\system32>',
248
- '[*] Uploading',
249
- '[*] Opening SVCManager',
250
- 'Microsoft Windows', # Version banner
251
- '[*] Starting service',
252
- 'Process .+ created', # Process creation message
300
+ # Use simple string matching for literal strings, regex for patterns
301
+ literal_indicators = [
302
+ "[*] Requesting shares on",
303
+ "[*] Uploading",
304
+ "[*] Opening SVCManager",
305
+ "[*] Starting service",
306
+ "C:\\Windows\\system32>",
307
+ "C:\\WINDOWS\\system32>",
308
+ "Microsoft Windows",
309
+ "nt authority\\system",
310
+ "ErrorCode: 0",
253
311
  ]
254
312
 
255
- for indicator in success_indicators:
256
- if re.search(indicator, content, re.IGNORECASE):
313
+ for indicator in literal_indicators:
314
+ if indicator.lower() in content.lower():
257
315
  success = True
258
316
  break
259
-
317
+
260
318
  # Extract command output (everything after the prompt)
261
- output_lines = [line for line in content.split('\n') if line.strip()]
262
-
319
+ output_lines = [line for line in content.split("\n") if line.strip()]
320
+
263
321
  except FileNotFoundError:
264
322
  return {
265
- 'tool': 'psexec',
266
- 'target': target,
267
- 'error': 'Log file not found',
268
- 'success': False
323
+ "tool": "psexec",
324
+ "target": target,
325
+ "error": "Log file not found",
326
+ "success": False,
269
327
  }
270
328
  except Exception as e:
271
- return {
272
- 'tool': 'psexec',
273
- 'target': target,
274
- 'error': str(e),
275
- 'success': False
276
- }
277
-
329
+ return {"tool": "psexec", "target": target, "error": str(e), "success": False}
330
+
278
331
  return {
279
- 'tool': 'psexec',
280
- 'target': target,
281
- 'success': success,
282
- 'output_lines': len(output_lines),
283
- 'output': '\n'.join(output_lines)
332
+ "tool": "psexec",
333
+ "target": target,
334
+ "success": success,
335
+ "output_lines": len(output_lines),
336
+ "output": "\n".join(output_lines),
284
337
  }
285
338
 
286
339
 
@@ -291,89 +344,89 @@ def parse_smbclient(log_path: str, target: str) -> Dict[str, Any]:
291
344
  shares = []
292
345
  files = []
293
346
  success = False
294
-
347
+
295
348
  try:
296
- with open(log_path, 'r', encoding='utf-8') as f:
349
+ with open(log_path, "r", encoding="utf-8") as f:
297
350
  content = f.read()
298
-
351
+
299
352
  # Check for successful connection
300
- if 'Type Client' in content or 'smb:' in content:
353
+ if "Type Client" in content or "smb:" in content:
301
354
  success = True
302
-
355
+
303
356
  # Parse share listings
304
- share_pattern = r'^\s*([A-Z$]+)\s+(Disk|Printer|Device|IPC)\s*(.*)$'
357
+ share_pattern = r"^\s*([A-Z$]+)\s+(Disk|Printer|Device|IPC)\s*(.*)$"
305
358
  for match in re.finditer(share_pattern, content, re.MULTILINE):
306
359
  share_name, share_type, comment = match.groups()
307
-
308
- shares.append({
309
- 'name': share_name.strip(),
310
- 'type': share_type.strip(),
311
- 'comment': comment.strip()
312
- })
313
-
360
+
361
+ shares.append(
362
+ {
363
+ "name": share_name.strip(),
364
+ "type": share_type.strip(),
365
+ "comment": comment.strip(),
366
+ }
367
+ )
368
+
314
369
  # Parse file listings (basic)
315
- file_pattern = r'^\s*([^\s]+)\s+([DAH]+)\s+(\d+)\s+'
370
+ file_pattern = r"^\s*([^\s]+)\s+([DAH]+)\s+(\d+)\s+"
316
371
  for match in re.finditer(file_pattern, content, re.MULTILINE):
317
372
  filename, attributes, size = match.groups()
318
-
319
- if filename not in ['.', '..']:
320
- files.append({
321
- 'name': filename,
322
- 'attributes': attributes,
323
- 'size': int(size)
324
- })
325
-
373
+
374
+ if filename not in [".", ".."]:
375
+ files.append(
376
+ {"name": filename, "attributes": attributes, "size": int(size)}
377
+ )
378
+
326
379
  except FileNotFoundError:
327
380
  return {
328
- 'tool': 'smbclient',
329
- 'target': target,
330
- 'error': 'Log file not found',
331
- 'success': False
381
+ "tool": "smbclient",
382
+ "target": target,
383
+ "error": "Log file not found",
384
+ "success": False,
332
385
  }
333
386
  except Exception as e:
334
387
  return {
335
- 'tool': 'smbclient',
336
- 'target': target,
337
- 'error': str(e),
338
- 'success': False
388
+ "tool": "smbclient",
389
+ "target": target,
390
+ "error": str(e),
391
+ "success": False,
339
392
  }
340
-
393
+
341
394
  return {
342
- 'tool': 'smbclient',
343
- 'target': target,
344
- 'success': success,
345
- 'shares_count': len(shares),
346
- 'files_count': len(files),
347
- 'shares': shares,
348
- 'files': files
395
+ "tool": "smbclient",
396
+ "target": target,
397
+ "success": success,
398
+ "shares_count": len(shares),
399
+ "files_count": len(files),
400
+ "shares": shares,
401
+ "files": files,
349
402
  }
350
403
 
351
404
 
352
405
  def parse_impacket(log_path: str, target: str, tool: str) -> Dict[str, Any]:
353
406
  """
354
407
  Unified parser that routes to specific Impacket tool parsers.
355
-
408
+
356
409
  Args:
357
410
  log_path: Path to tool output file
358
411
  target: Target host/domain
359
412
  tool: Specific Impacket tool name
360
-
413
+
361
414
  Returns:
362
415
  Parsed results dictionary
363
416
  """
364
- tool_lower = tool.lower().replace('impacket-', '')
365
-
366
- if 'secretsdump' in tool_lower:
417
+ tool_lower = tool.lower().replace("impacket-", "")
418
+
419
+ if "secretsdump" in tool_lower:
367
420
  return parse_secretsdump(log_path, target)
368
- elif 'getnpusers' in tool_lower:
421
+ elif "getnpusers" in tool_lower:
369
422
  return parse_getnpusers(log_path, target)
370
- elif 'psexec' in tool_lower:
423
+ elif "psexec" in tool_lower:
371
424
  return parse_psexec(log_path, target)
372
- elif 'smbclient' in tool_lower:
425
+ elif "smbclient" in tool_lower:
373
426
  return parse_smbclient(log_path, target)
374
427
  else:
375
428
  return {
376
- 'tool': tool,
377
- 'target': target,
378
- 'error': f'Unknown Impacket tool: {tool}'
429
+ "tool": tool,
430
+ "target": target,
431
+ "error": f"Unknown Impacket tool: {tool}",
379
432
  }