souleyez 3.0.0__py3-none-any.whl → 3.0.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of souleyez might be problematic. Click here for more details.

Files changed (325) hide show
  1. souleyez/__init__.py +1 -1
  2. souleyez/ai/__init__.py +7 -7
  3. souleyez/ai/action_mapper.py +3 -2
  4. souleyez/ai/chain_advisor.py +2 -1
  5. souleyez/ai/claude_provider.py +2 -2
  6. souleyez/ai/context_builder.py +4 -2
  7. souleyez/ai/executor.py +9 -6
  8. souleyez/ai/feedback_handler.py +4 -2
  9. souleyez/ai/llm_provider.py +2 -2
  10. souleyez/ai/ollama_provider.py +2 -2
  11. souleyez/ai/ollama_service.py +10 -26
  12. souleyez/ai/path_scorer.py +2 -1
  13. souleyez/ai/recommender.py +6 -4
  14. souleyez/ai/report_context.py +2 -2
  15. souleyez/ai/report_service.py +5 -5
  16. souleyez/ai/result_parser.py +3 -2
  17. souleyez/ai/safety.py +5 -2
  18. souleyez/auth/__init__.py +6 -6
  19. souleyez/auth/audit.py +2 -2
  20. souleyez/auth/engagement_access.py +5 -7
  21. souleyez/auth/permissions.py +1 -1
  22. souleyez/auth/session_manager.py +5 -5
  23. souleyez/auth/user_manager.py +4 -5
  24. souleyez/commands/audit.py +6 -5
  25. souleyez/commands/auth.py +6 -5
  26. souleyez/commands/deliverables.py +2 -3
  27. souleyez/commands/engagement.py +3 -3
  28. souleyez/commands/license.py +3 -2
  29. souleyez/commands/screenshots.py +5 -4
  30. souleyez/commands/user.py +10 -8
  31. souleyez/config.py +4 -2
  32. souleyez/core/credential_tester.py +4 -2
  33. souleyez/core/cve_mappings.py +2 -1
  34. souleyez/core/cve_matcher.py +2 -1
  35. souleyez/core/msf_auto_mapper.py +2 -0
  36. souleyez/core/msf_chain_engine.py +3 -1
  37. souleyez/core/msf_database.py +7 -13
  38. souleyez/core/msf_integration.py +2 -2
  39. souleyez/core/msf_rpc_client.py +3 -2
  40. souleyez/core/msf_rpc_manager.py +4 -4
  41. souleyez/core/msf_sync_manager.py +7 -7
  42. souleyez/core/network_utils.py +1 -1
  43. souleyez/core/parser_handler.py +2 -1
  44. souleyez/core/pending_chains.py +4 -3
  45. souleyez/core/templates.py +5 -2
  46. souleyez/core/tool_chaining.py +101 -70
  47. souleyez/core/version_utils.py +1 -0
  48. souleyez/core/vuln_correlation.py +3 -2
  49. souleyez/core/web_utils.py +2 -1
  50. souleyez/detection/__init__.py +1 -1
  51. souleyez/detection/attack_signatures.py +1 -1
  52. souleyez/detection/mitre_mappings.py +1 -2
  53. souleyez/detection/validator.py +5 -4
  54. souleyez/devtools.py +4 -2
  55. souleyez/docs/README.md +2 -2
  56. souleyez/engine/background.py +168 -7
  57. souleyez/engine/base.py +2 -1
  58. souleyez/engine/loader.py +4 -2
  59. souleyez/engine/log_sanitizer.py +1 -0
  60. souleyez/engine/manager.py +3 -1
  61. souleyez/engine/result_handler.py +50 -67
  62. souleyez/engine/worker_manager.py +6 -4
  63. souleyez/export/evidence_bundle.py +1 -0
  64. souleyez/handlers/base.py +1 -0
  65. souleyez/handlers/bash_handler.py +1 -0
  66. souleyez/handlers/bloodhound_handler.py +1 -0
  67. souleyez/handlers/certipy_handler.py +1 -0
  68. souleyez/handlers/crackmapexec_handler.py +2 -20
  69. souleyez/handlers/dnsrecon_handler.py +2 -1
  70. souleyez/handlers/enum4linux_handler.py +65 -37
  71. souleyez/handlers/evil_winrm_handler.py +1 -0
  72. souleyez/handlers/ffuf_handler.py +3 -1
  73. souleyez/handlers/gobuster_handler.py +7 -6
  74. souleyez/handlers/gpp_extract_handler.py +1 -0
  75. souleyez/handlers/hashcat_handler.py +1 -0
  76. souleyez/handlers/hydra_handler.py +5 -2
  77. souleyez/handlers/impacket_getuserspns_handler.py +1 -0
  78. souleyez/handlers/impacket_psexec_handler.py +1 -0
  79. souleyez/handlers/impacket_secretsdump_handler.py +1 -0
  80. souleyez/handlers/john_handler.py +1 -0
  81. souleyez/handlers/katana_handler.py +39 -2
  82. souleyez/handlers/kerbrute_handler.py +1 -0
  83. souleyez/handlers/ldapsearch_handler.py +90 -17
  84. souleyez/handlers/lfi_extract_handler.py +1 -0
  85. souleyez/handlers/msf_auxiliary_handler.py +1 -0
  86. souleyez/handlers/msf_exploit_handler.py +1 -0
  87. souleyez/handlers/nikto_handler.py +2 -1
  88. souleyez/handlers/nmap_handler.py +2 -1
  89. souleyez/handlers/nuclei_handler.py +2 -1
  90. souleyez/handlers/nxc_handler.py +3 -18
  91. souleyez/handlers/rdp_sec_check_handler.py +1 -0
  92. souleyez/handlers/registry.py +1 -0
  93. souleyez/handlers/responder_handler.py +1 -0
  94. souleyez/handlers/service_explorer_handler.py +2 -1
  95. souleyez/handlers/smbclient_handler.py +1 -0
  96. souleyez/handlers/smbmap_handler.py +3 -2
  97. souleyez/handlers/sqlmap_handler.py +6 -4
  98. souleyez/handlers/theharvester_handler.py +2 -1
  99. souleyez/handlers/web_login_test_handler.py +1 -0
  100. souleyez/handlers/whois_handler.py +3 -2
  101. souleyez/handlers/wpscan_handler.py +2 -1
  102. souleyez/history.py +4 -3
  103. souleyez/importers/msf_importer.py +5 -3
  104. souleyez/importers/smart_importer.py +6 -4
  105. souleyez/integrations/siem/__init__.py +6 -6
  106. souleyez/integrations/siem/base.py +1 -1
  107. souleyez/integrations/siem/elastic.py +3 -3
  108. souleyez/integrations/siem/factory.py +1 -2
  109. souleyez/integrations/siem/googlesecops.py +4 -4
  110. souleyez/integrations/siem/rule_mappings/wazuh_rules.py +1 -1
  111. souleyez/integrations/siem/sentinel.py +3 -3
  112. souleyez/integrations/siem/splunk.py +3 -3
  113. souleyez/integrations/siem/wazuh.py +4 -4
  114. souleyez/integrations/wazuh/__init__.py +1 -1
  115. souleyez/integrations/wazuh/client.py +3 -2
  116. souleyez/integrations/wazuh/config.py +3 -2
  117. souleyez/integrations/wazuh/host_mapper.py +3 -1
  118. souleyez/integrations/wazuh/sync.py +4 -1
  119. souleyez/intelligence/__init__.py +1 -1
  120. souleyez/intelligence/correlation_analyzer.py +6 -5
  121. souleyez/intelligence/exploit_knowledge.py +4 -4
  122. souleyez/intelligence/exploit_suggestions.py +4 -3
  123. souleyez/intelligence/gap_analyzer.py +5 -3
  124. souleyez/intelligence/gap_detector.py +2 -0
  125. souleyez/intelligence/sensitive_tables.py +1 -1
  126. souleyez/intelligence/service_parser.py +1 -0
  127. souleyez/intelligence/surface_analyzer.py +9 -9
  128. souleyez/intelligence/target_parser.py +1 -0
  129. souleyez/licensing/__init__.py +3 -3
  130. souleyez/main.py +25 -18
  131. souleyez/migrations/fix_job_counter.py +2 -1
  132. souleyez/parsers/bloodhound_parser.py +1 -0
  133. souleyez/parsers/crackmapexec_parser.py +2 -1
  134. souleyez/parsers/dalfox_parser.py +3 -2
  135. souleyez/parsers/dnsrecon_parser.py +2 -1
  136. souleyez/parsers/enum4linux_parser.py +2 -1
  137. souleyez/parsers/ffuf_parser.py +2 -1
  138. souleyez/parsers/gobuster_parser.py +2 -1
  139. souleyez/parsers/hashcat_parser.py +3 -2
  140. souleyez/parsers/http_fingerprint_parser.py +2 -1
  141. souleyez/parsers/hydra_parser.py +2 -1
  142. souleyez/parsers/impacket_parser.py +2 -1
  143. souleyez/parsers/john_parser.py +4 -3
  144. souleyez/parsers/katana_parser.py +134 -2
  145. souleyez/parsers/msf_parser.py +2 -1
  146. souleyez/parsers/nikto_parser.py +2 -1
  147. souleyez/parsers/nmap_parser.py +14 -3
  148. souleyez/parsers/nuclei_parser.py +3 -2
  149. souleyez/parsers/responder_parser.py +1 -0
  150. souleyez/parsers/searchsploit_parser.py +3 -2
  151. souleyez/parsers/service_explorer_parser.py +1 -0
  152. souleyez/parsers/smbmap_parser.py +2 -1
  153. souleyez/parsers/sqlmap_parser.py +36 -2
  154. souleyez/parsers/theharvester_parser.py +2 -1
  155. souleyez/parsers/whois_parser.py +2 -1
  156. souleyez/parsers/wpscan_parser.py +3 -2
  157. souleyez/plugins/afp.py +3 -1
  158. souleyez/plugins/afp_brute.py +3 -1
  159. souleyez/plugins/ard.py +3 -1
  160. souleyez/plugins/bloodhound.py +3 -2
  161. souleyez/plugins/certipy.py +1 -0
  162. souleyez/plugins/crackmapexec.py +11 -7
  163. souleyez/plugins/dalfox.py +5 -2
  164. souleyez/plugins/dns_hijack.py +3 -1
  165. souleyez/plugins/dnsrecon.py +3 -1
  166. souleyez/plugins/enum4linux.py +3 -1
  167. souleyez/plugins/evil_winrm.py +1 -0
  168. souleyez/plugins/ffuf.py +3 -1
  169. souleyez/plugins/firmware_extract.py +3 -2
  170. souleyez/plugins/gobuster.py +6 -3
  171. souleyez/plugins/gpp_extract.py +1 -0
  172. souleyez/plugins/hashcat.py +2 -1
  173. souleyez/plugins/http_fingerprint.py +57 -7
  174. souleyez/plugins/hydra.py +5 -3
  175. souleyez/plugins/impacket_common.py +40 -0
  176. souleyez/plugins/impacket_getnpusers.py +19 -2
  177. souleyez/plugins/impacket_getuserspns.py +158 -0
  178. souleyez/plugins/impacket_psexec.py +19 -2
  179. souleyez/plugins/impacket_secretsdump.py +19 -2
  180. souleyez/plugins/impacket_smbclient.py +19 -2
  181. souleyez/plugins/john.py +2 -1
  182. souleyez/plugins/katana.py +48 -6
  183. souleyez/plugins/kerbrute.py +1 -0
  184. souleyez/plugins/lfi_extract.py +1 -0
  185. souleyez/plugins/macos_ssh.py +3 -1
  186. souleyez/plugins/mdns.py +3 -1
  187. souleyez/plugins/msf_auxiliary.py +3 -2
  188. souleyez/plugins/msf_exploit.py +6 -5
  189. souleyez/plugins/nikto.py +5 -2
  190. souleyez/plugins/nmap.py +6 -4
  191. souleyez/plugins/nuclei.py +3 -1
  192. souleyez/plugins/nxc.py +1 -0
  193. souleyez/plugins/plugin_base.py +3 -2
  194. souleyez/plugins/plugin_template.py +3 -2
  195. souleyez/plugins/rdp_sec_check.py +1 -0
  196. souleyez/plugins/responder.py +2 -1
  197. souleyez/plugins/router_http_brute.py +3 -1
  198. souleyez/plugins/router_ssh_brute.py +3 -1
  199. souleyez/plugins/router_telnet_brute.py +3 -1
  200. souleyez/plugins/routersploit.py +5 -3
  201. souleyez/plugins/routersploit_exploit.py +5 -3
  202. souleyez/plugins/searchsploit.py +1 -0
  203. souleyez/plugins/service_explorer.py +2 -1
  204. souleyez/plugins/smbmap.py +3 -1
  205. souleyez/plugins/smbpasswd.py +1 -0
  206. souleyez/plugins/sqlmap.py +3 -1
  207. souleyez/plugins/theharvester.py +3 -1
  208. souleyez/plugins/tr069.py +3 -1
  209. souleyez/plugins/upnp.py +3 -1
  210. souleyez/plugins/upnp_abuse.py +4 -2
  211. souleyez/plugins/vnc_access.py +4 -2
  212. souleyez/plugins/vnc_brute.py +3 -1
  213. souleyez/plugins/web_login_test.py +1 -0
  214. souleyez/plugins/whois.py +3 -1
  215. souleyez/plugins/wpscan.py +3 -1
  216. souleyez/reporting/attack_chain.py +2 -1
  217. souleyez/reporting/charts.py +1 -0
  218. souleyez/reporting/compliance_mappings.py +1 -0
  219. souleyez/reporting/detection_report.py +10 -10
  220. souleyez/reporting/formatters.py +7 -12
  221. souleyez/reporting/generator.py +34 -46
  222. souleyez/reporting/metrics.py +2 -1
  223. souleyez/scanner.py +6 -3
  224. souleyez/security/__init__.py +7 -5
  225. souleyez/security/scope_validator.py +5 -4
  226. souleyez/security.py +5 -2
  227. souleyez/storage/credentials.py +14 -19
  228. souleyez/storage/crypto.py +7 -4
  229. souleyez/storage/database.py +6 -6
  230. souleyez/storage/db.py +8 -8
  231. souleyez/storage/deliverable_evidence.py +2 -1
  232. souleyez/storage/deliverable_exporter.py +3 -2
  233. souleyez/storage/deliverable_templates.py +2 -1
  234. souleyez/storage/deliverables.py +2 -1
  235. souleyez/storage/engagements.py +6 -4
  236. souleyez/storage/evidence.py +5 -4
  237. souleyez/storage/execution_log.py +4 -2
  238. souleyez/storage/exploit_attempts.py +3 -2
  239. souleyez/storage/exploits.py +3 -1
  240. souleyez/storage/findings.py +3 -1
  241. souleyez/storage/hosts.py +5 -2
  242. souleyez/storage/migrate_to_engagements.py +14 -24
  243. souleyez/storage/migrations/_001_add_credential_enhancements.py +12 -21
  244. souleyez/storage/migrations/_003_add_execution_log.py +8 -13
  245. souleyez/storage/migrations/_005_screenshots.py +2 -4
  246. souleyez/storage/migrations/_006_deliverables.py +2 -4
  247. souleyez/storage/migrations/_007_deliverable_templates.py +4 -8
  248. souleyez/storage/migrations/_008_add_nuclei_table.py +2 -4
  249. souleyez/storage/migrations/_010_evidence_linking.py +6 -12
  250. souleyez/storage/migrations/_012_team_collaboration.py +12 -24
  251. souleyez/storage/migrations/_013_add_host_tags.py +2 -4
  252. souleyez/storage/migrations/_014_exploit_attempts.py +10 -20
  253. souleyez/storage/migrations/_015_add_mac_os_fields.py +4 -8
  254. souleyez/storage/migrations/_016_add_domain_field.py +2 -4
  255. souleyez/storage/migrations/_017_msf_sessions.py +8 -16
  256. souleyez/storage/migrations/_018_add_osint_target.py +4 -8
  257. souleyez/storage/migrations/_019_add_engagement_type.py +4 -8
  258. souleyez/storage/migrations/_020_add_rbac.py +9 -17
  259. souleyez/storage/migrations/_021_wazuh_integration.py +4 -8
  260. souleyez/storage/migrations/_023_fix_detection_results_fk.py +2 -4
  261. souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +4 -8
  262. souleyez/storage/migrations/_026_add_engagement_scope.py +4 -8
  263. souleyez/storage/migrations/_027_multi_siem_persistence.py +8 -16
  264. souleyez/storage/migrations/__init__.py +1 -4
  265. souleyez/storage/migrations/migration_manager.py +6 -9
  266. souleyez/storage/msf_sessions.py +1 -1
  267. souleyez/storage/osint.py +3 -1
  268. souleyez/storage/recommendation_engine.py +3 -2
  269. souleyez/storage/screenshots.py +2 -1
  270. souleyez/storage/smb_shares.py +3 -1
  271. souleyez/storage/sqlmap_data.py +6 -4
  272. souleyez/storage/team_collaboration.py +3 -2
  273. souleyez/storage/timeline_tracker.py +2 -1
  274. souleyez/storage/wazuh_vulns.py +3 -1
  275. souleyez/storage/web_paths.py +3 -1
  276. souleyez/testing/credential_tester.py +2 -0
  277. souleyez/ui/__init__.py +2 -1
  278. souleyez/ui/ai_quotes.py +1 -1
  279. souleyez/ui/attack_surface.py +50 -28
  280. souleyez/ui/chain_rules_view.py +6 -3
  281. souleyez/ui/correlation_view.py +3 -2
  282. souleyez/ui/dashboard.py +85 -139
  283. souleyez/ui/deliverables_view.py +1 -1
  284. souleyez/ui/design_system.py +5 -3
  285. souleyez/ui/errors.py +3 -1
  286. souleyez/ui/evidence_linking_view.py +2 -1
  287. souleyez/ui/evidence_vault.py +11 -6
  288. souleyez/ui/exploit_suggestions_view.py +11 -7
  289. souleyez/ui/export_view.py +3 -1
  290. souleyez/ui/gap_analysis_view.py +6 -3
  291. souleyez/ui/help_system.py +4 -1
  292. souleyez/ui/intelligence_view.py +7 -3
  293. souleyez/ui/interactive.py +1280 -558
  294. souleyez/ui/interactive_selector.py +3 -2
  295. souleyez/ui/log_formatter.py +1 -0
  296. souleyez/ui/menu_components.py +3 -1
  297. souleyez/ui/msf_auxiliary_menu.py +4 -1
  298. souleyez/ui/pending_chains_view.py +15 -12
  299. souleyez/ui/progress_indicators.py +5 -2
  300. souleyez/ui/recommendations_view.py +4 -2
  301. souleyez/ui/rule_builder.py +4 -1
  302. souleyez/ui/setup_wizard.py +10 -8
  303. souleyez/ui/shortcuts.py +1 -1
  304. souleyez/ui/splunk_gap_analysis_view.py +7 -4
  305. souleyez/ui/splunk_vulns_view.py +4 -1
  306. souleyez/ui/team_dashboard.py +7 -5
  307. souleyez/ui/template_selector.py +2 -1
  308. souleyez/ui/terminal.py +3 -2
  309. souleyez/ui/timeline_view.py +2 -1
  310. souleyez/ui/tool_setup.py +92 -31
  311. souleyez/ui/tutorial.py +7 -4
  312. souleyez/ui/tutorial_state.py +3 -2
  313. souleyez/ui/wazuh_vulns_view.py +5 -2
  314. souleyez/ui/wordlist_browser.py +4 -3
  315. souleyez/ui.py +13 -7
  316. souleyez/utils/tool_checker.py +95 -17
  317. souleyez/utils.py +4 -4
  318. souleyez/wordlists.py +1 -0
  319. {souleyez-3.0.0.dist-info → souleyez-3.0.9.dist-info}/METADATA +1 -1
  320. souleyez-3.0.9.dist-info/RECORD +445 -0
  321. souleyez-3.0.0.dist-info/RECORD +0 -443
  322. {souleyez-3.0.0.dist-info → souleyez-3.0.9.dist-info}/WHEEL +0 -0
  323. {souleyez-3.0.0.dist-info → souleyez-3.0.9.dist-info}/entry_points.txt +0 -0
  324. {souleyez-3.0.0.dist-info → souleyez-3.0.9.dist-info}/licenses/LICENSE +0 -0
  325. {souleyez-3.0.0.dist-info → souleyez-3.0.9.dist-info}/top_level.txt +0 -0
