souleyez 2.43.26__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 +23434 -10286
- 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.26.dist-info → souleyez-2.43.34.dist-info}/METADATA +1 -1
- souleyez-2.43.34.dist-info/RECORD +443 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
- souleyez-2.43.26.dist-info/RECORD +0 -379
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
|
@@ -20,19 +20,13 @@ def parse_nuclei(log_path: str, target: str) -> Dict[str, Any]:
|
|
|
20
20
|
Dict containing parsed findings with severity breakdown
|
|
21
21
|
"""
|
|
22
22
|
findings = []
|
|
23
|
-
severity_counts = {
|
|
24
|
-
'critical': 0,
|
|
25
|
-
'high': 0,
|
|
26
|
-
'medium': 0,
|
|
27
|
-
'low': 0,
|
|
28
|
-
'info': 0
|
|
29
|
-
}
|
|
23
|
+
severity_counts = {"critical": 0, "high": 0, "medium": 0, "low": 0, "info": 0}
|
|
30
24
|
|
|
31
25
|
try:
|
|
32
|
-
with open(log_path,
|
|
26
|
+
with open(log_path, "r", encoding="utf-8") as f:
|
|
33
27
|
for line in f:
|
|
34
28
|
# Skip comment lines (metadata)
|
|
35
|
-
if line.startswith(
|
|
29
|
+
if line.startswith("#"):
|
|
36
30
|
continue
|
|
37
31
|
|
|
38
32
|
line = line.strip()
|
|
@@ -43,33 +37,35 @@ def parse_nuclei(log_path: str, target: str) -> Dict[str, Any]:
|
|
|
43
37
|
result = json.loads(line)
|
|
44
38
|
|
|
45
39
|
# Extract finding information
|
|
46
|
-
info = result.get(
|
|
47
|
-
severity = info.get(
|
|
40
|
+
info = result.get("info", {})
|
|
41
|
+
severity = info.get("severity", "info").lower()
|
|
48
42
|
|
|
49
43
|
finding = {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
44
|
+
"template_id": result.get(
|
|
45
|
+
"template-id", result.get("templateID")
|
|
46
|
+
),
|
|
47
|
+
"name": info.get("name"),
|
|
48
|
+
"severity": severity,
|
|
49
|
+
"description": info.get("description"),
|
|
50
|
+
"tags": info.get("tags", []),
|
|
51
|
+
"matched_at": result.get("matched-at", result.get("matched")),
|
|
52
|
+
"matcher_name": result.get("matcher-name"),
|
|
53
|
+
"extracted_results": result.get("extracted-results", []),
|
|
54
|
+
"curl_command": result.get("curl-command"),
|
|
55
|
+
"type": result.get("type"),
|
|
56
|
+
"host": result.get("host"),
|
|
57
|
+
"metadata": info.get("metadata", {}),
|
|
62
58
|
}
|
|
63
59
|
|
|
64
60
|
# Extract CVE ID if present
|
|
65
|
-
classification = info.get(
|
|
61
|
+
classification = info.get("classification", {})
|
|
66
62
|
if classification:
|
|
67
|
-
finding[
|
|
68
|
-
finding[
|
|
69
|
-
finding[
|
|
63
|
+
finding["cve_id"] = classification.get("cve-id")
|
|
64
|
+
finding["cvss_score"] = classification.get("cvss-score")
|
|
65
|
+
finding["cwe_id"] = classification.get("cwe-id")
|
|
70
66
|
|
|
71
67
|
# Extract reference links
|
|
72
|
-
finding[
|
|
68
|
+
finding["references"] = info.get("reference", [])
|
|
73
69
|
|
|
74
70
|
findings.append(finding)
|
|
75
71
|
severity_counts[severity] = severity_counts.get(severity, 0) + 1
|
|
@@ -80,24 +76,24 @@ def parse_nuclei(log_path: str, target: str) -> Dict[str, Any]:
|
|
|
80
76
|
|
|
81
77
|
except FileNotFoundError:
|
|
82
78
|
return {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
"tool": "nuclei",
|
|
80
|
+
"target": target,
|
|
81
|
+
"error": "Log file not found",
|
|
82
|
+
"findings_count": 0,
|
|
83
|
+
"findings": [],
|
|
88
84
|
}
|
|
89
85
|
|
|
90
86
|
return {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
"tool": "nuclei",
|
|
88
|
+
"target": target,
|
|
89
|
+
"findings_count": len(findings),
|
|
90
|
+
"critical": severity_counts["critical"],
|
|
91
|
+
"high": severity_counts["high"],
|
|
92
|
+
"medium": severity_counts["medium"],
|
|
93
|
+
"low": severity_counts["low"],
|
|
94
|
+
"info": severity_counts["info"],
|
|
95
|
+
"findings": findings,
|
|
96
|
+
"severity_breakdown": severity_counts,
|
|
101
97
|
}
|
|
102
98
|
|
|
103
99
|
|
|
@@ -113,7 +109,7 @@ def parse_nuclei_output(content: str, target: str) -> Dict[str, Any]:
|
|
|
113
109
|
Parsed nuclei data structure
|
|
114
110
|
"""
|
|
115
111
|
# Write content to temp file and call existing parse_nuclei
|
|
116
|
-
with tempfile.NamedTemporaryFile(mode=
|
|
112
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".log", delete=False) as f:
|
|
117
113
|
f.write(content)
|
|
118
114
|
temp_path = f.name
|
|
119
115
|
|
|
@@ -24,7 +24,7 @@ def parse_responder(log_path: str, interface: str) -> Dict:
|
|
|
24
24
|
hash_files = list(log_dir.glob("*NTLMv2*.txt"))
|
|
25
25
|
|
|
26
26
|
for hash_file in hash_files:
|
|
27
|
-
with open(hash_file,
|
|
27
|
+
with open(hash_file, "r") as f:
|
|
28
28
|
for line in f:
|
|
29
29
|
line = line.strip()
|
|
30
30
|
if not line or line.startswith("#"):
|
|
@@ -35,18 +35,18 @@ def parse_responder(log_path: str, interface: str) -> Dict:
|
|
|
35
35
|
credentials.append(cred)
|
|
36
36
|
|
|
37
37
|
return {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
"tool": "responder",
|
|
39
|
+
"interface": interface,
|
|
40
|
+
"credentials_captured": len(credentials),
|
|
41
|
+
"credentials": credentials,
|
|
42
|
+
"hash_files": [str(f) for f in hash_files],
|
|
43
|
+
"summary": f"Captured {len(credentials)} NTLMv2 hash(es) from {len(hash_files)} file(s)",
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def _parse_ntlmv2_hash(hash_line: str, filename: str) -> Dict:
|
|
48
48
|
"""Parse NTLMv2 hash line."""
|
|
49
|
-
protocol_match = re.match(r
|
|
49
|
+
protocol_match = re.match(r"([A-Z]+)-NTLMv2", filename)
|
|
50
50
|
protocol = protocol_match.group(1) if protocol_match else "Unknown"
|
|
51
51
|
|
|
52
52
|
parts = hash_line.split(":")
|
|
@@ -65,14 +65,14 @@ def _parse_ntlmv2_hash(hash_line: str, filename: str) -> Dict:
|
|
|
65
65
|
return None
|
|
66
66
|
|
|
67
67
|
return {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
"username": username,
|
|
69
|
+
"domain": domain,
|
|
70
|
+
"protocol": protocol,
|
|
71
|
+
"hash_type": "NTLMv2",
|
|
72
|
+
"hash": hash_line,
|
|
73
|
+
"challenge": challenge,
|
|
74
|
+
"response": response,
|
|
75
|
+
"source": "responder",
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
|
|
@@ -89,18 +89,18 @@ def store_responder_results(result: Dict, engagement_id: int, job_id: int):
|
|
|
89
89
|
|
|
90
90
|
cm = CredentialsManager(engagement_id)
|
|
91
91
|
|
|
92
|
-
for cred in result.get(
|
|
92
|
+
for cred in result.get("credentials", []):
|
|
93
93
|
cm.add_credential(
|
|
94
94
|
username=f"{cred['domain']}\\{cred['username']}",
|
|
95
|
-
password=cred[
|
|
96
|
-
service=cred[
|
|
95
|
+
password=cred["hash"],
|
|
96
|
+
service=cred["protocol"].lower(),
|
|
97
97
|
host=None,
|
|
98
|
-
status=
|
|
98
|
+
status="captured",
|
|
99
99
|
source=f'responder_{cred["protocol"]}',
|
|
100
|
-
notes=f"NTLMv2 hash captured via {cred['protocol']} poisoning"
|
|
100
|
+
notes=f"NTLMv2 hash captured via {cred['protocol']} poisoning",
|
|
101
101
|
)
|
|
102
102
|
|
|
103
|
-
if result[
|
|
103
|
+
if result["credentials_captured"] > 0:
|
|
104
104
|
from souleyez.storage.findings import FindingsManager
|
|
105
105
|
|
|
106
106
|
fm = FindingsManager()
|
|
@@ -108,8 +108,8 @@ def store_responder_results(result: Dict, engagement_id: int, job_id: int):
|
|
|
108
108
|
engagement_id=engagement_id,
|
|
109
109
|
title=f"LLMNR/NBT-NS Poisoning - {result['credentials_captured']} Credential(s) Captured",
|
|
110
110
|
description=f"Responder successfully captured {result['credentials_captured']} NTLMv2 hash(es) "
|
|
111
|
-
|
|
112
|
-
severity=
|
|
113
|
-
tool=
|
|
114
|
-
evidence=result[
|
|
111
|
+
f"via LLMNR/NBT-NS poisoning. These hashes can be cracked offline.",
|
|
112
|
+
severity="high",
|
|
113
|
+
tool="responder",
|
|
114
|
+
evidence=result["summary"],
|
|
115
115
|
)
|
|
@@ -17,15 +17,15 @@ def _load_exploitdb_csv() -> Dict[str, Dict[str, str]]:
|
|
|
17
17
|
Dict mapping EDB-ID to exploit metadata (platform, type, date_published)
|
|
18
18
|
"""
|
|
19
19
|
csv_paths = [
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
"/usr/share/exploitdb/files_exploits.csv",
|
|
21
|
+
"/usr/share/exploitdb/files.csv",
|
|
22
22
|
]
|
|
23
23
|
|
|
24
24
|
for csv_path in csv_paths:
|
|
25
25
|
if Path(csv_path).exists():
|
|
26
26
|
try:
|
|
27
27
|
exploits_db = {}
|
|
28
|
-
with open(csv_path,
|
|
28
|
+
with open(csv_path, "r", encoding="utf-8", errors="replace") as f:
|
|
29
29
|
reader = csv.reader(f)
|
|
30
30
|
next(reader) # Skip header
|
|
31
31
|
|
|
@@ -35,9 +35,9 @@ def _load_exploitdb_csv() -> Dict[str, Dict[str, str]]:
|
|
|
35
35
|
|
|
36
36
|
edb_id = row[0]
|
|
37
37
|
exploits_db[edb_id] = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
"platform": row[6] if len(row) > 6 else "",
|
|
39
|
+
"type": row[5] if len(row) > 5 else "",
|
|
40
|
+
"date_published": row[3] if len(row) > 3 else "",
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
return exploits_db
|
|
@@ -61,11 +61,11 @@ def _extract_edb_id(url: str) -> Optional[str]:
|
|
|
61
61
|
if not url:
|
|
62
62
|
return None
|
|
63
63
|
|
|
64
|
-
match = re.search(r
|
|
64
|
+
match = re.search(r"/exploits/(\d+)/?$", url)
|
|
65
65
|
if match:
|
|
66
66
|
return match.group(1)
|
|
67
67
|
|
|
68
|
-
match = re.search(r
|
|
68
|
+
match = re.search(r"/shellcodes/(\d+)/?$", url)
|
|
69
69
|
if match:
|
|
70
70
|
return match.group(1)
|
|
71
71
|
|
|
@@ -89,18 +89,18 @@ def parse_searchsploit(log_path: str, target: str) -> Dict[str, Any]:
|
|
|
89
89
|
# Load exploitdb CSV database once for all exploits
|
|
90
90
|
exploits_db = _load_exploitdb_csv()
|
|
91
91
|
|
|
92
|
-
with open(log_path,
|
|
92
|
+
with open(log_path, "r", encoding="utf-8") as f:
|
|
93
93
|
content = f.read()
|
|
94
94
|
|
|
95
95
|
# Find JSON content (skip metadata header)
|
|
96
|
-
json_start = content.find(
|
|
96
|
+
json_start = content.find("{")
|
|
97
97
|
if json_start == -1:
|
|
98
98
|
return {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
"tool": "searchsploit",
|
|
100
|
+
"target": target,
|
|
101
|
+
"exploit_count": 0,
|
|
102
|
+
"exploits": [],
|
|
103
|
+
"error": "No JSON output found",
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
json_content = content[json_start:]
|
|
@@ -111,9 +111,9 @@ def parse_searchsploit(log_path: str, target: str) -> Dict[str, Any]:
|
|
|
111
111
|
bracket_count = 0
|
|
112
112
|
json_end = 0
|
|
113
113
|
for i, char in enumerate(json_content):
|
|
114
|
-
if char ==
|
|
114
|
+
if char == "{":
|
|
115
115
|
bracket_count += 1
|
|
116
|
-
elif char ==
|
|
116
|
+
elif char == "}":
|
|
117
117
|
bracket_count -= 1
|
|
118
118
|
if bracket_count == 0:
|
|
119
119
|
json_end = i + 1
|
|
@@ -128,105 +128,105 @@ def parse_searchsploit(log_path: str, target: str) -> Dict[str, Any]:
|
|
|
128
128
|
data = json.loads(json_content)
|
|
129
129
|
|
|
130
130
|
# Parse results
|
|
131
|
-
for result in data.get(
|
|
131
|
+
for result in data.get("RESULTS_EXPLOIT", []):
|
|
132
132
|
# searchsploit --json provides these fields directly
|
|
133
|
-
edb_id = result.get(
|
|
133
|
+
edb_id = result.get("EDB-ID", "")
|
|
134
134
|
|
|
135
135
|
# URL may be provided or we construct it from EDB-ID
|
|
136
|
-
url = result.get(
|
|
136
|
+
url = result.get("URL", "")
|
|
137
137
|
if not url and edb_id:
|
|
138
|
-
url = f
|
|
138
|
+
url = f"https://www.exploit-db.com/exploits/{edb_id}"
|
|
139
139
|
|
|
140
140
|
# If EDB-ID not in result, try extracting from URL
|
|
141
141
|
if not edb_id:
|
|
142
|
-
edb_id = _extract_edb_id(url) or
|
|
142
|
+
edb_id = _extract_edb_id(url) or ""
|
|
143
143
|
|
|
144
144
|
# Get metadata directly from result (newer searchsploit format)
|
|
145
145
|
# Fall back to CSV lookup if not present
|
|
146
|
-
date = result.get(
|
|
147
|
-
platform = result.get(
|
|
148
|
-
exploit_type = result.get(
|
|
146
|
+
date = result.get("Date_Published", result.get("Date_Added", ""))
|
|
147
|
+
platform = result.get("Platform", "")
|
|
148
|
+
exploit_type = result.get("Type", "")
|
|
149
149
|
|
|
150
150
|
# If metadata not in result, look up from CSV database
|
|
151
151
|
if not (date or platform or exploit_type):
|
|
152
152
|
metadata = exploits_db.get(str(edb_id), {}) if edb_id else {}
|
|
153
|
-
date = date or metadata.get(
|
|
154
|
-
platform = platform or metadata.get(
|
|
155
|
-
exploit_type = exploit_type or metadata.get(
|
|
153
|
+
date = date or metadata.get("date_published", "")
|
|
154
|
+
platform = platform or metadata.get("platform", "")
|
|
155
|
+
exploit_type = exploit_type or metadata.get("type", "")
|
|
156
156
|
|
|
157
157
|
exploit = {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
158
|
+
"title": result.get("Title", ""),
|
|
159
|
+
"path": result.get("Path", ""),
|
|
160
|
+
"edb_id": str(edb_id),
|
|
161
|
+
"date": date,
|
|
162
|
+
"platform": platform,
|
|
163
|
+
"type": exploit_type,
|
|
164
|
+
"url": url,
|
|
165
|
+
"verified": result.get("Verified", "0") == "1",
|
|
166
|
+
"codes": result.get("Codes", ""), # CVE codes
|
|
167
167
|
}
|
|
168
168
|
exploits.append(exploit)
|
|
169
169
|
|
|
170
170
|
# Also check for shellcode results
|
|
171
|
-
for result in data.get(
|
|
172
|
-
edb_id = result.get(
|
|
173
|
-
url = result.get(
|
|
171
|
+
for result in data.get("RESULTS_SHELLCODE", []):
|
|
172
|
+
edb_id = result.get("EDB-ID", "")
|
|
173
|
+
url = result.get("URL", "")
|
|
174
174
|
if not url and edb_id:
|
|
175
|
-
url = f
|
|
175
|
+
url = f"https://www.exploit-db.com/shellcodes/{edb_id}"
|
|
176
176
|
|
|
177
177
|
if not edb_id:
|
|
178
|
-
edb_id = _extract_edb_id(url) or
|
|
178
|
+
edb_id = _extract_edb_id(url) or ""
|
|
179
179
|
|
|
180
|
-
date = result.get(
|
|
181
|
-
platform = result.get(
|
|
180
|
+
date = result.get("Date_Published", result.get("Date_Added", ""))
|
|
181
|
+
platform = result.get("Platform", "")
|
|
182
182
|
|
|
183
183
|
# Look up metadata from CSV database if not in result
|
|
184
184
|
if not (date or platform):
|
|
185
185
|
metadata = exploits_db.get(str(edb_id), {}) if edb_id else {}
|
|
186
|
-
date = date or metadata.get(
|
|
187
|
-
platform = platform or metadata.get(
|
|
186
|
+
date = date or metadata.get("date_published", "")
|
|
187
|
+
platform = platform or metadata.get("platform", "")
|
|
188
188
|
|
|
189
189
|
exploit = {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
190
|
+
"title": result.get("Title", ""),
|
|
191
|
+
"path": result.get("Path", ""),
|
|
192
|
+
"edb_id": str(edb_id),
|
|
193
|
+
"date": date,
|
|
194
|
+
"platform": platform,
|
|
195
|
+
"type": "shellcode",
|
|
196
|
+
"url": url,
|
|
197
|
+
"verified": result.get("Verified", "0") == "1",
|
|
198
|
+
"codes": result.get("Codes", ""),
|
|
199
199
|
}
|
|
200
200
|
exploits.append(exploit)
|
|
201
201
|
|
|
202
202
|
except FileNotFoundError:
|
|
203
203
|
return {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
204
|
+
"tool": "searchsploit",
|
|
205
|
+
"target": target,
|
|
206
|
+
"error": "Log file not found",
|
|
207
|
+
"exploit_count": 0,
|
|
208
|
+
"exploits": [],
|
|
209
209
|
}
|
|
210
210
|
except json.JSONDecodeError as e:
|
|
211
211
|
return {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
212
|
+
"tool": "searchsploit",
|
|
213
|
+
"target": target,
|
|
214
|
+
"error": f"JSON parse error: {e}",
|
|
215
|
+
"exploit_count": 0,
|
|
216
|
+
"exploits": [],
|
|
217
217
|
}
|
|
218
218
|
except Exception as e:
|
|
219
219
|
return {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
220
|
+
"tool": "searchsploit",
|
|
221
|
+
"target": target,
|
|
222
|
+
"error": f"Parse error: {e}",
|
|
223
|
+
"exploit_count": 0,
|
|
224
|
+
"exploits": [],
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
return {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
228
|
+
"tool": "searchsploit",
|
|
229
|
+
"target": target,
|
|
230
|
+
"exploit_count": len(exploits),
|
|
231
|
+
"exploits": exploits,
|
|
232
232
|
}
|