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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. souleyez/__init__.py +1 -2
  2. souleyez/ai/__init__.py +21 -15
  3. souleyez/ai/action_mapper.py +249 -150
  4. souleyez/ai/chain_advisor.py +116 -100
  5. souleyez/ai/claude_provider.py +29 -28
  6. souleyez/ai/context_builder.py +80 -62
  7. souleyez/ai/executor.py +158 -117
  8. souleyez/ai/feedback_handler.py +136 -121
  9. souleyez/ai/llm_factory.py +27 -20
  10. souleyez/ai/llm_provider.py +4 -2
  11. souleyez/ai/ollama_provider.py +6 -9
  12. souleyez/ai/ollama_service.py +44 -37
  13. souleyez/ai/path_scorer.py +91 -76
  14. souleyez/ai/recommender.py +176 -144
  15. souleyez/ai/report_context.py +74 -73
  16. souleyez/ai/report_service.py +84 -66
  17. souleyez/ai/result_parser.py +222 -229
  18. souleyez/ai/safety.py +67 -44
  19. souleyez/auth/__init__.py +23 -22
  20. souleyez/auth/audit.py +36 -26
  21. souleyez/auth/engagement_access.py +65 -48
  22. souleyez/auth/permissions.py +14 -3
  23. souleyez/auth/session_manager.py +54 -37
  24. souleyez/auth/user_manager.py +109 -64
  25. souleyez/commands/audit.py +40 -43
  26. souleyez/commands/auth.py +35 -15
  27. souleyez/commands/deliverables.py +55 -50
  28. souleyez/commands/engagement.py +47 -28
  29. souleyez/commands/license.py +32 -23
  30. souleyez/commands/screenshots.py +36 -32
  31. souleyez/commands/user.py +82 -36
  32. souleyez/config.py +52 -44
  33. souleyez/core/credential_tester.py +87 -81
  34. souleyez/core/cve_mappings.py +179 -192
  35. souleyez/core/cve_matcher.py +162 -148
  36. souleyez/core/msf_auto_mapper.py +100 -83
  37. souleyez/core/msf_chain_engine.py +294 -256
  38. souleyez/core/msf_database.py +153 -70
  39. souleyez/core/msf_integration.py +679 -673
  40. souleyez/core/msf_rpc_client.py +40 -42
  41. souleyez/core/msf_rpc_manager.py +77 -79
  42. souleyez/core/msf_sync_manager.py +241 -181
  43. souleyez/core/network_utils.py +22 -15
  44. souleyez/core/parser_handler.py +34 -25
  45. souleyez/core/pending_chains.py +114 -63
  46. souleyez/core/templates.py +158 -107
  47. souleyez/core/tool_chaining.py +9526 -2879
  48. souleyez/core/version_utils.py +79 -94
  49. souleyez/core/vuln_correlation.py +136 -89
  50. souleyez/core/web_utils.py +33 -32
  51. souleyez/data/wordlists/ad_users.txt +378 -0
  52. souleyez/data/wordlists/api_endpoints_large.txt +769 -0
  53. souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
  54. souleyez/data/wordlists/lfi_payloads.txt +82 -0
  55. souleyez/data/wordlists/passwords_brute.txt +1548 -0
  56. souleyez/data/wordlists/passwords_crack.txt +2479 -0
  57. souleyez/data/wordlists/passwords_spray.txt +386 -0
  58. souleyez/data/wordlists/subdomains_large.txt +5057 -0
  59. souleyez/data/wordlists/usernames_common.txt +694 -0
  60. souleyez/data/wordlists/web_dirs_large.txt +4769 -0
  61. souleyez/detection/__init__.py +1 -1
  62. souleyez/detection/attack_signatures.py +12 -17
  63. souleyez/detection/mitre_mappings.py +61 -55
  64. souleyez/detection/validator.py +97 -86
  65. souleyez/devtools.py +23 -10
  66. souleyez/docs/README.md +4 -4
  67. souleyez/docs/api-reference/cli-commands.md +2 -2
  68. souleyez/docs/developer-guide/adding-new-tools.md +562 -0
  69. souleyez/docs/user-guide/auto-chaining.md +30 -8
  70. souleyez/docs/user-guide/getting-started.md +1 -1
  71. souleyez/docs/user-guide/installation.md +26 -3
  72. souleyez/docs/user-guide/metasploit-integration.md +2 -2
  73. souleyez/docs/user-guide/rbac.md +1 -1
  74. souleyez/docs/user-guide/scope-management.md +1 -1
  75. souleyez/docs/user-guide/siem-integration.md +1 -1
  76. souleyez/docs/user-guide/tools-reference.md +1 -8
  77. souleyez/docs/user-guide/worker-management.md +1 -1
  78. souleyez/engine/background.py +1239 -535
  79. souleyez/engine/base.py +4 -1
  80. souleyez/engine/job_status.py +17 -49
  81. souleyez/engine/log_sanitizer.py +103 -77
  82. souleyez/engine/manager.py +38 -7
  83. souleyez/engine/result_handler.py +2200 -1550
  84. souleyez/engine/worker_manager.py +50 -41
  85. souleyez/export/evidence_bundle.py +72 -62
  86. souleyez/feature_flags/features.py +16 -20
  87. souleyez/feature_flags.py +5 -9
  88. souleyez/handlers/__init__.py +11 -0
  89. souleyez/handlers/base.py +188 -0
  90. souleyez/handlers/bash_handler.py +277 -0
  91. souleyez/handlers/bloodhound_handler.py +243 -0
  92. souleyez/handlers/certipy_handler.py +311 -0
  93. souleyez/handlers/crackmapexec_handler.py +486 -0
  94. souleyez/handlers/dnsrecon_handler.py +344 -0
  95. souleyez/handlers/enum4linux_handler.py +400 -0
  96. souleyez/handlers/evil_winrm_handler.py +493 -0
  97. souleyez/handlers/ffuf_handler.py +815 -0
  98. souleyez/handlers/gobuster_handler.py +1114 -0
  99. souleyez/handlers/gpp_extract_handler.py +334 -0
  100. souleyez/handlers/hashcat_handler.py +444 -0
  101. souleyez/handlers/hydra_handler.py +563 -0
  102. souleyez/handlers/impacket_getuserspns_handler.py +343 -0
  103. souleyez/handlers/impacket_psexec_handler.py +222 -0
  104. souleyez/handlers/impacket_secretsdump_handler.py +426 -0
  105. souleyez/handlers/john_handler.py +286 -0
  106. souleyez/handlers/katana_handler.py +425 -0
  107. souleyez/handlers/kerbrute_handler.py +298 -0
  108. souleyez/handlers/ldapsearch_handler.py +636 -0
  109. souleyez/handlers/lfi_extract_handler.py +464 -0
  110. souleyez/handlers/msf_auxiliary_handler.py +408 -0
  111. souleyez/handlers/msf_exploit_handler.py +380 -0
  112. souleyez/handlers/nikto_handler.py +413 -0
  113. souleyez/handlers/nmap_handler.py +821 -0
  114. souleyez/handlers/nuclei_handler.py +359 -0
  115. souleyez/handlers/nxc_handler.py +371 -0
  116. souleyez/handlers/rdp_sec_check_handler.py +353 -0
  117. souleyez/handlers/registry.py +292 -0
  118. souleyez/handlers/responder_handler.py +232 -0
  119. souleyez/handlers/service_explorer_handler.py +434 -0
  120. souleyez/handlers/smbclient_handler.py +344 -0
  121. souleyez/handlers/smbmap_handler.py +510 -0
  122. souleyez/handlers/smbpasswd_handler.py +296 -0
  123. souleyez/handlers/sqlmap_handler.py +1116 -0
  124. souleyez/handlers/theharvester_handler.py +601 -0
  125. souleyez/handlers/web_login_test_handler.py +327 -0
  126. souleyez/handlers/whois_handler.py +277 -0
  127. souleyez/handlers/wpscan_handler.py +554 -0
  128. souleyez/history.py +32 -16
  129. souleyez/importers/msf_importer.py +106 -75
  130. souleyez/importers/smart_importer.py +208 -147
  131. souleyez/integrations/siem/__init__.py +10 -10
  132. souleyez/integrations/siem/base.py +17 -18
  133. souleyez/integrations/siem/elastic.py +108 -122
  134. souleyez/integrations/siem/factory.py +207 -80
  135. souleyez/integrations/siem/googlesecops.py +146 -154
  136. souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
  137. souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
  138. souleyez/integrations/siem/sentinel.py +107 -109
  139. souleyez/integrations/siem/splunk.py +246 -212
  140. souleyez/integrations/siem/wazuh.py +65 -71
  141. souleyez/integrations/wazuh/__init__.py +5 -5
  142. souleyez/integrations/wazuh/client.py +70 -93
  143. souleyez/integrations/wazuh/config.py +85 -57
  144. souleyez/integrations/wazuh/host_mapper.py +28 -36
  145. souleyez/integrations/wazuh/sync.py +78 -68
  146. souleyez/intelligence/__init__.py +4 -5
  147. souleyez/intelligence/correlation_analyzer.py +309 -295
  148. souleyez/intelligence/exploit_knowledge.py +661 -623
  149. souleyez/intelligence/exploit_suggestions.py +159 -139
  150. souleyez/intelligence/gap_analyzer.py +132 -97
  151. souleyez/intelligence/gap_detector.py +251 -214
  152. souleyez/intelligence/sensitive_tables.py +266 -129
  153. souleyez/intelligence/service_parser.py +137 -123
  154. souleyez/intelligence/surface_analyzer.py +407 -268
  155. souleyez/intelligence/target_parser.py +159 -162
  156. souleyez/licensing/__init__.py +6 -6
  157. souleyez/licensing/validator.py +17 -19
  158. souleyez/log_config.py +79 -54
  159. souleyez/main.py +1505 -687
  160. souleyez/migrations/fix_job_counter.py +16 -14
  161. souleyez/parsers/bloodhound_parser.py +41 -39
  162. souleyez/parsers/crackmapexec_parser.py +178 -111
  163. souleyez/parsers/dalfox_parser.py +72 -77
  164. souleyez/parsers/dnsrecon_parser.py +103 -91
  165. souleyez/parsers/enum4linux_parser.py +183 -153
  166. souleyez/parsers/ffuf_parser.py +29 -25
  167. souleyez/parsers/gobuster_parser.py +301 -41
  168. souleyez/parsers/hashcat_parser.py +324 -79
  169. souleyez/parsers/http_fingerprint_parser.py +350 -103
  170. souleyez/parsers/hydra_parser.py +131 -111
  171. souleyez/parsers/impacket_parser.py +231 -178
  172. souleyez/parsers/john_parser.py +98 -86
  173. souleyez/parsers/katana_parser.py +316 -0
  174. souleyez/parsers/msf_parser.py +943 -498
  175. souleyez/parsers/nikto_parser.py +346 -65
  176. souleyez/parsers/nmap_parser.py +262 -174
  177. souleyez/parsers/nuclei_parser.py +40 -44
  178. souleyez/parsers/responder_parser.py +26 -26
  179. souleyez/parsers/searchsploit_parser.py +74 -74
  180. souleyez/parsers/service_explorer_parser.py +279 -0
  181. souleyez/parsers/smbmap_parser.py +180 -124
  182. souleyez/parsers/sqlmap_parser.py +434 -308
  183. souleyez/parsers/theharvester_parser.py +75 -57
  184. souleyez/parsers/whois_parser.py +135 -94
  185. souleyez/parsers/wpscan_parser.py +278 -190
  186. souleyez/plugins/afp.py +44 -36
  187. souleyez/plugins/afp_brute.py +114 -46
  188. souleyez/plugins/ard.py +48 -37
  189. souleyez/plugins/bloodhound.py +95 -61
  190. souleyez/plugins/certipy.py +303 -0
  191. souleyez/plugins/crackmapexec.py +186 -85
  192. souleyez/plugins/dalfox.py +120 -59
  193. souleyez/plugins/dns_hijack.py +146 -41
  194. souleyez/plugins/dnsrecon.py +97 -61
  195. souleyez/plugins/enum4linux.py +91 -66
  196. souleyez/plugins/evil_winrm.py +291 -0
  197. souleyez/plugins/ffuf.py +166 -90
  198. souleyez/plugins/firmware_extract.py +133 -29
  199. souleyez/plugins/gobuster.py +387 -190
  200. souleyez/plugins/gpp_extract.py +393 -0
  201. souleyez/plugins/hashcat.py +100 -73
  202. souleyez/plugins/http_fingerprint.py +854 -267
  203. souleyez/plugins/hydra.py +566 -200
  204. souleyez/plugins/impacket_getnpusers.py +117 -69
  205. souleyez/plugins/impacket_psexec.py +84 -64
  206. souleyez/plugins/impacket_secretsdump.py +103 -69
  207. souleyez/plugins/impacket_smbclient.py +89 -75
  208. souleyez/plugins/john.py +86 -69
  209. souleyez/plugins/katana.py +313 -0
  210. souleyez/plugins/kerbrute.py +237 -0
  211. souleyez/plugins/lfi_extract.py +541 -0
  212. souleyez/plugins/macos_ssh.py +117 -48
  213. souleyez/plugins/mdns.py +35 -30
  214. souleyez/plugins/msf_auxiliary.py +253 -130
  215. souleyez/plugins/msf_exploit.py +239 -161
  216. souleyez/plugins/nikto.py +134 -78
  217. souleyez/plugins/nmap.py +275 -91
  218. souleyez/plugins/nuclei.py +180 -89
  219. souleyez/plugins/nxc.py +285 -0
  220. souleyez/plugins/plugin_base.py +35 -36
  221. souleyez/plugins/plugin_template.py +13 -5
  222. souleyez/plugins/rdp_sec_check.py +130 -0
  223. souleyez/plugins/responder.py +112 -71
  224. souleyez/plugins/router_http_brute.py +76 -65
  225. souleyez/plugins/router_ssh_brute.py +118 -41
  226. souleyez/plugins/router_telnet_brute.py +124 -42
  227. souleyez/plugins/routersploit.py +91 -59
  228. souleyez/plugins/routersploit_exploit.py +77 -55
  229. souleyez/plugins/searchsploit.py +91 -77
  230. souleyez/plugins/service_explorer.py +1160 -0
  231. souleyez/plugins/smbmap.py +122 -72
  232. souleyez/plugins/smbpasswd.py +215 -0
  233. souleyez/plugins/sqlmap.py +301 -113
  234. souleyez/plugins/theharvester.py +127 -75
  235. souleyez/plugins/tr069.py +79 -57
  236. souleyez/plugins/upnp.py +65 -47
  237. souleyez/plugins/upnp_abuse.py +73 -55
  238. souleyez/plugins/vnc_access.py +129 -42
  239. souleyez/plugins/vnc_brute.py +109 -38
  240. souleyez/plugins/web_login_test.py +417 -0
  241. souleyez/plugins/whois.py +77 -58
  242. souleyez/plugins/wpscan.py +173 -69
  243. souleyez/reporting/__init__.py +2 -1
  244. souleyez/reporting/attack_chain.py +411 -346
  245. souleyez/reporting/charts.py +436 -501
  246. souleyez/reporting/compliance_mappings.py +334 -201
  247. souleyez/reporting/detection_report.py +126 -125
  248. souleyez/reporting/formatters.py +828 -591
  249. souleyez/reporting/generator.py +386 -302
  250. souleyez/reporting/metrics.py +72 -75
  251. souleyez/scanner.py +35 -29
  252. souleyez/security/__init__.py +37 -11
  253. souleyez/security/scope_validator.py +175 -106
  254. souleyez/security/validation.py +223 -149
  255. souleyez/security.py +22 -6
  256. souleyez/storage/credentials.py +247 -186
  257. souleyez/storage/crypto.py +296 -129
  258. souleyez/storage/database.py +73 -50
  259. souleyez/storage/db.py +58 -36
  260. souleyez/storage/deliverable_evidence.py +177 -128
  261. souleyez/storage/deliverable_exporter.py +282 -246
  262. souleyez/storage/deliverable_templates.py +134 -116
  263. souleyez/storage/deliverables.py +135 -130
  264. souleyez/storage/engagements.py +109 -56
  265. souleyez/storage/evidence.py +181 -152
  266. souleyez/storage/execution_log.py +31 -17
  267. souleyez/storage/exploit_attempts.py +93 -57
  268. souleyez/storage/exploits.py +67 -36
  269. souleyez/storage/findings.py +48 -61
  270. souleyez/storage/hosts.py +176 -144
  271. souleyez/storage/migrate_to_engagements.py +43 -19
  272. souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
  273. souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
  274. souleyez/storage/migrations/_003_add_execution_log.py +14 -8
  275. souleyez/storage/migrations/_005_screenshots.py +13 -5
  276. souleyez/storage/migrations/_006_deliverables.py +13 -5
  277. souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
  278. souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
  279. souleyez/storage/migrations/_010_evidence_linking.py +17 -10
  280. souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
  281. souleyez/storage/migrations/_012_team_collaboration.py +34 -21
  282. souleyez/storage/migrations/_013_add_host_tags.py +12 -6
  283. souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
  284. souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
  285. souleyez/storage/migrations/_016_add_domain_field.py +10 -4
  286. souleyez/storage/migrations/_017_msf_sessions.py +16 -8
  287. souleyez/storage/migrations/_018_add_osint_target.py +10 -6
  288. souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
  289. souleyez/storage/migrations/_020_add_rbac.py +36 -15
  290. souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
  291. souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
  292. souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
  293. souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
  294. souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
  295. souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
  296. souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
  297. souleyez/storage/migrations/__init__.py +26 -26
  298. souleyez/storage/migrations/migration_manager.py +19 -19
  299. souleyez/storage/msf_sessions.py +100 -65
  300. souleyez/storage/osint.py +17 -24
  301. souleyez/storage/recommendation_engine.py +269 -235
  302. souleyez/storage/screenshots.py +33 -32
  303. souleyez/storage/smb_shares.py +136 -92
  304. souleyez/storage/sqlmap_data.py +183 -128
  305. souleyez/storage/team_collaboration.py +135 -141
  306. souleyez/storage/timeline_tracker.py +122 -94
  307. souleyez/storage/wazuh_vulns.py +64 -66
  308. souleyez/storage/web_paths.py +33 -37
  309. souleyez/testing/credential_tester.py +221 -205
  310. souleyez/ui/__init__.py +1 -1
  311. souleyez/ui/ai_quotes.py +12 -12
  312. souleyez/ui/attack_surface.py +2439 -1516
  313. souleyez/ui/chain_rules_view.py +914 -382
  314. souleyez/ui/correlation_view.py +312 -230
  315. souleyez/ui/dashboard.py +2382 -1130
  316. souleyez/ui/deliverables_view.py +148 -62
  317. souleyez/ui/design_system.py +13 -13
  318. souleyez/ui/errors.py +49 -49
  319. souleyez/ui/evidence_linking_view.py +284 -179
  320. souleyez/ui/evidence_vault.py +393 -285
  321. souleyez/ui/exploit_suggestions_view.py +555 -349
  322. souleyez/ui/export_view.py +100 -66
  323. souleyez/ui/gap_analysis_view.py +315 -171
  324. souleyez/ui/help_system.py +105 -97
  325. souleyez/ui/intelligence_view.py +436 -293
  326. souleyez/ui/interactive.py +22827 -10678
  327. souleyez/ui/interactive_selector.py +75 -68
  328. souleyez/ui/log_formatter.py +47 -39
  329. souleyez/ui/menu_components.py +22 -13
  330. souleyez/ui/msf_auxiliary_menu.py +184 -133
  331. souleyez/ui/pending_chains_view.py +336 -172
  332. souleyez/ui/progress_indicators.py +5 -3
  333. souleyez/ui/recommendations_view.py +195 -137
  334. souleyez/ui/rule_builder.py +343 -225
  335. souleyez/ui/setup_wizard.py +678 -284
  336. souleyez/ui/shortcuts.py +217 -165
  337. souleyez/ui/splunk_gap_analysis_view.py +452 -270
  338. souleyez/ui/splunk_vulns_view.py +139 -86
  339. souleyez/ui/team_dashboard.py +498 -335
  340. souleyez/ui/template_selector.py +196 -105
  341. souleyez/ui/terminal.py +6 -6
  342. souleyez/ui/timeline_view.py +198 -127
  343. souleyez/ui/tool_setup.py +264 -164
  344. souleyez/ui/tutorial.py +202 -72
  345. souleyez/ui/tutorial_state.py +40 -40
  346. souleyez/ui/wazuh_vulns_view.py +235 -141
  347. souleyez/ui/wordlist_browser.py +260 -107
  348. souleyez/ui.py +464 -312
  349. souleyez/utils/tool_checker.py +427 -367
  350. souleyez/utils.py +33 -29
  351. souleyez/wordlists.py +134 -167
  352. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/METADATA +1 -1
  353. souleyez-2.43.34.dist-info/RECORD +443 -0
  354. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
  355. souleyez-2.43.29.dist-info/RECORD +0 -379
  356. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
  357. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
  358. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
@@ -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", [])