@@ -105,24 +105,8 @@ class CrackMapExecHandler(BaseToolHandler):
105
105
  vulns_found = len(parsed.get("findings", {}).get("vulnerabilities", []))
106
106
  pw_must_change = parsed.get("password_must_change", [])
107
107
 
108
- # Check for transient errors that should trigger retry
109
- transient_errors = [
110
- "NETBIOS connection with the remote host timed out",
111
- "Connection reset by peer",
112
- "Connection timed out",
113
- "Error enumerating shares",
114
- ]
115
- log_content = ""
116
- try:
117
- with open(log_path, "r", encoding="utf-8", errors="replace") as f:
118
- log_content = f.read()
119
- except Exception:
120
- pass
121
-
122
- has_transient_error = any(
123
- err.lower() in log_content.lower() for err in transient_errors
124
- )
125
-
108
+ # Determine status based on results found
109
+ # Retry logic is handled by background.py before parsing
126
110
  if (
127
111
  hosts_found > 0
128
112
  or shares_found > 0
@@ -132,8 +116,6 @@ class CrackMapExecHandler(BaseToolHandler):
132
116
  or len(pw_must_change) > 0
133
117
  ):
134
118
  status = STATUS_DONE
135
- elif has_transient_error:
136
- status = STATUS_WARNING # Transient error - may be retried
137
119
  else:
