souleyez 2.43.28__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 +23142 -10430
  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.28.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.28.dist-info → souleyez-2.43.32.dist-info}/WHEEL +1 -1
  353. souleyez-2.43.28.dist-info/RECORD +0 -379
  354. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/entry_points.txt +0 -0
  355. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/licenses/LICENSE +0 -0
  356. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/top_level.txt +0 -0
@@ -12,208 +12,220 @@ from typing import Dict, List, Tuple
12
12
  def parse_john_output(output: str, hash_file: str = None) -> Dict:
13
13
  """
14
14
  Parse John the Ripper output and extract cracked passwords.
15
-
15
+
16
16
  Args:
17
17
  output: John's stdout/stderr output
18
18
  hash_file: Path to the hash file (to run --show if needed)
19
-
19
+
20
20
  Returns:
21
21
  Dictionary with cracked credentials
22
22
  """
23
23
  results = {
24
- 'cracked': [],
25
- 'total_loaded': 0,
26
- 'total_cracked': 0,
27
- 'session_status': 'unknown'
24
+ "cracked": [],
25
+ "total_loaded": 0,
26
+ "total_cracked": 0,
27
+ "session_status": "unknown",
28
28
  }
29
-
29
+
30
30
  # Parse loaded hashes
31
- loaded_match = re.search(r'Loaded (\d+) password hash', output)
31
+ loaded_match = re.search(r"Loaded (\d+) password hash", output)
32
32
  if loaded_match:
33
- results['total_loaded'] = int(loaded_match.group(1))
34
-
33
+ results["total_loaded"] = int(loaded_match.group(1))
34
+
35
35
  # Parse cracked passwords from live output with multiple format support
36
36
  # Format 1: "password (username)"
37
37
  # Format 2: "password (username)"
38
38
  # Format 3: "username:password"
39
39
  # Format 4: "password (username) [hash_type]"
40
- for line in output.split('\n'):
40
+ for line in output.split("\n"):
41
41
  line = line.strip()
42
- if not line or line.startswith('#') or line.startswith('['):
42
+ if not line or line.startswith("#") or line.startswith("["):
43
43
  continue
44
44
 
45
45
  # Try format: password (username) with optional hash type
46
- match = re.match(r'^(\S+)\s+\(([^)]+)\)(?:\s+\[.+\])?\s*$', line)
46
+ match = re.match(r"^(\S+)\s+\(([^)]+)\)(?:\s+\[.+\])?\s*$", line)
47
47
  if match:
48
48
  password = match.group(1)
49
49
  username = match.group(2)
50
- results['cracked'].append({
51
- 'username': username,
52
- 'password': password,
53
- 'source': 'john_live'
54
- })
50
+ results["cracked"].append(
51
+ {"username": username, "password": password, "source": "john_live"}
52
+ )
55
53
  continue
56
54
 
57
55
  # Try format: username:password (from --show output)
58
- if ':' in line and not line.startswith('Loaded'):
59
- parts = line.split(':')
56
+ if ":" in line and not line.startswith("Loaded"):
57
+ parts = line.split(":")
60
58
  if len(parts) >= 2 and len(parts[0]) > 0 and len(parts[-1]) > 0:
61
59
  # Skip if it looks like a hash (32+ hex chars)
62
- if not re.match(r'^[0-9a-fA-F]{32,}$', parts[-1]):
60
+ if not re.match(r"^[0-9a-fA-F]{32,}$", parts[-1]):
63
61
  username = parts[0]
64
62
  password = parts[-1]
65
- results['cracked'].append({
66
- 'username': username,
67
- 'password': password,
68
- 'source': 'john_live'
69
- })
63
+ results["cracked"].append(
64
+ {
65
+ "username": username,
66
+ "password": password,
67
+ "source": "john_live",
68
+ }
69
+ )
70
70
 
71
71
  # Check session status with multiple format support
72
- if any(x in output for x in ['Session completed', 'session completed', 'Proceeding with next']):
73
- results['session_status'] = 'completed'
74
- elif any(x in output for x in ['Session aborted', 'session aborted', 'Interrupted']):
75
- results['session_status'] = 'aborted'
76
- elif 'No password hashes left to crack' in output:
77
- results['session_status'] = 'completed'
72
+ if any(
73
+ x in output
74
+ for x in ["Session completed", "session completed", "Proceeding with next"]
75
+ ):
76
+ results["session_status"] = "completed"
77
+ elif any(
78
+ x in output for x in ["Session aborted", "session aborted", "Interrupted"]
79
+ ):
80
+ results["session_status"] = "aborted"
81
+ elif "No password hashes left to crack" in output:
82
+ results["session_status"] = "completed"
78
83
 
