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.
Potentially problematic release.
This version of souleyez might be problematic. Click here for more details.
- souleyez/__init__.py +1 -2
- souleyez/ai/__init__.py +21 -15
- souleyez/ai/action_mapper.py +249 -150
- souleyez/ai/chain_advisor.py +116 -100
- souleyez/ai/claude_provider.py +29 -28
- souleyez/ai/context_builder.py +80 -62
- souleyez/ai/executor.py +158 -117
- souleyez/ai/feedback_handler.py +136 -121
- souleyez/ai/llm_factory.py +27 -20
- souleyez/ai/llm_provider.py +4 -2
- souleyez/ai/ollama_provider.py +6 -9
- souleyez/ai/ollama_service.py +44 -37
- souleyez/ai/path_scorer.py +91 -76
- souleyez/ai/recommender.py +176 -144
- souleyez/ai/report_context.py +74 -73
- souleyez/ai/report_service.py +84 -66
- souleyez/ai/result_parser.py +222 -229
- souleyez/ai/safety.py +67 -44
- souleyez/auth/__init__.py +23 -22
- souleyez/auth/audit.py +36 -26
- souleyez/auth/engagement_access.py +65 -48
- souleyez/auth/permissions.py +14 -3
- souleyez/auth/session_manager.py +54 -37
- souleyez/auth/user_manager.py +109 -64
- souleyez/commands/audit.py +40 -43
- souleyez/commands/auth.py +35 -15
- souleyez/commands/deliverables.py +55 -50
- souleyez/commands/engagement.py +47 -28
- souleyez/commands/license.py +32 -23
- souleyez/commands/screenshots.py +36 -32
- souleyez/commands/user.py +82 -36
- souleyez/config.py +52 -44
- souleyez/core/credential_tester.py +87 -81
- souleyez/core/cve_mappings.py +179 -192
- souleyez/core/cve_matcher.py +162 -148
- souleyez/core/msf_auto_mapper.py +100 -83
- souleyez/core/msf_chain_engine.py +294 -256
- souleyez/core/msf_database.py +153 -70
- souleyez/core/msf_integration.py +679 -673
- souleyez/core/msf_rpc_client.py +40 -42
- souleyez/core/msf_rpc_manager.py +77 -79
- souleyez/core/msf_sync_manager.py +241 -181
- souleyez/core/network_utils.py +22 -15
- souleyez/core/parser_handler.py +34 -25
- souleyez/core/pending_chains.py +114 -63
- souleyez/core/templates.py +158 -107
- souleyez/core/tool_chaining.py +9526 -2879
- souleyez/core/version_utils.py +79 -94
- souleyez/core/vuln_correlation.py +136 -89
- souleyez/core/web_utils.py +33 -32
- souleyez/data/wordlists/ad_users.txt +378 -0
- souleyez/data/wordlists/api_endpoints_large.txt +769 -0
- souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
- souleyez/data/wordlists/lfi_payloads.txt +82 -0
- souleyez/data/wordlists/passwords_brute.txt +1548 -0
- souleyez/data/wordlists/passwords_crack.txt +2479 -0
- souleyez/data/wordlists/passwords_spray.txt +386 -0
- souleyez/data/wordlists/subdomains_large.txt +5057 -0
- souleyez/data/wordlists/usernames_common.txt +694 -0
- souleyez/data/wordlists/web_dirs_large.txt +4769 -0
- souleyez/detection/__init__.py +1 -1
- souleyez/detection/attack_signatures.py +12 -17
- souleyez/detection/mitre_mappings.py +61 -55
- souleyez/detection/validator.py +97 -86
- souleyez/devtools.py +23 -10
- souleyez/docs/README.md +4 -4
- souleyez/docs/api-reference/cli-commands.md +2 -2
- souleyez/docs/developer-guide/adding-new-tools.md +562 -0
- souleyez/docs/user-guide/auto-chaining.md +30 -8
- souleyez/docs/user-guide/getting-started.md +1 -1
- souleyez/docs/user-guide/installation.md +26 -3
- souleyez/docs/user-guide/metasploit-integration.md +2 -2
- souleyez/docs/user-guide/rbac.md +1 -1
- souleyez/docs/user-guide/scope-management.md +1 -1
- souleyez/docs/user-guide/siem-integration.md +1 -1
- souleyez/docs/user-guide/tools-reference.md +1 -8
- souleyez/docs/user-guide/worker-management.md +1 -1
- souleyez/engine/background.py +1239 -535
- souleyez/engine/base.py +4 -1
- souleyez/engine/job_status.py +17 -49
- souleyez/engine/log_sanitizer.py +103 -77
- souleyez/engine/manager.py +38 -7
- souleyez/engine/result_handler.py +2200 -1550
- souleyez/engine/worker_manager.py +50 -41
- souleyez/export/evidence_bundle.py +72 -62
- souleyez/feature_flags/features.py +16 -20
- souleyez/feature_flags.py +5 -9
- souleyez/handlers/__init__.py +11 -0
- souleyez/handlers/base.py +188 -0
- souleyez/handlers/bash_handler.py +277 -0
- souleyez/handlers/bloodhound_handler.py +243 -0
- souleyez/handlers/certipy_handler.py +311 -0
- souleyez/handlers/crackmapexec_handler.py +486 -0
- souleyez/handlers/dnsrecon_handler.py +344 -0
- souleyez/handlers/enum4linux_handler.py +400 -0
- souleyez/handlers/evil_winrm_handler.py +493 -0
- souleyez/handlers/ffuf_handler.py +815 -0
- souleyez/handlers/gobuster_handler.py +1114 -0
- souleyez/handlers/gpp_extract_handler.py +334 -0
- souleyez/handlers/hashcat_handler.py +444 -0
- souleyez/handlers/hydra_handler.py +563 -0
- souleyez/handlers/impacket_getuserspns_handler.py +343 -0
- souleyez/handlers/impacket_psexec_handler.py +222 -0
- souleyez/handlers/impacket_secretsdump_handler.py +426 -0
- souleyez/handlers/john_handler.py +286 -0
- souleyez/handlers/katana_handler.py +425 -0
- souleyez/handlers/kerbrute_handler.py +298 -0
- souleyez/handlers/ldapsearch_handler.py +636 -0
- souleyez/handlers/lfi_extract_handler.py +464 -0
- souleyez/handlers/msf_auxiliary_handler.py +408 -0
- souleyez/handlers/msf_exploit_handler.py +380 -0
- souleyez/handlers/nikto_handler.py +413 -0
- souleyez/handlers/nmap_handler.py +821 -0
- souleyez/handlers/nuclei_handler.py +359 -0
- souleyez/handlers/nxc_handler.py +371 -0
- souleyez/handlers/rdp_sec_check_handler.py +353 -0
- souleyez/handlers/registry.py +292 -0
- souleyez/handlers/responder_handler.py +232 -0
- souleyez/handlers/service_explorer_handler.py +434 -0
- souleyez/handlers/smbclient_handler.py +344 -0
- souleyez/handlers/smbmap_handler.py +510 -0
- souleyez/handlers/smbpasswd_handler.py +296 -0
- souleyez/handlers/sqlmap_handler.py +1116 -0
- souleyez/handlers/theharvester_handler.py +601 -0
- souleyez/handlers/web_login_test_handler.py +327 -0
- souleyez/handlers/whois_handler.py +277 -0
- souleyez/handlers/wpscan_handler.py +554 -0
- souleyez/history.py +32 -16
- souleyez/importers/msf_importer.py +106 -75
- souleyez/importers/smart_importer.py +208 -147
- souleyez/integrations/siem/__init__.py +10 -10
- souleyez/integrations/siem/base.py +17 -18
- souleyez/integrations/siem/elastic.py +108 -122
- souleyez/integrations/siem/factory.py +207 -80
- souleyez/integrations/siem/googlesecops.py +146 -154
- souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
- souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
- souleyez/integrations/siem/sentinel.py +107 -109
- souleyez/integrations/siem/splunk.py +246 -212
- souleyez/integrations/siem/wazuh.py +65 -71
- souleyez/integrations/wazuh/__init__.py +5 -5
- souleyez/integrations/wazuh/client.py +70 -93
- souleyez/integrations/wazuh/config.py +85 -57
- souleyez/integrations/wazuh/host_mapper.py +28 -36
- souleyez/integrations/wazuh/sync.py +78 -68
- souleyez/intelligence/__init__.py +4 -5
- souleyez/intelligence/correlation_analyzer.py +309 -295
- souleyez/intelligence/exploit_knowledge.py +661 -623
- souleyez/intelligence/exploit_suggestions.py +159 -139
- souleyez/intelligence/gap_analyzer.py +132 -97
- souleyez/intelligence/gap_detector.py +251 -214
- souleyez/intelligence/sensitive_tables.py +266 -129
- souleyez/intelligence/service_parser.py +137 -123
- souleyez/intelligence/surface_analyzer.py +407 -268
- souleyez/intelligence/target_parser.py +159 -162
- souleyez/licensing/__init__.py +6 -6
- souleyez/licensing/validator.py +17 -19
- souleyez/log_config.py +79 -54
- souleyez/main.py +1505 -687
- souleyez/migrations/fix_job_counter.py +16 -14
- souleyez/parsers/bloodhound_parser.py +41 -39
- souleyez/parsers/crackmapexec_parser.py +178 -111
- souleyez/parsers/dalfox_parser.py +72 -77
- souleyez/parsers/dnsrecon_parser.py +103 -91
- souleyez/parsers/enum4linux_parser.py +183 -153
- souleyez/parsers/ffuf_parser.py +29 -25
- souleyez/parsers/gobuster_parser.py +301 -41
- souleyez/parsers/hashcat_parser.py +324 -79
- souleyez/parsers/http_fingerprint_parser.py +350 -103
- souleyez/parsers/hydra_parser.py +131 -111
- souleyez/parsers/impacket_parser.py +231 -178
- souleyez/parsers/john_parser.py +98 -86
- souleyez/parsers/katana_parser.py +316 -0
- souleyez/parsers/msf_parser.py +943 -498
- souleyez/parsers/nikto_parser.py +346 -65
- souleyez/parsers/nmap_parser.py +262 -174
- souleyez/parsers/nuclei_parser.py +40 -44
- souleyez/parsers/responder_parser.py +26 -26
- souleyez/parsers/searchsploit_parser.py +74 -74
- souleyez/parsers/service_explorer_parser.py +279 -0
- souleyez/parsers/smbmap_parser.py +180 -124
- souleyez/parsers/sqlmap_parser.py +434 -308
- souleyez/parsers/theharvester_parser.py +75 -57
- souleyez/parsers/whois_parser.py +135 -94
- souleyez/parsers/wpscan_parser.py +278 -190
- souleyez/plugins/afp.py +44 -36
- souleyez/plugins/afp_brute.py +114 -46
- souleyez/plugins/ard.py +48 -37
- souleyez/plugins/bloodhound.py +95 -61
- souleyez/plugins/certipy.py +303 -0
- souleyez/plugins/crackmapexec.py +186 -85
- souleyez/plugins/dalfox.py +120 -59
- souleyez/plugins/dns_hijack.py +146 -41
- souleyez/plugins/dnsrecon.py +97 -61
- souleyez/plugins/enum4linux.py +91 -66
- souleyez/plugins/evil_winrm.py +291 -0
- souleyez/plugins/ffuf.py +166 -90
- souleyez/plugins/firmware_extract.py +133 -29
- souleyez/plugins/gobuster.py +387 -190
- souleyez/plugins/gpp_extract.py +393 -0
- souleyez/plugins/hashcat.py +100 -73
- souleyez/plugins/http_fingerprint.py +854 -267
- souleyez/plugins/hydra.py +566 -200
- souleyez/plugins/impacket_getnpusers.py +117 -69
- souleyez/plugins/impacket_psexec.py +84 -64
- souleyez/plugins/impacket_secretsdump.py +103 -69
- souleyez/plugins/impacket_smbclient.py +89 -75
- souleyez/plugins/john.py +86 -69
- souleyez/plugins/katana.py +313 -0
- souleyez/plugins/kerbrute.py +237 -0
- souleyez/plugins/lfi_extract.py +541 -0
- souleyez/plugins/macos_ssh.py +117 -48
- souleyez/plugins/mdns.py +35 -30
- souleyez/plugins/msf_auxiliary.py +253 -130
- souleyez/plugins/msf_exploit.py +239 -161
- souleyez/plugins/nikto.py +134 -78
- souleyez/plugins/nmap.py +275 -91
- souleyez/plugins/nuclei.py +180 -89
- souleyez/plugins/nxc.py +285 -0
- souleyez/plugins/plugin_base.py +35 -36
- souleyez/plugins/plugin_template.py +13 -5
- souleyez/plugins/rdp_sec_check.py +130 -0
- souleyez/plugins/responder.py +112 -71
- souleyez/plugins/router_http_brute.py +76 -65
- souleyez/plugins/router_ssh_brute.py +118 -41
- souleyez/plugins/router_telnet_brute.py +124 -42
- souleyez/plugins/routersploit.py +91 -59
- souleyez/plugins/routersploit_exploit.py +77 -55
- souleyez/plugins/searchsploit.py +91 -77
- souleyez/plugins/service_explorer.py +1160 -0
- souleyez/plugins/smbmap.py +122 -72
- souleyez/plugins/smbpasswd.py +215 -0
- souleyez/plugins/sqlmap.py +301 -113
- souleyez/plugins/theharvester.py +127 -75
- souleyez/plugins/tr069.py +79 -57
- souleyez/plugins/upnp.py +65 -47
- souleyez/plugins/upnp_abuse.py +73 -55
- souleyez/plugins/vnc_access.py +129 -42
- souleyez/plugins/vnc_brute.py +109 -38
- souleyez/plugins/web_login_test.py +417 -0
- souleyez/plugins/whois.py +77 -58
- souleyez/plugins/wpscan.py +173 -69
- souleyez/reporting/__init__.py +2 -1
- souleyez/reporting/attack_chain.py +411 -346
- souleyez/reporting/charts.py +436 -501
- souleyez/reporting/compliance_mappings.py +334 -201
- souleyez/reporting/detection_report.py +126 -125
- souleyez/reporting/formatters.py +828 -591
- souleyez/reporting/generator.py +386 -302
- souleyez/reporting/metrics.py +72 -75
- souleyez/scanner.py +35 -29
- souleyez/security/__init__.py +37 -11
- souleyez/security/scope_validator.py +175 -106
- souleyez/security/validation.py +223 -149
- souleyez/security.py +22 -6
- souleyez/storage/credentials.py +247 -186
- souleyez/storage/crypto.py +296 -129
- souleyez/storage/database.py +73 -50
- souleyez/storage/db.py +58 -36
- souleyez/storage/deliverable_evidence.py +177 -128
- souleyez/storage/deliverable_exporter.py +282 -246
- souleyez/storage/deliverable_templates.py +134 -116
- souleyez/storage/deliverables.py +135 -130
- souleyez/storage/engagements.py +109 -56
- souleyez/storage/evidence.py +181 -152
- souleyez/storage/execution_log.py +31 -17
- souleyez/storage/exploit_attempts.py +93 -57
- souleyez/storage/exploits.py +67 -36
- souleyez/storage/findings.py +48 -61
- souleyez/storage/hosts.py +176 -144
- souleyez/storage/migrate_to_engagements.py +43 -19
- souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
- souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
- souleyez/storage/migrations/_003_add_execution_log.py +14 -8
- souleyez/storage/migrations/_005_screenshots.py +13 -5
- souleyez/storage/migrations/_006_deliverables.py +13 -5
- souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
- souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
- souleyez/storage/migrations/_010_evidence_linking.py +17 -10
- souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
- souleyez/storage/migrations/_012_team_collaboration.py +34 -21
- souleyez/storage/migrations/_013_add_host_tags.py +12 -6
- souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
- souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
- souleyez/storage/migrations/_016_add_domain_field.py +10 -4
- souleyez/storage/migrations/_017_msf_sessions.py +16 -8
- souleyez/storage/migrations/_018_add_osint_target.py +10 -6
- souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
- souleyez/storage/migrations/_020_add_rbac.py +36 -15
- souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
- souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
- souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
- souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
- souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
- souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
- souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
- souleyez/storage/migrations/__init__.py +26 -26
- souleyez/storage/migrations/migration_manager.py +19 -19
- souleyez/storage/msf_sessions.py +100 -65
- souleyez/storage/osint.py +17 -24
- souleyez/storage/recommendation_engine.py +269 -235
- souleyez/storage/screenshots.py +33 -32
- souleyez/storage/smb_shares.py +136 -92
- souleyez/storage/sqlmap_data.py +183 -128
- souleyez/storage/team_collaboration.py +135 -141
- souleyez/storage/timeline_tracker.py +122 -94
- souleyez/storage/wazuh_vulns.py +64 -66
- souleyez/storage/web_paths.py +33 -37
- souleyez/testing/credential_tester.py +221 -205
- souleyez/ui/__init__.py +1 -1
- souleyez/ui/ai_quotes.py +12 -12
- souleyez/ui/attack_surface.py +2439 -1516
- souleyez/ui/chain_rules_view.py +914 -382
- souleyez/ui/correlation_view.py +312 -230
- souleyez/ui/dashboard.py +2382 -1130
- souleyez/ui/deliverables_view.py +148 -62
- souleyez/ui/design_system.py +13 -13
- souleyez/ui/errors.py +49 -49
- souleyez/ui/evidence_linking_view.py +284 -179
- souleyez/ui/evidence_vault.py +393 -285
- souleyez/ui/exploit_suggestions_view.py +555 -349
- souleyez/ui/export_view.py +100 -66
- souleyez/ui/gap_analysis_view.py +315 -171
- souleyez/ui/help_system.py +105 -97
- souleyez/ui/intelligence_view.py +436 -293
- souleyez/ui/interactive.py +22827 -10678
- souleyez/ui/interactive_selector.py +75 -68
- souleyez/ui/log_formatter.py +47 -39
- souleyez/ui/menu_components.py +22 -13
- souleyez/ui/msf_auxiliary_menu.py +184 -133
- souleyez/ui/pending_chains_view.py +336 -172
- souleyez/ui/progress_indicators.py +5 -3
- souleyez/ui/recommendations_view.py +195 -137
- souleyez/ui/rule_builder.py +343 -225
- souleyez/ui/setup_wizard.py +678 -284
- souleyez/ui/shortcuts.py +217 -165
- souleyez/ui/splunk_gap_analysis_view.py +452 -270
- souleyez/ui/splunk_vulns_view.py +139 -86
- souleyez/ui/team_dashboard.py +498 -335
- souleyez/ui/template_selector.py +196 -105
- souleyez/ui/terminal.py +6 -6
- souleyez/ui/timeline_view.py +198 -127
- souleyez/ui/tool_setup.py +264 -164
- souleyez/ui/tutorial.py +202 -72
- souleyez/ui/tutorial_state.py +40 -40
- souleyez/ui/wazuh_vulns_view.py +235 -141
- souleyez/ui/wordlist_browser.py +260 -107
- souleyez/ui.py +464 -312
- souleyez/utils/tool_checker.py +427 -367
- souleyez/utils.py +33 -29
- souleyez/wordlists.py +134 -167
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/METADATA +1 -1
- souleyez-2.43.34.dist-info/RECORD +443 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
- souleyez-2.43.29.dist-info/RECORD +0 -379
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
|
@@ -56,168 +56,189 @@ def parse_smbmap_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
56
56
|
}
|
|
57
57
|
"""
|
|
58
58
|
result = {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
"target": target,
|
|
60
|
+
"status": None,
|
|
61
|
+
"shares": [],
|
|
62
|
+
"files": [],
|
|
63
|
+
"smb_detected": False,
|
|
64
|
+
"hosts_count": 0,
|
|
65
|
+
"error": None,
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
# Check for SMB detection (even if tool crashes later)
|
|
69
69
|
# [*] Detected 1 hosts serving SMB
|
|
70
|
-
smb_detected_match = re.search(
|
|
70
|
+
smb_detected_match = re.search(
|
|
71
|
+
r"\[\*\]\s*Detected\s+(\d+)\s+hosts?\s+serving\s+SMB", output
|
|
72
|
+
)
|
|
71
73
|
if smb_detected_match:
|
|
72
|
-
result[
|
|
73
|
-
result[
|
|
74
|
+
result["smb_detected"] = True
|
|
75
|
+
result["hosts_count"] = int(smb_detected_match.group(1))
|
|
74
76
|
|
|
75
77
|
# Check for Python traceback (tool crash)
|
|
76
|
-
if
|
|
78
|
+
if "Traceback (most recent call last):" in output:
|
|
77
79
|
# Extract error message from traceback
|
|
78
|
-
error_match = re.search(
|
|
80
|
+
error_match = re.search(
|
|
81
|
+
r'(?:Error|Exception).*?[\'"]([^\'"]+)[\'"]', output, re.DOTALL
|
|
82
|
+
)
|
|
79
83
|
if error_match:
|
|
80
|
-
result[
|
|
84
|
+
result["error"] = error_match.group(1)
|
|
81
85
|
else:
|
|
82
86
|
# Try to get the last line of the traceback
|
|
83
|
-
traceback_lines =
|
|
87
|
+
traceback_lines = (
|
|
88
|
+
output.split("Traceback (most recent call last):")[-1]
|
|
89
|
+
.strip()
|
|
90
|
+
.split("\n")
|
|
91
|
+
)
|
|
84
92
|
for line in reversed(traceback_lines):
|
|
85
93
|
line = line.strip()
|
|
86
|
-
if
|
|
87
|
-
|
|
94
|
+
if (
|
|
95
|
+
line
|
|
96
|
+
and not line.startswith("File")
|
|
97
|
+
and not line.startswith("raise")
|
|
98
|
+
):
|
|
99
|
+
result["error"] = line[:200] # Limit length
|
|
88
100
|
break
|
|
89
101
|
|
|
90
|
-
lines = output.split(
|
|
102
|
+
lines = output.split("\n")
|
|
91
103
|
in_share_table = False
|
|
92
104
|
current_share = None
|
|
93
105
|
|
|
94
106
|
for i, line in enumerate(lines):
|
|
95
107
|
# Remove ANSI color codes and control characters more thoroughly
|
|
96
|
-
line = re.sub(r
|
|
97
|
-
line = re.sub(r
|
|
108
|
+
line = re.sub(r"\x1b\[[0-9;]*[a-zA-Z]", "", line) # All ANSI escape sequences
|
|
109
|
+
line = re.sub(r"\x1b\].*?\x07", "", line) # OSC sequences
|
|
98
110
|
# Only remove leading progress indicators, not all brackets
|
|
99
|
-
line = re.sub(r
|
|
111
|
+
line = re.sub(r"^[\[\]\|/\\-]+\s*", "", line)
|
|
100
112
|
line = line.strip()
|
|
101
113
|
|
|
102
114
|
# Extract target and status
|
|
103
115
|
# [+] IP: 10.0.0.82:445 Name: 10.0.0.82 Status: Authenticated
|
|
104
|
-
if line.startswith(
|
|
105
|
-
status_match = re.search(r
|
|
116
|
+
if line.startswith("+") and "IP:" in line and "Status:" in line:
|
|
117
|
+
status_match = re.search(r"Status:\s+(\w+)", line)
|
|
106
118
|
if status_match:
|
|
107
|
-
result[
|
|
119
|
+
result["status"] = status_match.group(1)
|
|
108
120
|
|
|
109
121
|
# Extract target IP if not provided
|
|
110
|
-
if not result[
|
|
111
|
-
ip_match = re.search(r
|
|
122
|
+
if not result["target"]:
|
|
123
|
+
ip_match = re.search(r"IP:\s+([\d\.]+)", line)
|
|
112
124
|
if ip_match:
|
|
113
|
-
result[
|
|
125
|
+
result["target"] = ip_match.group(1)
|
|
114
126
|
|
|
115
127
|
# Detect share table header
|
|
116
128
|
# Disk Permissions Comment
|
|
117
|
-
elif
|
|
129
|
+
elif "Disk" in line and "Permissions" in line and "Comment" in line:
|
|
118
130
|
in_share_table = True
|
|
119
131
|
continue
|
|
120
132
|
|
|
121
133
|
# Skip separator line
|
|
122
|
-
elif line.startswith(
|
|
134
|
+
elif line.startswith("----") or line.startswith("==="):
|
|
123
135
|
continue
|
|
124
136
|
|
|
125
137
|
# Parse share entries
|
|
126
|
-
elif
|
|
138
|
+
elif (
|
|
139
|
+
in_share_table
|
|
140
|
+
and line
|
|
141
|
+
and not line.startswith("*")
|
|
142
|
+
and not line.startswith("Closed")
|
|
143
|
+
):
|
|
127
144
|
# Try to parse share line
|
|
128
145
|
# Format: sharename <tabs/spaces> permissions <tabs/spaces> comment
|
|
129
146
|
# tmp READ, WRITE oh noes!
|
|
130
147
|
|
|
131
148
|
share_name = None
|
|
132
149
|
permissions = None
|
|
133
|
-
comment =
|
|
150
|
+
comment = ""
|
|
134
151
|
|
|
135
152
|
# Try tab split first
|
|
136
|
-
parts = re.split(r
|
|
153
|
+
parts = re.split(r"\t+", line)
|
|
137
154
|
if len(parts) >= 2:
|
|
138
155
|
share_name = parts[0].strip()
|
|
139
156
|
# Find permissions in remaining parts
|
|
140
157
|
for p in parts[1:]:
|
|
141
158
|
p = p.strip().upper()
|
|
142
|
-
if any(x in p for x in [
|
|
159
|
+
if any(x in p for x in ["READ", "WRITE", "NO ACCESS", "NOACCESS"]):
|
|
143
160
|
permissions = p
|
|
144
161
|
break
|
|
145
162
|
# Comment is everything after permissions
|
|
146
163
|
if permissions and len(parts) > 2:
|
|
147
|
-
perm_idx = next(
|
|
164
|
+
perm_idx = next(
|
|
165
|
+
(i for i, p in enumerate(parts) if permissions in p.upper()), -1
|
|
166
|
+
)
|
|
148
167
|
if perm_idx >= 0 and perm_idx + 1 < len(parts):
|
|
149
|
-
comment =
|
|
168
|
+
comment = " ".join(parts[perm_idx + 1 :]).strip()
|
|
150
169
|
|
|
151
170
|
# No tabs or tab parse failed - try space-based parsing
|
|
152
171
|
if not permissions:
|
|
153
172
|
# Match patterns with flexible spacing and permission variations
|
|
154
173
|
permission_patterns = [
|
|
155
|
-
r
|
|
156
|
-
r
|
|
174
|
+
r"^\s*(\S+)\s{2,}(READ,?\s*WRITE|READ\s*ONLY|WRITE\s*ONLY|NO\s*ACCESS|READ|WRITE)(?:\s{2,}(.*))?$",
|
|
175
|
+
r"^\s*(\S+)\s+(READ,?\s*WRITE|READ\s*ONLY|WRITE\s*ONLY|NO\s*ACCESS|READ|WRITE)\s*(.*)$",
|
|
157
176
|
]
|
|
158
177
|
for pattern in permission_patterns:
|
|
159
178
|
match = re.match(pattern, line, re.IGNORECASE)
|
|
160
179
|
if match:
|
|
161
180
|
share_name = match.group(1).strip()
|
|
162
181
|
permissions = match.group(2).strip().upper()
|
|
163
|
-
comment = match.group(3).strip() if match.group(3) else
|
|
182
|
+
comment = match.group(3).strip() if match.group(3) else ""
|
|
164
183
|
break
|
|
165
184
|
|
|
166
185
|
if not share_name or not permissions:
|
|
167
186
|
continue
|
|
168
187
|
|
|
169
188
|
# Skip empty lines or non-share lines
|
|
170
|
-
if not share_name or share_name in [
|
|
189
|
+
if not share_name or share_name in ["Disk", "IPC", "", "*"]:
|
|
171
190
|
continue
|
|
172
191
|
|
|
173
192
|
# Skip separator lines (----, ===, etc.)
|
|
174
|
-
if re.match(r
|
|
193
|
+
if re.match(r"^[\-=]+$", share_name):
|
|
175
194
|
continue
|
|
176
195
|
|
|
177
196
|
# Determine share type (Disk vs IPC)
|
|
178
|
-
share_type =
|
|
197
|
+
share_type = (
|
|
198
|
+
"IPC" if share_name.endswith("$") and "IPC" in comment else "Disk"
|
|
199
|
+
)
|
|
179
200
|
|
|
180
201
|
# Parse permissions
|
|
181
|
-
readable =
|
|
182
|
-
writable =
|
|
202
|
+
readable = "READ" in permissions.upper()
|
|
203
|
+
writable = "WRITE" in permissions.upper()
|
|
183
204
|
|
|
184
205
|
share_info = {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
206
|
+
"name": share_name,
|
|
207
|
+
"type": share_type,
|
|
208
|
+
"permissions": permissions,
|
|
209
|
+
"comment": comment,
|
|
210
|
+
"readable": readable,
|
|
211
|
+
"writable": writable,
|
|
191
212
|
}
|
|
192
213
|
|
|
193
|
-
result[
|
|
214
|
+
result["shares"].append(share_info)
|
|
194
215
|
current_share = share_name
|
|
195
216
|
|
|
196
217
|
# Parse file listings (if -R was used)
|
|
197
218
|
# dr--r--r-- 0 Sat May 16 14:06:55 2009 .
|
|
198
219
|
# dr--r--r-- 0 Sat May 16 14:06:55 2009 ..
|
|
199
220
|
# fr--r--r-- 512 Sat May 16 14:06:55 2009 script.sh
|
|
200
|
-
elif current_share and re.match(r
|
|
221
|
+
elif current_share and re.match(r"^[df]r", line):
|
|
201
222
|
# File listing format: permissions size timestamp filename
|
|
202
|
-
file_match = re.match(r
|
|
223
|
+
file_match = re.match(r"^([df]r[\-rwx]+)\s+(\d+)\s+(.+?)\s{2,}(.+)$", line)
|
|
203
224
|
if file_match:
|
|
204
225
|
perms, size, timestamp, filename = file_match.groups()
|
|
205
226
|
|
|
206
227
|
# Skip . and .. entries
|
|
207
|
-
if filename in [
|
|
228
|
+
if filename in [".", ".."]:
|
|
208
229
|
continue
|
|
209
230
|
|
|
210
231
|
file_info = {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
232
|
+
"share": current_share,
|
|
233
|
+
"path": filename,
|
|
234
|
+
"size": int(size),
|
|
235
|
+
"timestamp": timestamp.strip(),
|
|
236
|
+
"is_directory": perms.startswith("d"),
|
|
216
237
|
}
|
|
217
|
-
result[
|
|
238
|
+
result["files"].append(file_info)
|
|
218
239
|
|
|
219
240
|
# Detect end of output
|
|
220
|
-
elif
|
|
241
|
+
elif "Closed" in line and "connections" in line:
|
|
221
242
|
in_share_table = False
|
|
222
243
|
current_share = None
|
|
223
244
|
|
|
@@ -240,86 +261,121 @@ def extract_findings(parsed_data: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
|
240
261
|
findings = []
|
|
241
262
|
|
|
242
263
|
# Finding 1: Writable shares (HIGH severity)
|
|
243
|
-
writable_shares = [s for s in parsed_data[
|
|
264
|
+
writable_shares = [s for s in parsed_data["shares"] if s["writable"]]
|
|
244
265
|
if writable_shares:
|
|
245
|
-
share_names =
|
|
246
|
-
findings.append(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
266
|
+
share_names = ", ".join([s["name"] for s in writable_shares])
|
|
267
|
+
findings.append(
|
|
268
|
+
{
|
|
269
|
+
"title": "Writable SMB Shares Detected",
|
|
270
|
+
"severity": "high",
|
|
271
|
+
"description": f"Found {len(writable_shares)} SMB share(s) with WRITE permissions: {share_names}. "
|
|
272
|
+
"Writable shares can be exploited to upload malicious files, plant ransomware, "
|
|
273
|
+
"or exfiltrate sensitive data.",
|
|
274
|
+
"evidence": "\n".join(
|
|
275
|
+
[
|
|
276
|
+
f"- {s['name']}: {s['permissions']} ({s['comment']})"
|
|
277
|
+
for s in writable_shares
|
|
278
|
+
]
|
|
279
|
+
),
|
|
280
|
+
}
|
|
281
|
+
)
|
|
257
282
|
|
|
258
283
|
# Finding 2: Readable shares (MEDIUM severity)
|
|
259
|
-
readable_shares = [
|
|
260
|
-
|
|
284
|
+
readable_shares = [
|
|
285
|
+
s
|
|
286
|
+
for s in parsed_data["shares"]
|
|
287
|
+
if s["readable"] and not s["writable"] and s["type"] == "Disk"
|
|
288
|
+
]
|
|
261
289
|
if readable_shares:
|
|
262
|
-
share_names =
|
|
263
|
-
findings.append(
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
290
|
+
share_names = ", ".join([s["name"] for s in readable_shares])
|
|
291
|
+
findings.append(
|
|
292
|
+
{
|
|
293
|
+
"title": "Readable SMB Shares Detected",
|
|
294
|
+
"severity": "medium",
|
|
295
|
+
"description": f"Found {len(readable_shares)} SMB share(s) with READ permissions: {share_names}. "
|
|
296
|
+
"These shares may contain sensitive information accessible without proper authentication.",
|
|
297
|
+
"evidence": "\n".join(
|
|
298
|
+
[
|
|
299
|
+
f"- {s['name']}: {s['permissions']} ({s['comment']})"
|
|
300
|
+
for s in readable_shares
|
|
301
|
+
]
|
|
302
|
+
),
|
|
303
|
+
}
|
|
304
|
+
)
|
|
273
305
|
|
|
274
306
|
# Finding 3: Anonymous access (MEDIUM severity)
|
|
275
|
-
if parsed_data.get(
|
|
276
|
-
accessible_shares = [
|
|
277
|
-
|
|
307
|
+
if parsed_data.get("status") in ["Guest", "Anonymous"]:
|
|
308
|
+
accessible_shares = [
|
|
309
|
+
s for s in parsed_data["shares"] if s["readable"] or s["writable"]
|
|
310
|
+
]
|
|
278
311
|
if accessible_shares:
|
|
279
|
-
findings.append(
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
312
|
+
findings.append(
|
|
313
|
+
{
|
|
314
|
+
"title": "Anonymous SMB Access Allowed",
|
|
315
|
+
"severity": "medium",
|
|
316
|
+
"description": f"Anonymous/guest access is permitted, allowing access to {len(accessible_shares)} share(s) "
|
|
317
|
+
"without authentication. This violates the principle of least privilege.",
|
|
318
|
+
"evidence": f"Authentication Status: {parsed_data.get('status')}\n"
|
|
319
|
+
+ "\n".join(
|
|
320
|
+
[
|
|
321
|
+
f"- {s['name']}: {s['permissions']}"
|
|
322
|
+
for s in accessible_shares
|
|
323
|
+
]
|
|
324
|
+
),
|
|
325
|
+
}
|
|
326
|
+
)
|
|
287
327
|
|
|
288
328
|
# Finding 4: Sensitive files exposed (if files were enumerated)
|
|
289
329
|
sensitive_patterns = [
|
|
290
|
-
(r
|
|
291
|
-
(r
|
|
292
|
-
(r
|
|
293
|
-
(r
|
|
294
|
-
(r
|
|
295
|
-
(r
|
|
330
|
+
(r"\.config$", "Configuration files"),
|
|
331
|
+
(r"password|passwd|pwd", "Password files"),
|
|
332
|
+
(r"\.key|\.pem|\.crt", "Cryptographic keys/certificates"),
|
|
333
|
+
(r"backup|\.bak|\.old", "Backup files"),
|
|
334
|
+
(r"\.sql|\.db|\.sqlite", "Database files"),
|
|
335
|
+
(r"id_rsa|id_dsa|\.ssh", "SSH private keys"),
|
|
296
336
|
]
|
|
297
337
|
|
|
298
338
|
for pattern, desc in sensitive_patterns:
|
|
299
|
-
matching_files = [
|
|
300
|
-
|
|
339
|
+
matching_files = [
|
|
340
|
+
f
|
|
341
|
+
for f in parsed_data["files"]
|
|
342
|
+
if re.search(pattern, f["path"], re.IGNORECASE)
|
|
343
|
+
]
|
|
301
344
|
if matching_files:
|
|
302
|
-
findings.append(
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
345
|
+
findings.append(
|
|
346
|
+
{
|
|
347
|
+
"title": f"Sensitive Files Exposed: {desc}",
|
|
348
|
+
"severity": "high",
|
|
349
|
+
"description": f"Found {len(matching_files)} potentially sensitive file(s) ({desc}) "
|
|
350
|
+
"accessible via SMB shares.",
|
|
351
|
+
"evidence": "\n".join(
|
|
352
|
+
[
|
|
353
|
+
f"- {f['share']}/{f['path']} ({f['size']} bytes)"
|
|
354
|
+
for f in matching_files[:10] # Limit to first 10
|
|
355
|
+
]
|
|
356
|
+
)
|
|
357
|
+
+ (
|
|
358
|
+
f"\n... and {len(matching_files) - 10} more"
|
|
359
|
+
if len(matching_files) > 10
|
|
360
|
+
else ""
|
|
361
|
+
),
|
|
362
|
+
}
|
|
363
|
+
)
|
|
312
364
|
|
|
313
365
|
# Finding 5: Info - All shares enumerated
|
|
314
|
-
if parsed_data[
|
|
315
|
-
findings.append(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
366
|
+
if parsed_data["shares"]:
|
|
367
|
+
findings.append(
|
|
368
|
+
{
|
|
369
|
+
"title": "SMB Share Enumeration Successful",
|
|
370
|
+
"severity": "info",
|
|
371
|
+
"description": f"Successfully enumerated {len(parsed_data['shares'])} SMB share(s) on target.",
|
|
372
|
+
"evidence": "\n".join(
|
|
373
|
+
[
|
|
374
|
+
f"- {s['name']} ({s['type']}): {s['permissions']}"
|
|
375
|
+
for s in parsed_data["shares"]
|
|
376
|
+
]
|
|
377
|
+
),
|
|
378
|
+
}
|
|
379
|
+
)
|
|
324
380
|
|
|
325
381
|
return findings
|