138
120
  status = STATUS_NO_RESULTS
139
121
 
@@ -4,6 +4,7 @@ DNSRecon handler.
4
4
 
5
5
  Consolidates parsing and display logic for DNSRecon DNS enumeration jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re
@@ -44,9 +45,9 @@ class DNSReconHandler(BaseToolHandler):
44
45
  Extracts DNS records and stores them as OSINT data.
45
46
  """
46
47
  try:
48
+ from souleyez.engine.result_handler import detect_tool_error
47
49
  from souleyez.parsers.dnsrecon_parser import parse_dnsrecon_output
48
50
  from souleyez.storage.osint import OsintManager
49
- from souleyez.engine.result_handler import detect_tool_error
50
51
 
51
52
  # Import managers if not provided
52
53
  if host_manager is None:
@@ -4,6 +4,7 @@ enum4linux handler.
4
4
 
5
5
  Consolidates parsing and display logic for enum4linux SMB/Samba enumeration jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re
@@ -11,7 +12,7 @@ from typing import Any, Dict, Optional
11
12
 
12
13
  import click
13
14
 
14
- from souleyez.engine.job_status import STATUS_DONE, STATUS_WARNING, STATUS_NO_RESULTS
15
+ from souleyez.engine.job_status import STATUS_DONE, STATUS_NO_RESULTS, STATUS_WARNING
15
16
  from souleyez.handlers.base import BaseToolHandler
16
17
 
17
18
  logger = logging.getLogger(__name__)
@@ -44,12 +45,12 @@ class Enum4LinuxHandler(BaseToolHandler):
44
45
  Extracts SMB users, groups, shares and stores them.
45
46
  """
