souleyez 2.43.29__py3-none-any.whl → 3.0.0__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.
- 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 +9564 -2881
- 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 +564 -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 +409 -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 +417 -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 +913 -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 +219 -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 +237 -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 +23034 -10679
- 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-3.0.0.dist-info}/METADATA +2 -2
- souleyez-3.0.0.dist-info/RECORD +443 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/WHEEL +1 -1
- souleyez-2.43.29.dist-info/RECORD +0 -379
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/top_level.txt +0 -0
|
@@ -50,20 +50,15 @@ def parse_dalfox_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
50
50
|
}
|
|
51
51
|
"""
|
|
52
52
|
result = {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
'total_vulns': 0,
|
|
60
|
-
'reflected': 0,
|
|
61
|
-
'dom': 0,
|
|
62
|
-
'parameters_found': 0
|
|
63
|
-
}
|
|
53
|
+
"target": target,
|
|
54
|
+
"vulnerabilities": [],
|
|
55
|
+
"parameters": [],
|
|
56
|
+
"warnings": [],
|
|
57
|
+
"info": [],
|
|
58
|
+
"stats": {"total_vulns": 0, "reflected": 0, "dom": 0, "parameters_found": 0},
|
|
64
59
|
}
|
|
65
60
|
|
|
66
|
-
lines = output.split(
|
|
61
|
+
lines = output.split("\n")
|
|
67
62
|
|
|
68
63
|
for line in lines:
|
|
69
64
|
line = line.strip()
|
|
@@ -71,7 +66,7 @@ def parse_dalfox_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
71
66
|
continue
|
|
72
67
|
|
|
73
68
|
# Try JSON parsing first
|
|
74
|
-
if line.startswith(
|
|
69
|
+
if line.startswith("{"):
|
|
75
70
|
try:
|
|
76
71
|
data = json.loads(line)
|
|
77
72
|
_process_json_line(data, result)
|
|
@@ -83,139 +78,139 @@ def parse_dalfox_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
83
78
|
_process_text_line(line, result)
|
|
84
79
|
|
|
85
80
|
# Update stats
|
|
86
|
-
result[
|
|
87
|
-
result[
|
|
81
|
+
result["stats"]["total_vulns"] = len(result["vulnerabilities"])
|
|
82
|
+
result["stats"]["parameters_found"] = len(result["parameters"])
|
|
88
83
|
|
|
89
84
|
return result
|
|
90
85
|
|
|
91
86
|
|
|
92
87
|
def _process_json_line(data: Dict, result: Dict):
|
|
93
88
|
"""Process a JSON-formatted line from Dalfox."""
|
|
94
|
-
msg_type = data.get(
|
|
95
|
-
msg_data = data.get(
|
|
96
|
-
poc = data.get(
|
|
97
|
-
cwe = data.get(
|
|
89
|
+
msg_type = data.get("type", "")
|
|
90
|
+
msg_data = data.get("data", "")
|
|
91
|
+
poc = data.get("poc", "")
|
|
92
|
+
cwe = data.get("cwe", "")
|
|
98
93
|
|
|
99
|
-
if msg_type ==
|
|
94
|
+
if msg_type == "V":
|
|
100
95
|
# Vulnerability found
|
|
101
96
|
vuln = {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
97
|
+
"type": _detect_xss_type(msg_data),
|
|
98
|
+
"parameter": _extract_parameter(poc or msg_data),
|
|
99
|
+
"payload": _extract_payload(poc or msg_data),
|
|
100
|
+
"poc": poc,
|
|
101
|
+
"cwe": cwe,
|
|
102
|
+
"raw": msg_data,
|
|
108
103
|
}
|
|
109
|
-
result[
|
|
104
|
+
result["vulnerabilities"].append(vuln)
|
|
110
105
|
|
|
111
|
-
if
|
|
112
|
-
result[
|
|
106
|
+
if "dom" in msg_data.lower():
|
|
107
|
+
result["stats"]["dom"] += 1
|
|
113
108
|
else:
|
|
114
|
-
result[
|
|
109
|
+
result["stats"]["reflected"] += 1
|
|
115
110
|
|
|
116
|
-
elif msg_type ==
|
|
117
|
-
result[
|
|
111
|
+
elif msg_type == "I":
|
|
112
|
+
result["info"].append(msg_data)
|
|
118
113
|
# Check for parameter discovery
|
|
119
114
|
param = _extract_discovered_param(msg_data)
|
|
120
|
-
if param and param not in result[
|
|
121
|
-
result[
|
|
115
|
+
if param and param not in result["parameters"]:
|
|
116
|
+
result["parameters"].append(param)
|
|
122
117
|
|
|
123
|
-
elif msg_type ==
|
|
124
|
-
result[
|
|
118
|
+
elif msg_type == "W":
|
|
119
|
+
result["warnings"].append(msg_data)
|
|
125
120
|
|
|
126
121
|
|
|
127
122
|
def _process_text_line(line: str, result: Dict):
|
|
128
123
|
"""Process a text-formatted line from Dalfox."""
|
|
129
124
|
|
|
130
125
|
# Vulnerability line: [V] or [POC]
|
|
131
|
-
if line.startswith(
|
|
126
|
+
if line.startswith("[V]") or "Vulnerable" in line:
|
|
132
127
|
vuln = {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
128
|
+
"type": _detect_xss_type(line),
|
|
129
|
+
"parameter": _extract_parameter(line),
|
|
130
|
+
"payload": _extract_payload(line),
|
|
131
|
+
"poc": "",
|
|
132
|
+
"cwe": "CWE-79",
|
|
133
|
+
"raw": line,
|
|
139
134
|
}
|
|
140
|
-
result[
|
|
135
|
+
result["vulnerabilities"].append(vuln)
|
|
141
136
|
|
|
142
|
-
if
|
|
143
|
-
result[
|
|
137
|
+
if "dom" in line.lower():
|
|
138
|
+
result["stats"]["dom"] += 1
|
|
144
139
|
else:
|
|
145
|
-
result[
|
|
140
|
+
result["stats"]["reflected"] += 1
|
|
146
141
|
|
|
147
|
-
elif line.startswith(
|
|
142
|
+
elif line.startswith("[POC]"):
|
|
148
143
|
# Add POC to last vulnerability
|
|
149
|
-
poc = line.replace(
|
|
150
|
-
if result[
|
|
151
|
-
result[
|
|
144
|
+
poc = line.replace("[POC]", "").strip()
|
|
145
|
+
if result["vulnerabilities"]:
|
|
146
|
+
result["vulnerabilities"][-1]["poc"] = poc
|
|
152
147
|
|
|
153
|
-
elif line.startswith(
|
|
154
|
-
result[
|
|
148
|
+
elif line.startswith("[I]") or "Found parameter" in line:
|
|
149
|
+
result["info"].append(line)
|
|
155
150
|
param = _extract_discovered_param(line)
|
|
156
|
-
if param and param not in result[
|
|
157
|
-
result[
|
|
151
|
+
if param and param not in result["parameters"]:
|
|
152
|
+
result["parameters"].append(param)
|
|
158
153
|
|
|
159
|
-
elif line.startswith(
|
|
160
|
-
result[
|
|
154
|
+
elif line.startswith("[W]") or "WAF" in line:
|
|
155
|
+
result["warnings"].append(line)
|
|
161
156
|
|
|
162
157
|
|
|
163
158
|
def _detect_xss_type(text: str) -> str:
|
|
164
159
|
"""Detect the type of XSS from the message."""
|
|
165
160
|
text_lower = text.lower()
|
|
166
|
-
if
|
|
167
|
-
return
|
|
168
|
-
elif
|
|
169
|
-
return
|
|
161
|
+
if "dom" in text_lower:
|
|
162
|
+
return "dom"
|
|
163
|
+
elif "stored" in text_lower:
|
|
164
|
+
return "stored"
|
|
170
165
|
else:
|
|
171
|
-
return
|
|
166
|
+
return "reflected"
|
|
172
167
|
|
|
173
168
|
|
|
174
169
|
def _extract_parameter(text: str) -> str:
|
|
175
170
|
"""Extract the vulnerable parameter name from text."""
|
|
176
171
|
# Look for common patterns like ?param=, ¶m=
|
|
177
|
-
match = re.search(r
|
|
172
|
+
match = re.search(r"[?&]([a-zA-Z0-9_-]+)=", text)
|
|
178
173
|
if match:
|
|
179
174
|
return match.group(1)
|
|
180
|
-
return
|
|
175
|
+
return ""
|
|
181
176
|
|
|
182
177
|
|
|
183
178
|
def _extract_payload(text: str) -> str:
|
|
184
179
|
"""Extract the XSS payload from text."""
|
|
185
180
|
# Look for script tags or event handlers
|
|
186
181
|
patterns = [
|
|
187
|
-
r
|
|
188
|
-
r
|
|
189
|
-
r
|
|
182
|
+
r"(<script[^>]*>.*?</script>)",
|
|
183
|
+
r"(<img[^>]*onerror[^>]*>)",
|
|
184
|
+
r"(<svg[^>]*onload[^>]*>)",
|
|
190
185
|
r'(javascript:[^\s"\']+)',
|
|
191
|
-
r
|
|
186
|
+
r"(%3C[^%]*%3E)", # URL encoded
|
|
192
187
|
]
|
|
193
188
|
for pattern in patterns:
|
|
194
189
|
match = re.search(pattern, text, re.IGNORECASE)
|
|
195
190
|
if match:
|
|
196
191
|
return match.group(1)
|
|
197
|
-
return
|
|
192
|
+
return ""
|
|
198
193
|
|
|
199
194
|
|
|
200
195
|
def _extract_discovered_param(text: str) -> str:
|
|
201
196
|
"""Extract discovered parameter name from info message."""
|
|
202
197
|
# Patterns like "Found parameter: q" or "parameter q"
|
|
203
198
|
patterns = [
|
|
204
|
-
r
|
|
205
|
-
r
|
|
199
|
+
r"parameter[:\s]+([a-zA-Z0-9_-]+)",
|
|
200
|
+
r"param[:\s]+([a-zA-Z0-9_-]+)",
|
|
206
201
|
]
|
|
207
202
|
for pattern in patterns:
|
|
208
203
|
match = re.search(pattern, text, re.IGNORECASE)
|
|
209
204
|
if match:
|
|
210
205
|
return match.group(1)
|
|
211
|
-
return
|
|
206
|
+
return ""
|
|
212
207
|
|
|
213
208
|
|
|
214
209
|
def get_vulnerable_parameters(parsed: Dict[str, Any]) -> List[str]:
|
|
215
210
|
"""Get list of parameters that have XSS vulnerabilities."""
|
|
216
211
|
params = set()
|
|
217
|
-
for vuln in parsed.get(
|
|
218
|
-
param = vuln.get(
|
|
212
|
+
for vuln in parsed.get("vulnerabilities", []):
|
|
213
|
+
param = vuln.get("parameter")
|
|
219
214
|
if param:
|
|
220
215
|
params.add(param)
|
|
221
216
|
return list(params)
|
|
@@ -224,8 +219,8 @@ def get_vulnerable_parameters(parsed: Dict[str, Any]) -> List[str]:
|
|
|
224
219
|
def get_pocs(parsed: Dict[str, Any]) -> List[str]:
|
|
225
220
|
"""Get list of proof-of-concept URLs."""
|
|
226
221
|
pocs = []
|
|
227
|
-
for vuln in parsed.get(
|
|
228
|
-
poc = vuln.get(
|
|
222
|
+
for vuln in parsed.get("vulnerabilities", []):
|
|
223
|
+
poc = vuln.get("poc")
|
|
229
224
|
if poc:
|
|
230
225
|
pocs.append(poc)
|
|
231
226
|
return pocs
|
|
@@ -233,4 +228,4 @@ def get_pocs(parsed: Dict[str, Any]) -> List[str]:
|
|
|
233
228
|
|
|
234
229
|
def has_critical_findings(parsed: Dict[str, Any]) -> bool:
|
|
235
230
|
"""Check if there are any XSS vulnerabilities (always critical)."""
|
|
236
|
-
return len(parsed.get(
|
|
231
|
+
return len(parsed.get("vulnerabilities", [])) > 0
|
|
@@ -36,16 +36,16 @@ def parse_dnsrecon_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
36
36
|
}
|
|
37
37
|
"""
|
|
38
38
|
result = {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
"target_domain": target,
|
|
40
|
+
"hosts": [],
|
|
41
|
+
"nameservers": [],
|
|
42
|
+
"mail_servers": [],
|
|
43
|
+
"txt_records": [],
|
|
44
|
+
"subdomains": [],
|
|
45
|
+
"count": 0,
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
lines = output.split(
|
|
48
|
+
lines = output.split("\n")
|
|
49
49
|
seen_hosts = set()
|
|
50
50
|
seen_subdomains = set()
|
|
51
51
|
|
|
@@ -53,7 +53,7 @@ def parse_dnsrecon_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
53
53
|
line_stripped = line.strip()
|
|
54
54
|
|
|
55
55
|
# Skip empty lines and headers
|
|
56
|
-
if not line_stripped or line_stripped.startswith(
|
|
56
|
+
if not line_stripped or line_stripped.startswith("[-]"):
|
|
57
57
|
continue
|
|
58
58
|
|
|
59
59
|
# Parse DNS records from dnsrecon output
|
|
@@ -66,77 +66,79 @@ def parse_dnsrecon_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
66
66
|
hostname = None
|
|
67
67
|
ip = None
|
|
68
68
|
|
|
69
|
-
if line_stripped.startswith(
|
|
69
|
+
if line_stripped.startswith("[*]") or line_stripped.startswith("[+]"):
|
|
70
70
|
# Format: [*] or [+] <type> <hostname> <ip>
|
|
71
71
|
# [*] = informational, [+] = found/success
|
|
72
72
|
parts = line_stripped.split()
|
|
73
73
|
if len(parts) >= 4:
|
|
74
74
|
record_type = parts[1]
|
|
75
75
|
hostname = parts[2].lower()
|
|
76
|
-
ip = parts[3] if len(parts) > 3 else
|
|
77
|
-
elif
|
|
76
|
+
ip = parts[3] if len(parts) > 3 else ""
|
|
77
|
+
elif " INFO " in line_stripped:
|
|
78
78
|
# New format: TIMESTAMP INFO <type> <hostname> <ip>
|
|
79
79
|
# Split on INFO and parse the rest
|
|
80
|
-
info_idx = line_stripped.find(
|
|
80
|
+
info_idx = line_stripped.find(" INFO ")
|
|
81
81
|
if info_idx != -1:
|
|
82
|
-
record_part = line_stripped[info_idx + 6:].strip()
|
|
82
|
+
record_part = line_stripped[info_idx + 6 :].strip()
|
|
83
83
|
parts = record_part.split()
|
|
84
84
|
if len(parts) >= 3:
|
|
85
85
|
record_type = parts[0]
|
|
86
86
|
hostname = parts[1].lower()
|
|
87
|
-
ip = parts[2] if len(parts) > 2 else
|
|
87
|
+
ip = parts[2] if len(parts) > 2 else ""
|
|
88
88
|
|
|
89
89
|
if record_type and hostname:
|
|
90
90
|
# Validate IP (both IPv4 and basic IPv6)
|
|
91
|
-
is_ipv4 =
|
|
91
|
+
is_ipv4 = (
|
|
92
|
+
re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", ip) if ip else False
|
|
93
|
+
)
|
|
92
94
|
|
|
93
|
-
if record_type ==
|
|
95
|
+
if record_type == "A" and is_ipv4:
|
|
94
96
|
if hostname not in seen_hosts:
|
|
95
97
|
seen_hosts.add(hostname)
|
|
96
|
-
result[
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
'type': 'A'
|
|
100
|
-
})
|
|
98
|
+
result["hosts"].append(
|
|
99
|
+
{"hostname": hostname, "ip": ip, "type": "A"}
|
|
100
|
+
)
|
|
101
101
|
if hostname != target and hostname not in seen_subdomains:
|
|
102
102
|
seen_subdomains.add(hostname)
|
|
103
|
-
result[
|
|
103
|
+
result["subdomains"].append(hostname)
|
|
104
104
|
|
|
105
|
-
elif record_type ==
|
|
106
|
-
if hostname not in result[
|
|
107
|
-
result[
|
|
105
|
+
elif record_type == "NS":
|
|
106
|
+
if hostname not in result["nameservers"]:
|
|
107
|
+
result["nameservers"].append(hostname)
|
|
108
108
|
|
|
109
|
-
elif record_type ==
|
|
110
|
-
if hostname not in result[
|
|
111
|
-
result[
|
|
109
|
+
elif record_type == "MX":
|
|
110
|
+
if hostname not in result["mail_servers"]:
|
|
111
|
+
result["mail_servers"].append(hostname)
|
|
112
112
|
|
|
113
|
-
elif record_type ==
|
|
113
|
+
elif record_type == "SOA":
|
|
114
114
|
# SOA records can also be nameservers
|
|
115
|
-
if hostname not in result[
|
|
116
|
-
result[
|
|
115
|
+
if hostname not in result["nameservers"]:
|
|
116
|
+
result["nameservers"].append(hostname)
|
|
117
117
|
|
|
118
118
|
# Parse subdomain brute force results: [*] Subdomain: api.example.com IP: 1.2.3.4
|
|
119
|
-
subdomain_match = re.search(
|
|
119
|
+
subdomain_match = re.search(
|
|
120
|
+
r"Subdomain:\s+(\S+)\s+IP:\s+(\d+\.\d+\.\d+\.\d+)", line_stripped
|
|
121
|
+
)
|
|
120
122
|
if subdomain_match:
|
|
121
123
|
hostname = subdomain_match.group(1).lower()
|
|
122
124
|
ip = subdomain_match.group(2)
|
|
123
125
|
if hostname not in seen_hosts:
|
|
124
126
|
seen_hosts.add(hostname)
|
|
125
|
-
result[
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
'type': 'Subdomain'
|
|
129
|
-
})
|
|
127
|
+
result["hosts"].append(
|
|
128
|
+
{"hostname": hostname, "ip": ip, "type": "Subdomain"}
|
|
129
|
+
)
|
|
130
130
|
if hostname not in seen_subdomains:
|
|
131
131
|
seen_subdomains.add(hostname)
|
|
132
|
-
result[
|
|
132
|
+
result["subdomains"].append(hostname)
|
|
133
133
|
|
|
134
|
-
result[
|
|
134
|
+
result["count"] = len(result["hosts"])
|
|
135
135
|
|
|
136
136
|
return result
|
|
137
137
|
|
|
138
138
|
|
|
139
|
-
def map_to_hosts(
|
|
139
|
+
def map_to_hosts(
|
|
140
|
+
parsed_data: Dict[str, Any], engagement_id: int
|
|
141
|
+
) -> List[Dict[str, Any]]:
|
|
140
142
|
"""
|
|
141
143
|
Convert parsed DNSRecon data into host records for database storage.
|
|
142
144
|
|
|
@@ -151,26 +153,28 @@ def map_to_hosts(parsed_data: Dict[str, Any], engagement_id: int) -> List[Dict[s
|
|
|
151
153
|
"""
|
|
152
154
|
hosts = []
|
|
153
155
|
|
|
154
|
-
for host_data in parsed_data.get(
|
|
155
|
-
hostname = host_data.get(
|
|
156
|
-
ip = host_data.get(
|
|
157
|
-
record_type = host_data.get(
|
|
156
|
+
for host_data in parsed_data.get("hosts", []):
|
|
157
|
+
hostname = host_data.get("hostname", "")
|
|
158
|
+
ip = host_data.get("ip", "")
|
|
159
|
+
record_type = host_data.get("type", "Unknown")
|
|
158
160
|
|
|
159
161
|
host = {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
162
|
+
"ip_address": ip,
|
|
163
|
+
"hostname": hostname,
|
|
164
|
+
"os_name": "Unknown",
|
|
165
|
+
"status": "up",
|
|
166
|
+
"notes": f"Discovered by dnsrecon ({record_type} record) for domain: {parsed_data.get('target_domain', '')}",
|
|
167
|
+
"tags": ["dns", "dnsrecon", record_type.lower()],
|
|
168
|
+
"source": "dnsrecon",
|
|
167
169
|
}
|
|
168
170
|
hosts.append(host)
|
|
169
171
|
|
|
170
172
|
return hosts
|
|
171
173
|
|
|
172
174
|
|
|
173
|
-
def map_to_osint(
|
|
175
|
+
def map_to_osint(
|
|
176
|
+
parsed_data: Dict[str, Any], engagement_id: int, job_id: int = None
|
|
177
|
+
) -> List[Dict[str, Any]]:
|
|
174
178
|
"""
|
|
175
179
|
Convert parsed DNSRecon data into OSINT records for database storage.
|
|
176
180
|
|
|
@@ -185,54 +189,62 @@ def map_to_osint(parsed_data: Dict[str, Any], engagement_id: int, job_id: int =
|
|
|
185
189
|
List of OSINT dicts ready for storage
|
|
186
190
|
"""
|
|
187
191
|
osint_records = []
|
|
188
|
-
target = parsed_data.get(
|
|
192
|
+
target = parsed_data.get("target_domain", "unknown")
|
|
189
193
|
|
|
190
194
|
# Add nameservers
|
|
191
|
-
for ns in parsed_data.get(
|
|
192
|
-
osint_records.append(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
195
|
+
for ns in parsed_data.get("nameservers", []):
|
|
196
|
+
osint_records.append(
|
|
197
|
+
{
|
|
198
|
+
"data_type": "nameserver",
|
|
199
|
+
"value": ns,
|
|
200
|
+
"source": "dnsrecon",
|
|
201
|
+
"engagement_id": engagement_id,
|
|
202
|
+
"job_id": job_id,
|
|
203
|
+
"notes": f"Nameserver for {target}",
|
|
204
|
+
}
|
|
205
|
+
)
|
|
200
206
|
|
|
201
207
|
# Add mail servers
|
|
202
|
-
for mx in parsed_data.get(
|
|
203
|
-
osint_records.append(
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
for mx in parsed_data.get("mail_servers", []):
|
|
209
|
+
osint_records.append(
|
|
210
|
+
{
|
|
211
|
+
"data_type": "mail_server",
|
|
212
|
+
"value": mx,
|
|
213
|
+
"source": "dnsrecon",
|
|
214
|
+
"engagement_id": engagement_id,
|
|
215
|
+
"job_id": job_id,
|
|
216
|
+
"notes": f"Mail server for {target}",
|
|
217
|
+
}
|
|
218
|
+
)
|
|
211
219
|
|
|
212
220
|
# Add TXT records (often contain SPF, DKIM, DMARC, verification codes)
|
|
213
|
-
for txt in parsed_data.get(
|
|
214
|
-
osint_records.append(
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
221
|
+
for txt in parsed_data.get("txt_records", []):
|
|
222
|
+
osint_records.append(
|
|
223
|
+
{
|
|
224
|
+
"data_type": "txt_record",
|
|
225
|
+
"value": txt[:500], # Limit length
|
|
226
|
+
"source": "dnsrecon",
|
|
227
|
+
"engagement_id": engagement_id,
|
|
228
|
+
"job_id": job_id,
|
|
229
|
+
"notes": f"TXT record for {target}",
|
|
230
|
+
}
|
|
231
|
+
)
|
|
222
232
|
|
|
223
233
|
# Add subdomains as hosts
|
|
224
|
-
for subdomain in parsed_data.get(
|
|
225
|
-
osint_records.append(
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
234
|
+
for subdomain in parsed_data.get("subdomains", []):
|
|
235
|
+
osint_records.append(
|
|
236
|
+
{
|
|
237
|
+
"data_type": "host",
|
|
238
|
+
"value": subdomain,
|
|
239
|
+
"source": "dnsrecon",
|
|
240
|
+
"engagement_id": engagement_id,
|
|
241
|
+
"job_id": job_id,
|
|
242
|
+
"notes": f"Subdomain of {target}",
|
|
243
|
+
}
|
|
244
|
+
)
|
|
233
245
|
|
|
234
246
|
return osint_records
|
|
235
247
|
|
|
236
248
|
|
|
237
249
|
# Export the main functions
|
|
238
|
-
__all__ = [
|
|
250
|
+
__all__ = ["parse_dnsrecon_output", "map_to_hosts", "map_to_osint"]
|