79
84
  # Parse summary line with multiple formats
80
85
  # Format 1: "2g 0:00:00:01 DONE..."
81
86
  # Format 2: "2g 0:00:00:01 100% DONE..."
82
87
  # Format 3: "Session completed, 2g"
83
88
  summary_patterns = [
84
- r'(\d+)g\s+[\d:]+\s+(?:\d+%\s+)?(DONE|Session)',
85
- r'Session completed[,\s]+(\d+)g',
86
- r'(\d+)\s+password hashes? cracked',
89
+ r"(\d+)g\s+[\d:]+\s+(?:\d+%\s+)?(DONE|Session)",
90
+ r"Session completed[,\s]+(\d+)g",
91
+ r"(\d+)\s+password hashes? cracked",
87
92
  ]
88
93
  for pattern in summary_patterns:
89
94
  summary_match = re.search(pattern, output, re.IGNORECASE)
90
95
  if summary_match:
91
- results['total_cracked'] = int(summary_match.group(1))
96
+ results["total_cracked"] = int(summary_match.group(1))
92
97
  break
93
-
98
+
94
99
  # If hash_file provided, also parse john.pot or run --show
95
100
  if hash_file and os.path.isfile(hash_file):
96
101
  pot_results = parse_john_pot(hash_file)
97
102
  # Merge with live results (pot is authoritative)
98
103
  if pot_results:
99
- results['cracked'].extend(pot_results)
104
+ results["cracked"].extend(pot_results)
100
105
  # Deduplicate by username
101
106
  seen = set()
102
107
  unique_creds = []
103
- for cred in results['cracked']:
104
- if cred['username'] not in seen:
105
- seen.add(cred['username'])
108
+ for cred in results["cracked"]:
109
+ if cred["username"] not in seen:
110
+ seen.add(cred["username"])
106
111
  unique_creds.append(cred)
107
- results['cracked'] = unique_creds
108
- results['total_cracked'] = len(unique_creds)
109
-
112
+ results["cracked"] = unique_creds
113
+ results["total_cracked"] = len(unique_creds)
114
+
110
115
  return results
111
116
 
112
117
 
113
118
  def parse_john_pot(hash_file: str = None) -> List[Dict]:
114
119
  """
115
120
  Parse John's potfile for cracked passwords.
116
-
121
+
117
122
  Args:
118
123
  hash_file: If provided, run 'john --show hashfile' to get results
119
-
124
+
120
125
  Returns:
121
126
  List of cracked credentials
122
127
  """
123
128
  cracked = []
124
-
129
+
125
130
  # Try running john --show on the hash file
126
131
  if hash_file and os.path.isfile(hash_file):
127
132
  try:
128
133
  import subprocess
134
+
129
135
  result = subprocess.run(
130
- ['john', '--show', hash_file],
136
+ ["john", "--show", hash_file],
131
137
  capture_output=True,
132
138
  text=True,
133
- timeout=10
139
+ timeout=10,
134
140
  )
135
-
141
+
136
142
  # Parse --show output
137
143
  # Format: "username:password" or "username:hash:password"
138
- for line in result.stdout.split('\n'):
144
+ for line in result.stdout.split("\n"):
139
145
  line = line.strip()
140
- if ':' in line and not line.startswith('#'):
141
- parts = line.split(':')
146
+ if ":" in line and not line.startswith("#"):
147
+ parts = line.split(":")
142
148
  if len(parts) >= 2:
143
149
  username = parts[0]
144
150
  # Password is the last part
145
151
  password = parts[-1]
146
152
  if username and password:
147
- cracked.append({
148
- 'username': username,
149
- 'password': password,
150
- 'source': 'john_pot'
151
- })
153
+ cracked.append(
154
+ {
155
+ "username": username,
156
+ "password": password,
157
+ "source": "john_pot",
158
+ }
159
+ )
152
160
  except Exception:
153
161
  pass
154
-
162
+
155
163
  # Also try reading ~/.john/john.pot directly
156
- pot_file = os.path.expanduser('~/.john/john.pot')
164
+ pot_file = os.path.expanduser("~/.john/john.pot")
157
165
  if os.path.isfile(pot_file):
158
166
  try:
159
- with open(pot_file, 'r') as f:
167
+ with open(pot_file, "r") as f:
160
168
  for line in f:
161
169
  line = line.strip()
162
- if ':' in line:
170
+ if ":" in line:
163
171
  # Potfile format: hash:password
164
- parts = line.split(':')
172
+ parts = line.split(":")
165
173
  if len(parts) >= 2:
166
174
  # Extract password (last part)
167
175
  password = parts[-1]
168
176
  # Try to find username from hash if available
169
177
  # This is basic - john.pot doesn't always have username
170
- cracked.append({
171
- 'username': 'unknown',
172
- 'password': password,
173
- 'hash': parts[0],
174
- 'source': 'john_pot_file'
175
- })
178
+ cracked.append(
179
+ {
180
+ "username": "unknown",
181
+ "password": password,
182
+ "hash": parts[0],
183
+ "source": "john_pot_file",
184
+ }
185
+ )
176
186
  except Exception:
177
187
  pass
178
-
188
+
179
189
  return cracked
180
190
 
181
191
 
182
- def extract_credentials_to_db(output: str, hash_file: str = None, engagement_id: int = None):
192
+ def extract_credentials_to_db(
193
+ output: str, hash_file: str = None, engagement_id: int = None
194
+ ):
183
195
  """
184
196
  Extract cracked credentials and store them in the database.
185
-
197
+
186
198
  Args:
187
199
  output: John's output
188
200
  hash_file: Path to hash file
189
201
  engagement_id: Current engagement ID
190
202
  """
191
203
  from souleyez.storage.credentials import CredentialManager
192
-
204
+
193
205
  results = parse_john_output(output, hash_file)
194
-
195
- if not results['cracked']:
206
+
207
+ if not results["cracked"]:
196
208
  return 0
197
-
209
+
198
210
  cred_mgr = CredentialManager()
199
211
  added = 0
200
-
201
- for cred in results['cracked']:
202
- username = cred.get('username')
203
- password = cred.get('password')
204
-
205
- if username and password and username != 'unknown':
212
+
213
+ for cred in results["cracked"]:
214
+ username = cred.get("username")
215
+ password = cred.get("password")
216
+
217
+ if username and password and username != "unknown":
206
218
  try:
207
219
  # Add to credentials database
208
220
  cred_mgr.add_credential(
209
221
  username=username,
210
222
  password=password,
211
- service='cracked', # Mark as cracked hash
212
- host='', # No specific host
213
- engagement_id=engagement_id
223
+ service="cracked", # Mark as cracked hash
224
+ host="", # No specific host
225
+ engagement_id=engagement_id,
214
226
  )
215
227
  added += 1
216
228
  except Exception:
217
229
  pass # Credential might already exist