46
47
  try:
48
+ from souleyez.engine.result_handler import detect_tool_error
47
49
  from souleyez.parsers.enum4linux_parser import (
48
- parse_enum4linux_output,
49
- get_smb_stats,
50
50
  categorize_share,
51
+ get_smb_stats,
52
+ parse_enum4linux_output,
51
53
  )
52
- from souleyez.engine.result_handler import detect_tool_error
53
54
 
54
55
  # Import managers if not provided
55
56
  if host_manager is None:
@@ -103,46 +104,71 @@ class Enum4LinuxHandler(BaseToolHandler):
103
104
  )
104
105
  credentials_added += 1
105
106
 
106
- # Store shares as findings
107
+ # Store shares in smb_shares table (proper storage)
108
+ from souleyez.storage.smb_shares import SMBSharesManager
109
+
110
+ smb_mgr = SMBSharesManager()
111
+ shares_added = 0
107
112
  findings_added = 0
113
+
108
114
  for share in parsed.get("shares", []):
109
115
  category = categorize_share(share)
110
- if category == "open":
111
- severity = "high"
112
- elif category == "readable":
113
- severity = "medium"
114
- elif category == "restricted":
115
- severity = "low"
116
- else:
117
- severity = "info"
118
-
119
116
  share_name = share["name"]
120
117
  share_type = share.get("type", "Unknown")
121
118
  mapping = share.get("mapping", "N/A")
122
-
123
- if mapping == "OK":
124
- listing = share.get("listing", "N/A")
125
- writing = share.get("writing", "N/A")
126
- access_desc = (
127
- f"Mapping={mapping}, Listing={listing}, Writing={writing}"
119
+ listing = share.get("listing", "N/A")
120
+ writing = share.get("writing", "N/A")
121
+
122
+ # Determine readable/writable status
123
+ readable = mapping == "OK" and listing in ("OK", "N/A")
124
+ writable = mapping == "OK" and writing == "OK"
125
+
126
+ # Store in smb_shares table
127
+ if host_id:
128
+ try:
129
+ smb_mgr.add_share(
130
+ host_id=host_id,
131
+ share_data={
132
+ "name": share_name,
133
+ "type": share_type,
134
+ "permissions": f"{mapping}/{listing}/{writing}",
135
+ "comment": share.get("comment", ""),
136
+ "readable": readable,
137
+ "writable": writable,
138
+ },
139
+ )
140
+ shares_added += 1
141
+ except Exception as e:
142
+ logger.debug(f"Could not store share in smb_shares: {e}")
143
+
144
+ # Also add a finding for high-risk shares (writable or open)
145
+ if category == "open" or writable:
146
+ if category == "open":
147
+ severity = "high"
148
+ elif writable:
149
+ severity = "medium"
150
+ else:
151
+ severity = "low"
152
+
153
+ title = f"Writable SMB Share: {share_name}"
154
+ description = (
155
+ f"Share: {share_name}\n"
156
+ f"Type: {share_type}\n"
157
+ f"Comment: {share.get('comment', 'N/A')}\n"
158
+ f"Readable: {readable}, Writable: {writable}"
128
159
  )
129
- else:
130
- access_desc = f"Access denied (Mapping={mapping})"
131
160
 
132
- title = f"SMB Share: {share_name} ({share_type})"
133
- description = f"Share: {share_name}\nType: {share_type}\nComment: {share.get('comment', 'N/A')}\nAccess: {access_desc}"
134
-
135
- findings_manager.add_finding(
136
- engagement_id=engagement_id,
137
- host_id=host_id,
138
- title=title,
139
- finding_type="smb_share",
140
- severity=severity,
141
- description=description,
142
- tool="enum4linux",
143
- port=445,
144
- )
145
- findings_added += 1
161
+ findings_manager.add_finding(
162
+ engagement_id=engagement_id,
163
+ host_id=host_id,
164
+ title=title,
165
+ finding_type="smb_share",
166
+ severity=severity,
167
+ description=description,
168
+ tool="enum4linux",
169
+ port=445,
170
+ )
171
+ findings_added += 1
146
172
 
147
173
  stats = get_smb_stats(parsed)
148
174
 
@@ -158,7 +184,8 @@ class Enum4LinuxHandler(BaseToolHandler):
158
184
 
159
185
  # Determine status
160
186
  has_results = (
161
- findings_added > 0
187
+ shares_added > 0
188
+ or findings_added > 0
162
189
  or credentials_added > 0
163
190
  or len(parsed.get("users", [])) > 0
164
191
  or stats["total_shares"] > 0
@@ -177,6 +204,7 @@ class Enum4LinuxHandler(BaseToolHandler):
177
204
  return {
178
205
  "tool": "enum4linux",
179
206
  "status": status,
207
+ "shares_added": shares_added,
180
208
  "findings_added": findings_added,
181
209
  "credentials_added": credentials_added,
182
210
  "users_found": len(parsed.get("users", [])),
@@ -4,6 +4,7 @@ Evil-WinRM handler.
4
4
 
5
5
  Consolidates parsing and display logic for Evil-WinRM jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re
@@ -4,6 +4,7 @@ Ffuf handler.
4
4
 
5
5
  Consolidates parsing and display logic for ffuf fuzzing jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re
@@ -186,8 +187,8 @@ class FfufHandler(BaseToolHandler):
186
187
  Extracts discovered paths and stores them in the database.
187
188
  """
188
189
  try:
189
- from souleyez.parsers.ffuf_parser import parse_ffuf
190
190
  from souleyez.engine.result_handler import detect_tool_error
191
+ from souleyez.parsers.ffuf_parser import parse_ffuf
191
192
 
192
193
  # Import managers if not provided
193
194
  if host_manager is None:
@@ -344,6 +345,7 @@ class FfufHandler(BaseToolHandler):
344
345
  decode the base64, and parse for credentials.
345
346
  """
346
347
  import base64
348
+
347
349
  import requests
348
350
 
349
351
  extracted_creds = []
@@ -4,18 +4,19 @@ Gobuster handler.
4
4
 
5
5
  Consolidates parsing and display logic for Gobuster directory enumeration jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re
10
- import ssl
11
11
  import socket
12
- import urllib.request
12
+ import ssl
13
13
  import urllib.error
14
+ import urllib.request
14
15
  from typing import Any, Dict, List, Optional
15
- from urllib.parse import urlparse, urljoin
16
- import defusedxml.ElementTree as ElementTree # Safe XML parsing
16
+ from urllib.parse import urljoin, urlparse
17
17
 
18
18
  import click
19
+ import defusedxml.ElementTree as ElementTree # Safe XML parsing
19
20
 
20
21
  from souleyez.engine.job_status import (
21
22
  STATUS_DONE,
@@ -201,11 +202,11 @@ class GobusterHandler(BaseToolHandler):
201
202
  Extracts discovered paths and stores them in the database.
202
203
  """
203
204
  try:
205
+ from souleyez.engine.result_handler import detect_tool_error
204
206
  from souleyez.parsers.gobuster_parser import (
205
- parse_gobuster_output,
206
207
  get_paths_stats,
208
+ parse_gobuster_output,
207
209
  )
208
- from souleyez.engine.result_handler import detect_tool_error
209
210
 
210
211
  # Import managers if not provided
211
212
  if host_manager is None:
@@ -4,6 +4,7 @@ GPP Extract handler.
4
4
 
5
5
  Handles parsing and credential storage for GPP (Group Policy Preferences) extraction jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re
@@ -4,6 +4,7 @@ Hashcat handler.
4
4
 
5
5
  Consolidates parsing and display logic for Hashcat password cracking jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  from typing import Any, Dict, Optional
@@ -4,6 +4,7 @@ Hydra handler.
4
4
 
5
5
  Consolidates parsing and display logic for Hydra brute-force jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re
@@ -58,8 +59,8 @@ class HydraHandler(BaseToolHandler):
58
59
  Extracts credentials and usernames from the output.
59
60
  """
60
61
  try:
61
- from souleyez.parsers.hydra_parser import parse_hydra_output
62
62
  from souleyez.engine.result_handler import detect_tool_error
63
+ from souleyez.parsers.hydra_parser import parse_hydra_output
63
64
 
64
65
  # Import managers if not provided
65
66
  if host_manager is None:
@@ -261,7 +262,9 @@ class HydraHandler(BaseToolHandler):
261
262
  "port": parsed.get("port"),
262
263
  "credentials_found": len(parsed.get("credentials", [])),
263
264
  "credentials_added": creds_added,
264
- "credentials": parsed.get("credentials", []), # Include actual creds for smart chains
265
+ "credentials": parsed.get(
266
+ "credentials", []
267
+ ), # Include actual creds for smart chains
265
268
  "usernames_found": len(parsed.get("usernames", [])),
266
269
  "usernames": parsed.get("usernames", []),
267
270
  "usernames_added": usernames_added,
@@ -4,6 +4,7 @@ Impacket GetUserSPNs handler.
4
4
 
5
5
  Handles parsing and display for Kerberoasting results.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re
@@ -4,6 +4,7 @@ Impacket psexec handler.
4
4
 
5
5
  Consolidates parsing and display logic for Impacket psexec remote execution jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re
@@ -4,6 +4,7 @@ Impacket secretsdump handler.
4
4
 
5
5
  Consolidates parsing and display logic for Impacket secretsdump credential extraction jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re
@@ -4,6 +4,7 @@ John the Ripper handler.
4
4
 
5
5
  Consolidates parsing and display logic for John the Ripper password cracking jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  from typing import Any, Dict, Optional
@@ -4,6 +4,7 @@ Katana handler.
4
4
 
5
5
  Consolidates parsing and display logic for katana web crawling jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  from typing import Any, Dict, List, Optional
@@ -49,11 +50,11 @@ class KatanaHandler(BaseToolHandler):
49
50
  Extracts discovered URLs, parameters, forms, and JS endpoints.
50
51
  """
51
52
  try:
53
+ from souleyez.engine.result_handler import detect_tool_error
52
54
  from souleyez.parsers.katana_parser import (
53
- parse_katana_output,
54
55
  extract_injectable_urls,
56
+ parse_katana_output,
55
57
  )
56
- from souleyez.engine.result_handler import detect_tool_error
57
58
 
58
59
  # Import managers if not provided
59
60
  if host_manager is None:
@@ -134,6 +135,42 @@ class KatanaHandler(BaseToolHandler):
134
135
 
135
136
  lfi_urls = extract_lfi_urls(parsed)
136
137
 
138
+ # ARM64/headless workaround: If we have JS files but few parameterized URLs,
139
+ # extract endpoints directly from JavaScript source code
140
+ js_files = [u for u in parsed.get("urls", []) if u.endswith(".js")]
141
+ urls_with_params_list = parsed.get("urls_with_params", [])
142
+ sqli_candidates = parsed.get("sqli_candidate_urls", [])
143
+
144
+ if js_files and len(urls_with_params_list) < 10:
145
+ try:
146
+ from souleyez.parsers.katana_parser import (
147
+ fetch_and_extract_js_endpoints,
148
+ )
149
+
150
+ logger.info(
151
+ f"Extracting endpoints from {len(js_files)} JavaScript files..."
152
+ )
153
+ js_endpoints = fetch_and_extract_js_endpoints(target, js_files)
154
+
155
+ if js_endpoints:
156
+ logger.info(
157
+ f"Found {len(js_endpoints)} additional endpoints from JavaScript"
158
+ )
159
+ # Add to parsed results
160
+ for ep in js_endpoints:
161
+ if ep not in urls_with_params_list:
162
+ urls_with_params_list.append(ep)
163
+ if ep not in sqli_candidates:
164
+ sqli_candidates.append(ep)
165
+ if ep not in injectable_urls:
166
+ injectable_urls.append(ep)
167
+
168
+ # Update parsed dict for display
169
+ parsed["urls_with_params"] = urls_with_params_list
170
+ parsed["sqli_candidate_urls"] = sqli_candidates
171
+ except Exception as e:
172
+ logger.warning(f"JavaScript endpoint extraction failed: {e}")
173
+
137
174
  # Determine status
138
175
  urls_list = parsed.get("urls", [])
139
176
  urls_with_params_list = parsed.get("urls_with_params", [])
@@ -2,6 +2,7 @@
2
2
  """
3
3
  Handler for kerbrute Kerberos enumeration tool.
4
4
  """
5
+
5
6
  import logging
6
7
  import os
7
8
  import re
@@ -2,6 +2,7 @@
2
2
  """
3
3
  Handler for ldapsearch LDAP enumeration tool.
4
4
  """
5
+
5
6
  import logging
6
7
  import os
7
8
  import re
@@ -177,8 +178,8 @@ class LdapsearchHandler(BaseToolHandler):
177
178
  f"{user.get('sAMAccountName')} - check description field"
178
179
  )
179
180
 
180
- # Store credentials if found
181
- if credentials_found and credentials_manager:
181
+ # Store credentials if found AND store enumerated users
182
+ if (credentials_found or usernames) and credentials_manager:
182
183
  if host_manager is None:
183
184
  from souleyez.storage.hosts import HostManager
184
185
 
@@ -186,6 +187,7 @@ class LdapsearchHandler(BaseToolHandler):
186
187
 
187
188
  host = host_manager.get_host_by_ip(engagement_id, target)
188
189
  if host:
190
+ # Store passwords found in descriptions
189
191
  for cred in credentials_found:
190
192
  credentials_manager.add_credential(
191
193
  engagement_id=engagement_id,
@@ -199,6 +201,31 @@ class LdapsearchHandler(BaseToolHandler):
199
201
  notes="Found in LDAP user description field",
200
202
  )
201
203
 
204
+ # Store enumerated usernames (without passwords)
205
+ usernames_stored = 0
206
+ for username in usernames:
207
+ # Skip if already stored with a password
208
+ already_has_cred = any(
209
+ c["username"] == username for c in credentials_found
210
+ )
211
+ if not already_has_cred:
212
+ credentials_manager.add_credential(
213
+ engagement_id=engagement_id,
214
+ host_id=host["id"],
215
+ username=username,
216
+ password="",
217
+ service="ldap",
218
+ credential_type="ldap_user",
219
+ tool="ldapsearch",
220
+ status="enumerated",
221
+ notes="Enumerated via LDAP",
222
+ )
223
+ usernames_stored += 1
224
+ if usernames_stored > 0:
225
+ logger.info(
226
+ f"Stored {usernames_stored} enumerated LDAP usernames"
227
+ )
228
+
202
229
  logger.info(
203
230
  f"ldapsearch parse complete: {len(naming_contexts)} naming contexts, "
204
231
  f"{len(domains)} domains, {len(users)} users, {len(credentials_found)} creds, base_dn={base_dn}"
@@ -420,8 +447,11 @@ class LdapsearchHandler(BaseToolHandler):
420
447
 
421
448
  # New entry starts with "dn:"
422
449
  if line.startswith("dn:"):
450
+ # Save previous entry if it's not explicitly a group
451
+ # Default to including (is_group=False) if no objectClass info
423
452
  if current_user and current_user.get("sAMAccountName"):
424
- users.append(current_user)
453
+ if not current_user.get("is_group", False):
454
+ users.append(current_user)
425
455
  current_user = {}
426
456
  # Extract OU from DN
427
457
  ou_match = re.search(r"OU=([^,]+)", line, re.IGNORECASE)
@@ -448,12 +478,43 @@ class LdapsearchHandler(BaseToolHandler):
448
478
  "key ",
449
479
  "dns",
450
480
  "ras ",
481
+ "cloneable ",
451
482
  )
452
483
  ):
453
484
  current_user["cn_username"] = cn_name.replace(" ", ".")
454
485
 
486
+ elif line.startswith("objectClass:"):
487
+ obj_class = line.split(":", 1)[1].strip().lower()
488
+ # Mark as group if objectClass is group (blacklist approach)
489
+ if obj_class == "group":
490
+ current_user["is_group"] = True
491
+
455
492
  elif line.startswith("sAMAccountName:"):
456
- current_user["sAMAccountName"] = line.split(":", 1)[1].strip()
493
+ sam = line.split(":", 1)[1].strip()
494
+ current_user["sAMAccountName"] = sam
495
+ # Filter out obvious group names by sAMAccountName pattern
496
+ sam_lower = sam.lower()
497
+ if sam_lower in (
498
+ "guest",
499
+ "domain users",
500
+ "domain computers",
501
+ "domain guests",
502
+ "domain admins",
503
+ "enterprise admins",
504
+ "schema admins",
505
+ "cert publishers",
506
+ "group policy creator owners",
507
+ "ras and ias servers",
508
+ "allowed rodc password replication group",
509
+ "denied rodc password replication group",
510
+ "read-only domain controllers",
511
+ "enterprise read-only domain controllers",
512
+ "cloneable domain controllers",
513
+ "protected users",
514
+ "dnsadmins",
515
+ "dnsupdateproxy",
516
+ ):
517
+ current_user["is_group"] = True
457
518
 
458
519
  elif line.startswith("description:"):
459
520
  current_user["description"] = line.split(":", 1)[1].strip()
@@ -466,9 +527,10 @@ class LdapsearchHandler(BaseToolHandler):
466
527
  if cn_match:
467
528
  current_user["memberOf"].append(cn_match.group(1))
468
529
 
469
- # Don't forget last user
530
+ # Don't forget last user - only if it's not a group
470
531
  if current_user and current_user.get("sAMAccountName"):
471
- users.append(current_user)
532
+ if not current_user.get("is_group", False):
533
+ users.append(current_user)
472
534
 
473
535
  # Second pass: add users found only via CN (no sAMAccountName returned)
474
536
  # This catches users from broader queries like (objectClass=*)
@@ -476,9 +538,11 @@ class LdapsearchHandler(BaseToolHandler):
476
538
  for line in log_content.split("\n"):
477
539
  line = line.strip()
478
540
  if line.startswith("dn:"):
479
- if current_user.get("cn_username") and not current_user.get(
480
- "sAMAccountName"
481
- ):
541
+ if (
542
+ current_user.get("cn_username")
543
+ and not current_user.get("sAMAccountName")
544
+ and not current_user.get("is_group", False)
545
+ ): # Default to user if no objectClass
482
546
  # Check if we already have this user
483
547
  existing = [
484
548
  u
@@ -507,24 +571,33 @@ class LdapsearchHandler(BaseToolHandler):
507
571
  "key ",
508
572
  "dns",
509
573
  "ras ",
574
+ "cloneable ",
510
575
  )
511
576
  ):
512
577
  current_user["cn_username"] = cn_name.replace(" ", ".")
513
578
  if ou_match:
514
579
  current_user["ou"] = ou_match.group(1)
580
+ elif line.startswith("objectClass:"):
581
+ obj_class = line.split(":", 1)[1].strip().lower()
582
+ # Blacklist groups - mark as group if objectClass is group
583
+ if obj_class == "group":
584
+ current_user["is_group"] = True
515
585
  elif line.startswith("sAMAccountName:"):
516
586
  current_user["sAMAccountName"] = line.split(":", 1)[1].strip()
517
587
 
518
588
  # Last entry from second pass
519
589
  if current_user.get("cn_username") and not current_user.get("sAMAccountName"):
520
- existing = [
521
- u
522
- for u in users
523
- if u.get("sAMAccountName") == current_user.get("cn_username")
524
- ]
525
- if not existing:
526
- current_user["sAMAccountName"] = current_user["cn_username"]
527
- users.append(current_user)
590
+ if not current_user.get(
591
+ "is_group", False
592
+ ): # Default to user if no objectClass
593
+ existing = [
594
+ u
595
+ for u in users
596
+ if u.get("sAMAccountName") == current_user.get("cn_username")
597
+ ]
598
+ if not existing:
599
+ current_user["sAMAccountName"] = current_user["cn_username"]
600
+ users.append(current_user)
528
601
 
529
602
  return users
530
603
 
@@ -4,6 +4,7 @@ souleyez.handlers.lfi_extract_handler - Handler for LFI credential extraction
4
4
 
5
5
  Parses LFI extract results and stores discovered credentials in the database.
6
6
  """
7
+
7
8
  import json
8
9
  import logging
9
10
  import os
@@ -4,6 +4,7 @@ Metasploit auxiliary handler.
4
4
 
5
5
  Consolidates parsing and display logic for msf_auxiliary jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re
@@ -4,6 +4,7 @@ Metasploit exploit handler.
4
4
 
5
5
  Consolidates parsing and display logic for msf_exploit jobs.
6
6
  """
7
+
7
8
  import logging
8
9
  import os
9
10
  import re