218
-
230
+
219
231
  return added
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ souleyez.parsers.katana_parser - Parse Katana JSONL output
4
+
5
+ Katana is a web crawler from ProjectDiscovery that discovers endpoints,
6
+ parameters, and JavaScript-rendered routes.
7
+ """
8
+ import json
9
+ from typing import Dict, Any, List, Set
10
+ from urllib.parse import urlparse, parse_qs
11
+
12
+ # LFI-suspicious parameter names - these typically include files, not query databases
13
+ LFI_PARAM_NAMES = {
14
+ # Direct file inclusion params
15
+ "page",
16
+ "file",
17
+ "include",
18
+ "inc",
19
+ "path",
20
+ "filepath",
21
+ "filename",
22
+ "template",
23
+ "tmpl",
24
+ "tpl",
25
+ "view",
26
+ "layout",
27
+ "content",
28
+ # Document/resource params
29
+ "doc",
30
+ "document",
31
+ "pdf",
32
+ "folder",
33
+ "root",
34
+ "directory",
35
+ "dir",
36
+ # Language/locale (often load language files)
37
+ "lang",
38
+ "language",
39
+ "locale",
40
+ "loc",
41
+ # Style/theme (often load CSS/template files)
42
+ "style",
43
+ "stylesheet",
44
+ "css",
45
+ "theme",
46
+ "skin",
47
+ # Config/module loading
48
+ "config",
49
+ "conf",
50
+ "cfg",
51
+ "module",
52
+ "mod",
53
+ "plugin",
54
+ # Read/load operations
55
+ "read",
56
+ "load",
57
+ "fetch",
58
+ "get",
59
+ "show",
60
+ "display",
61
+ "render",
62
+ # PHP-specific
63
+ "pg",
64
+ "p",
65
+ "cont",
66
+ "controller",
67
+ "action",
68
+ "act",
69
+ # Common variations
70
+ "pagename",
71
+ "page_name",
72
+ "pageid",
73
+ "site",
74
+ "section",
75
+ }
76
+
77
+
78
+ def parse_katana_output(log_path: str) -> Dict[str, Any]:
79
+ """
80
+ Parse Katana JSONL output (one JSON object per line).
81
+
82
+ Args:
83
+ log_path: Path to katana output file
84
+
85
+ Returns:
86
+ Dict containing:
87
+ - urls: List of all discovered URLs
88
+ - urls_with_params: List of URLs containing query parameters
89
+ - lfi_candidate_urls: URLs with LFI-suspicious params (page, file, include, etc.)
90
+ - sqli_candidate_urls: URLs with non-LFI params (id, q, search, etc.)
91
+ - forms_found: List of POST endpoint URLs
92
+ - js_endpoints: List of JavaScript-discovered endpoints
93
+ - unique_parameters: Set of unique parameter names found
94
+ - lfi_params_found: Set of LFI parameter names found
95
+ - methods: Dict of method counts (GET, POST, etc.)
96
+ """
97
+ urls: List[str] = []
98
+ urls_with_params: List[str] = []
99
+ lfi_candidate_urls: List[str] = [] # URLs with LFI-suspicious params only
100
+ sqli_candidate_urls: List[str] = [] # URLs with non-LFI params
101
+ forms_found: List[str] = []
102
+ js_endpoints: List[str] = []
103
+ unique_parameters: Set[str] = set()
104
+ lfi_params_found: Set[str] = set() # Track which LFI params we found
105
+ methods: Dict[str, int] = {"GET": 0, "POST": 0, "PUT": 0, "DELETE": 0, "OTHER": 0}
106
+ status_codes: Dict[int, int] = {}
107
+ sources: Dict[str, int] = {}
108
+
109
+ try:
110
+ with open(log_path, "r", encoding="utf-8") as f:
111
+ for line in f:
112
+ # Skip comment lines and metadata
113
+ if line.startswith("#") or line.startswith("==="):
114
+ continue
115
+
116
+ line = line.strip()
117
+ if not line:
118
+ continue
119
+
120
+ try:
121
+ result = json.loads(line)
122
+
123
+ # Katana output format can vary by version
124
+ # Try multiple field locations
125
+ url = None
126
+ method = "GET"
127
+ status_code = None
128
+ source = None
129
+
130
+ # Format 1: request.endpoint structure
131
+ if "request" in result:
132
+ req = result["request"]
133
+ url = req.get("endpoint") or req.get("url")
134
+ method = req.get("method", "GET").upper()
135
+ if "response" in result:
136
+ status_code = result["response"].get("status_code")
137
+
138
+ # Format 2: Direct fields
139
+ if not url:
140
+ url = result.get("endpoint") or result.get("url")
141
+ method = result.get("method", "GET").upper()
142
+ status_code = result.get("status_code") or result.get("status")
143
+
144
+ # Get source (how endpoint was discovered)
145
+ source = result.get("source") or result.get("tag") or "unknown"
146
+
147
+ if not url:
148
+ continue
149
+
150
+ # Track all URLs
151
+ if url not in urls:
152
+ urls.append(url)
153
+
154
+ # Track methods
155
+ if method in methods:
156
+ methods[method] += 1
157
+ else:
158
+ methods["OTHER"] += 1
159
+
160
+ # Track status codes
161
+ if status_code:
162
+ status_codes[status_code] = status_codes.get(status_code, 0) + 1
163
+
164
+ # Track sources
165
+ sources[source] = sources.get(source, 0) + 1
166
+
167
+ # Check for query parameters
168
+ parsed = urlparse(url)
169
+ if parsed.query:
170
+ if url not in urls_with_params:
171
+ urls_with_params.append(url)
172
+
173
+ # Extract parameter names and categorize
174
+ # Use keep_blank_values=True to detect params like ?q= (empty value)
175
+ params = parse_qs(parsed.query, keep_blank_values=True)
176
+ param_names = set(params.keys())
177
+ unique_parameters.update(param_names)
178
+
179
+ # Check if params are LFI-suspicious
180
+ lfi_params_in_url = param_names & LFI_PARAM_NAMES
181
+ non_lfi_params = param_names - LFI_PARAM_NAMES
182
+
183
+ if lfi_params_in_url:
184
+ lfi_params_found.update(lfi_params_in_url)
185
+
186
+ # Categorize URL based on params
187
+ if lfi_params_in_url and not non_lfi_params:
188
+ # ALL params are LFI-suspicious → LFI candidate only
189
+ if url not in lfi_candidate_urls:
190
+ lfi_candidate_urls.append(url)
191
+ elif non_lfi_params:
192
+ # Has non-LFI params → SQLi candidate
193
+ if url not in sqli_candidate_urls:
194
+ sqli_candidate_urls.append(url)
195
+ # Also add to LFI if it has LFI params (mixed)
196
+ if lfi_params_in_url and url not in lfi_candidate_urls:
197
+ lfi_candidate_urls.append(url)
198
+
199
+ # Track POST endpoints as forms
200
+ if method == "POST":
201
+ if url not in forms_found:
202
+ forms_found.append(url)
203
+
204
+ # Track JavaScript-discovered endpoints
205
+ if source in ("js", "script", "javascript", "jscrawl"):
206
+ if url not in js_endpoints:
207
+ js_endpoints.append(url)
208
+
209
+ except json.JSONDecodeError:
210
+ # Skip non-JSON lines (like metadata headers)
211
+ continue
212
+
213
+ except FileNotFoundError:
214
+ return {
215
+ "urls": [],
216
+ "urls_with_params": [],
217
+ "lfi_candidate_urls": [],
218
+ "sqli_candidate_urls": [],
219
+ "forms_found": [],
220
+ "js_endpoints": [],
221
+ "unique_parameters": [],
222
+ "lfi_params_found": [],
223
+ "methods": methods,
224
+ "status_codes": {},
225
+ "sources": {},
226
+ "error": f"Log file not found: {log_path}",
227
+ }
228
+ except Exception as e:
229
+ return {
230
+ "urls": [],
231
+ "urls_with_params": [],
232
+ "lfi_candidate_urls": [],
233
+ "sqli_candidate_urls": [],
234
+ "forms_found": [],
235
+ "js_endpoints": [],
236
+ "unique_parameters": [],
237
+ "lfi_params_found": [],
238
+ "methods": methods,
239
+ "status_codes": {},
240
+ "sources": {},
241
+ "error": str(e),
242
+ }
243
+
244
+ return {
245
+ "urls": urls,
246
+ "urls_with_params": urls_with_params,
247
+ "lfi_candidate_urls": lfi_candidate_urls,
248
+ "sqli_candidate_urls": sqli_candidate_urls,
249
+ "forms_found": forms_found,
250
+ "js_endpoints": js_endpoints,
251
+ "unique_parameters": sorted(list(unique_parameters)),
252
+ "lfi_params_found": sorted(list(lfi_params_found)),
253
+ "methods": methods,
254
+ "status_codes": status_codes,
255
+ "sources": sources,
256
+ }
257
+
258
+
259
+ def extract_injectable_urls(parsed_data: Dict[str, Any]) -> List[str]:
260
+ """
261
+ Extract URLs that are good candidates for SQL injection testing.
262
+
263
+ Only returns URLs with non-LFI parameters. URLs with only LFI-suspicious
264
+ params (page, file, include, etc.) are excluded since SQLMap won't find
265
+ LFI vulnerabilities.
266
+
267
+ Prioritizes:
268
+ 1. URLs with non-LFI query parameters (sqli_candidate_urls)
269
+ 2. POST form endpoints
270
+ 3. JavaScript-discovered API endpoints
271
+
272
+ Args:
273
+ parsed_data: Output from parse_katana_output()
274
+
275
+ Returns:
276
+ List of URLs suitable for SQLMap/SQL injection testing
277
+ """
278
+ injectable = []
279
+
280
+ # SQLi candidate URLs (have non-LFI params)
281
+ for url in parsed_data.get("sqli_candidate_urls", []):
282
+ if url not in injectable:
283
+ injectable.append(url)
284
+
285
+ # POST forms are also injectable, but skip LFI-only forms
286
+ lfi_candidates = parsed_data.get("lfi_candidate_urls", [])
287
+ sqli_candidates = parsed_data.get("sqli_candidate_urls", [])
288
+ for url in parsed_data.get("forms_found", []):
289
+ if url not in injectable:
290
+ # Skip forms that only have LFI params (no SQLi potential)
291
+ if url in lfi_candidates and url not in sqli_candidates:
292
+ continue
293
+ injectable.append(url)
294
+
295
+ # JS endpoints might have hidden params
296
+ for url in parsed_data.get("js_endpoints", []):
297
+ if url not in injectable:
298
+ injectable.append(url)
299
+
300
+ return injectable
301
+
302
+
303
+ def extract_lfi_urls(parsed_data: Dict[str, Any]) -> List[str]:
304
+ """
305
+ Extract URLs that are good candidates for LFI (Local File Inclusion) testing.
306
+
307
+ Returns URLs with LFI-suspicious parameters like page, file, include, path,
308
+ template, etc. These should be tested with LFI payloads, not SQLMap.
309
+
310
+ Args:
311
+ parsed_data: Output from parse_katana_output()
312
+
313
+ Returns:
314
+ List of URLs suitable for LFI testing
315
+ """
316
+ return parsed_data.get("lfi_candidate_urls", [])