souleyez 2.43.34__py3-none-any.whl → 3.0.7__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 -1
- souleyez/ai/__init__.py +7 -7
- souleyez/ai/action_mapper.py +3 -2
- souleyez/ai/chain_advisor.py +2 -1
- souleyez/ai/claude_provider.py +2 -2
- souleyez/ai/context_builder.py +4 -2
- souleyez/ai/executor.py +9 -6
- souleyez/ai/feedback_handler.py +4 -2
- souleyez/ai/llm_provider.py +2 -2
- souleyez/ai/ollama_provider.py +2 -2
- souleyez/ai/ollama_service.py +10 -26
- souleyez/ai/path_scorer.py +2 -1
- souleyez/ai/recommender.py +6 -4
- souleyez/ai/report_context.py +2 -2
- souleyez/ai/report_service.py +5 -5
- souleyez/ai/result_parser.py +3 -2
- souleyez/ai/safety.py +5 -2
- souleyez/auth/__init__.py +6 -6
- souleyez/auth/audit.py +2 -2
- souleyez/auth/engagement_access.py +5 -7
- souleyez/auth/permissions.py +1 -1
- souleyez/auth/session_manager.py +5 -5
- souleyez/auth/user_manager.py +4 -5
- souleyez/commands/audit.py +6 -5
- souleyez/commands/auth.py +6 -5
- souleyez/commands/deliverables.py +2 -3
- souleyez/commands/engagement.py +3 -3
- souleyez/commands/license.py +3 -2
- souleyez/commands/screenshots.py +5 -4
- souleyez/commands/user.py +10 -8
- souleyez/config.py +4 -2
- souleyez/core/credential_tester.py +4 -2
- souleyez/core/cve_mappings.py +2 -1
- souleyez/core/cve_matcher.py +2 -1
- souleyez/core/msf_auto_mapper.py +2 -0
- souleyez/core/msf_chain_engine.py +3 -1
- souleyez/core/msf_database.py +7 -13
- souleyez/core/msf_integration.py +2 -2
- souleyez/core/msf_rpc_client.py +3 -2
- souleyez/core/msf_rpc_manager.py +4 -4
- souleyez/core/msf_sync_manager.py +7 -7
- souleyez/core/network_utils.py +1 -1
- souleyez/core/parser_handler.py +2 -1
- souleyez/core/pending_chains.py +4 -3
- souleyez/core/templates.py +5 -2
- souleyez/core/tool_chaining.py +297 -230
- souleyez/core/version_utils.py +1 -0
- souleyez/core/vuln_correlation.py +3 -2
- souleyez/core/web_utils.py +2 -1
- souleyez/detection/__init__.py +1 -1
- souleyez/detection/attack_signatures.py +1 -1
- souleyez/detection/mitre_mappings.py +1 -2
- souleyez/detection/validator.py +5 -4
- souleyez/devtools.py +4 -2
- souleyez/docs/README.md +2 -2
- souleyez/engine/background.py +168 -7
- souleyez/engine/base.py +2 -1
- souleyez/engine/loader.py +4 -2
- souleyez/engine/log_sanitizer.py +1 -0
- souleyez/engine/manager.py +3 -1
- souleyez/engine/result_handler.py +50 -67
- souleyez/engine/worker_manager.py +6 -4
- souleyez/export/evidence_bundle.py +1 -0
- souleyez/handlers/base.py +1 -0
- souleyez/handlers/bash_handler.py +1 -0
- souleyez/handlers/bloodhound_handler.py +1 -0
- souleyez/handlers/certipy_handler.py +1 -0
- souleyez/handlers/crackmapexec_handler.py +2 -20
- souleyez/handlers/dnsrecon_handler.py +2 -1
- souleyez/handlers/enum4linux_handler.py +65 -37
- souleyez/handlers/evil_winrm_handler.py +1 -0
- souleyez/handlers/ffuf_handler.py +3 -1
- souleyez/handlers/gobuster_handler.py +7 -6
- souleyez/handlers/gpp_extract_handler.py +1 -0
- souleyez/handlers/hashcat_handler.py +1 -0
- souleyez/handlers/hydra_handler.py +5 -1
- souleyez/handlers/impacket_getuserspns_handler.py +1 -0
- souleyez/handlers/impacket_psexec_handler.py +1 -0
- souleyez/handlers/impacket_secretsdump_handler.py +1 -0
- souleyez/handlers/john_handler.py +1 -0
- souleyez/handlers/katana_handler.py +39 -2
- souleyez/handlers/kerbrute_handler.py +1 -0
- souleyez/handlers/ldapsearch_handler.py +90 -17
- souleyez/handlers/lfi_extract_handler.py +1 -0
- souleyez/handlers/msf_auxiliary_handler.py +2 -0
- souleyez/handlers/msf_exploit_handler.py +1 -0
- souleyez/handlers/nikto_handler.py +2 -1
- souleyez/handlers/nmap_handler.py +2 -1
- souleyez/handlers/nuclei_handler.py +2 -1
- souleyez/handlers/nxc_handler.py +50 -19
- souleyez/handlers/rdp_sec_check_handler.py +1 -0
- souleyez/handlers/registry.py +1 -0
- souleyez/handlers/responder_handler.py +1 -0
- souleyez/handlers/service_explorer_handler.py +2 -1
- souleyez/handlers/smbclient_handler.py +1 -0
- souleyez/handlers/smbmap_handler.py +3 -2
- souleyez/handlers/sqlmap_handler.py +6 -4
- souleyez/handlers/theharvester_handler.py +2 -1
- souleyez/handlers/web_login_test_handler.py +1 -0
- souleyez/handlers/whois_handler.py +3 -2
- souleyez/handlers/wpscan_handler.py +2 -1
- souleyez/history.py +4 -3
- souleyez/importers/msf_importer.py +5 -3
- souleyez/importers/smart_importer.py +6 -4
- souleyez/integrations/siem/__init__.py +6 -6
- souleyez/integrations/siem/base.py +1 -1
- souleyez/integrations/siem/elastic.py +3 -3
- souleyez/integrations/siem/factory.py +1 -2
- souleyez/integrations/siem/googlesecops.py +4 -4
- souleyez/integrations/siem/rule_mappings/wazuh_rules.py +1 -1
- souleyez/integrations/siem/sentinel.py +3 -3
- souleyez/integrations/siem/splunk.py +3 -3
- souleyez/integrations/siem/wazuh.py +4 -4
- souleyez/integrations/wazuh/__init__.py +1 -1
- souleyez/integrations/wazuh/client.py +3 -2
- souleyez/integrations/wazuh/config.py +3 -2
- souleyez/integrations/wazuh/host_mapper.py +3 -1
- souleyez/integrations/wazuh/sync.py +4 -1
- souleyez/intelligence/__init__.py +1 -1
- souleyez/intelligence/correlation_analyzer.py +6 -5
- souleyez/intelligence/exploit_knowledge.py +4 -4
- souleyez/intelligence/exploit_suggestions.py +4 -3
- souleyez/intelligence/gap_analyzer.py +5 -3
- souleyez/intelligence/gap_detector.py +2 -0
- souleyez/intelligence/sensitive_tables.py +1 -1
- souleyez/intelligence/service_parser.py +1 -0
- souleyez/intelligence/surface_analyzer.py +9 -9
- souleyez/intelligence/target_parser.py +1 -0
- souleyez/licensing/__init__.py +3 -3
- souleyez/main.py +25 -18
- souleyez/migrations/fix_job_counter.py +2 -1
- souleyez/parsers/bloodhound_parser.py +1 -0
- souleyez/parsers/crackmapexec_parser.py +2 -1
- souleyez/parsers/dalfox_parser.py +3 -2
- souleyez/parsers/dnsrecon_parser.py +2 -1
- souleyez/parsers/enum4linux_parser.py +2 -1
- souleyez/parsers/ffuf_parser.py +2 -1
- souleyez/parsers/gobuster_parser.py +2 -1
- souleyez/parsers/hashcat_parser.py +3 -2
- souleyez/parsers/http_fingerprint_parser.py +2 -1
- souleyez/parsers/hydra_parser.py +2 -1
- souleyez/parsers/impacket_parser.py +2 -1
- souleyez/parsers/john_parser.py +4 -3
- souleyez/parsers/katana_parser.py +134 -2
- souleyez/parsers/msf_parser.py +2 -1
- souleyez/parsers/nikto_parser.py +2 -1
- souleyez/parsers/nmap_parser.py +14 -3
- souleyez/parsers/nuclei_parser.py +3 -2
- souleyez/parsers/responder_parser.py +1 -0
- souleyez/parsers/searchsploit_parser.py +3 -2
- souleyez/parsers/service_explorer_parser.py +1 -0
- souleyez/parsers/smbmap_parser.py +2 -1
- souleyez/parsers/sqlmap_parser.py +36 -2
- souleyez/parsers/theharvester_parser.py +2 -1
- souleyez/parsers/whois_parser.py +2 -1
- souleyez/parsers/wpscan_parser.py +3 -2
- souleyez/plugins/afp.py +3 -1
- souleyez/plugins/afp_brute.py +3 -1
- souleyez/plugins/ard.py +3 -1
- souleyez/plugins/bloodhound.py +3 -2
- souleyez/plugins/certipy.py +1 -0
- souleyez/plugins/crackmapexec.py +11 -7
- souleyez/plugins/dalfox.py +5 -2
- souleyez/plugins/dns_hijack.py +3 -1
- souleyez/plugins/dnsrecon.py +3 -1
- souleyez/plugins/enum4linux.py +3 -1
- souleyez/plugins/evil_winrm.py +1 -0
- souleyez/plugins/ffuf.py +3 -1
- souleyez/plugins/firmware_extract.py +3 -2
- souleyez/plugins/gobuster.py +6 -3
- souleyez/plugins/gpp_extract.py +1 -0
- souleyez/plugins/hashcat.py +2 -1
- souleyez/plugins/http_fingerprint.py +149 -40
- souleyez/plugins/hydra.py +5 -3
- souleyez/plugins/impacket_common.py +40 -0
- souleyez/plugins/impacket_getnpusers.py +19 -2
- souleyez/plugins/impacket_getuserspns.py +158 -0
- souleyez/plugins/impacket_psexec.py +19 -2
- souleyez/plugins/impacket_secretsdump.py +19 -2
- souleyez/plugins/impacket_smbclient.py +19 -2
- souleyez/plugins/john.py +2 -1
- souleyez/plugins/katana.py +48 -6
- souleyez/plugins/kerbrute.py +1 -0
- souleyez/plugins/lfi_extract.py +1 -0
- souleyez/plugins/macos_ssh.py +3 -1
- souleyez/plugins/mdns.py +3 -1
- souleyez/plugins/msf_auxiliary.py +3 -2
- souleyez/plugins/msf_exploit.py +6 -5
- souleyez/plugins/nikto.py +5 -2
- souleyez/plugins/nmap.py +6 -4
- souleyez/plugins/nuclei.py +3 -1
- souleyez/plugins/nxc.py +1 -0
- souleyez/plugins/plugin_base.py +3 -2
- souleyez/plugins/plugin_template.py +3 -2
- souleyez/plugins/rdp_sec_check.py +1 -0
- souleyez/plugins/responder.py +2 -1
- souleyez/plugins/router_http_brute.py +3 -1
- souleyez/plugins/router_ssh_brute.py +3 -1
- souleyez/plugins/router_telnet_brute.py +3 -1
- souleyez/plugins/routersploit.py +5 -3
- souleyez/plugins/routersploit_exploit.py +5 -3
- souleyez/plugins/searchsploit.py +1 -0
- souleyez/plugins/service_explorer.py +2 -1
- souleyez/plugins/smbmap.py +3 -1
- souleyez/plugins/smbpasswd.py +1 -0
- souleyez/plugins/sqlmap.py +3 -1
- souleyez/plugins/theharvester.py +3 -1
- souleyez/plugins/tr069.py +3 -1
- souleyez/plugins/upnp.py +3 -1
- souleyez/plugins/upnp_abuse.py +4 -2
- souleyez/plugins/vnc_access.py +4 -2
- souleyez/plugins/vnc_brute.py +3 -1
- souleyez/plugins/web_login_test.py +1 -0
- souleyez/plugins/whois.py +3 -1
- souleyez/plugins/wpscan.py +49 -1
- souleyez/reporting/attack_chain.py +2 -1
- souleyez/reporting/charts.py +1 -0
- souleyez/reporting/compliance_mappings.py +1 -0
- souleyez/reporting/detection_report.py +10 -10
- souleyez/reporting/formatters.py +7 -12
- souleyez/reporting/generator.py +34 -46
- souleyez/reporting/metrics.py +2 -1
- souleyez/scanner.py +6 -3
- souleyez/security/__init__.py +7 -5
- souleyez/security/scope_validator.py +5 -4
- souleyez/security/validation.py +14 -0
- souleyez/security.py +5 -2
- souleyez/storage/credentials.py +14 -19
- souleyez/storage/crypto.py +7 -4
- souleyez/storage/database.py +6 -6
- souleyez/storage/db.py +8 -8
- souleyez/storage/deliverable_evidence.py +2 -1
- souleyez/storage/deliverable_exporter.py +3 -2
- souleyez/storage/deliverable_templates.py +2 -1
- souleyez/storage/deliverables.py +2 -1
- souleyez/storage/engagements.py +6 -4
- souleyez/storage/evidence.py +5 -4
- souleyez/storage/execution_log.py +4 -2
- souleyez/storage/exploit_attempts.py +3 -2
- souleyez/storage/exploits.py +3 -1
- souleyez/storage/findings.py +3 -1
- souleyez/storage/hosts.py +5 -2
- souleyez/storage/migrate_to_engagements.py +14 -24
- souleyez/storage/migrations/_001_add_credential_enhancements.py +12 -21
- souleyez/storage/migrations/_003_add_execution_log.py +8 -13
- souleyez/storage/migrations/_005_screenshots.py +2 -4
- souleyez/storage/migrations/_006_deliverables.py +2 -4
- souleyez/storage/migrations/_007_deliverable_templates.py +4 -8
- souleyez/storage/migrations/_008_add_nuclei_table.py +2 -4
- souleyez/storage/migrations/_010_evidence_linking.py +6 -12
- souleyez/storage/migrations/_012_team_collaboration.py +12 -24
- souleyez/storage/migrations/_013_add_host_tags.py +2 -4
- souleyez/storage/migrations/_014_exploit_attempts.py +10 -20
- souleyez/storage/migrations/_015_add_mac_os_fields.py +4 -8
- souleyez/storage/migrations/_016_add_domain_field.py +2 -4
- souleyez/storage/migrations/_017_msf_sessions.py +8 -16
- souleyez/storage/migrations/_018_add_osint_target.py +4 -8
- souleyez/storage/migrations/_019_add_engagement_type.py +4 -8
- souleyez/storage/migrations/_020_add_rbac.py +9 -17
- souleyez/storage/migrations/_021_wazuh_integration.py +4 -8
- souleyez/storage/migrations/_023_fix_detection_results_fk.py +2 -4
- souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +4 -8
- souleyez/storage/migrations/_026_add_engagement_scope.py +4 -8
- souleyez/storage/migrations/_027_multi_siem_persistence.py +8 -16
- souleyez/storage/migrations/__init__.py +1 -4
- souleyez/storage/migrations/migration_manager.py +6 -9
- souleyez/storage/msf_sessions.py +1 -1
- souleyez/storage/osint.py +3 -1
- souleyez/storage/recommendation_engine.py +3 -2
- souleyez/storage/screenshots.py +2 -1
- souleyez/storage/smb_shares.py +3 -1
- souleyez/storage/sqlmap_data.py +6 -4
- souleyez/storage/team_collaboration.py +3 -2
- souleyez/storage/timeline_tracker.py +2 -1
- souleyez/storage/wazuh_vulns.py +3 -1
- souleyez/storage/web_paths.py +3 -1
- souleyez/testing/credential_tester.py +2 -0
- souleyez/ui/__init__.py +2 -1
- souleyez/ui/ai_quotes.py +1 -1
- souleyez/ui/attack_surface.py +50 -28
- souleyez/ui/chain_rules_view.py +6 -3
- souleyez/ui/correlation_view.py +3 -2
- souleyez/ui/dashboard.py +85 -139
- souleyez/ui/deliverables_view.py +1 -1
- souleyez/ui/design_system.py +5 -3
- souleyez/ui/errors.py +3 -1
- souleyez/ui/evidence_linking_view.py +2 -1
- souleyez/ui/evidence_vault.py +11 -6
- souleyez/ui/exploit_suggestions_view.py +11 -7
- souleyez/ui/export_view.py +3 -1
- souleyez/ui/gap_analysis_view.py +6 -3
- souleyez/ui/help_system.py +4 -1
- souleyez/ui/intelligence_view.py +7 -3
- souleyez/ui/interactive.py +1512 -584
- souleyez/ui/interactive_selector.py +3 -2
- souleyez/ui/log_formatter.py +1 -0
- souleyez/ui/menu_components.py +3 -1
- souleyez/ui/msf_auxiliary_menu.py +4 -1
- souleyez/ui/pending_chains_view.py +15 -12
- souleyez/ui/progress_indicators.py +5 -2
- souleyez/ui/recommendations_view.py +4 -2
- souleyez/ui/rule_builder.py +4 -1
- souleyez/ui/setup_wizard.py +10 -8
- souleyez/ui/shortcuts.py +1 -1
- souleyez/ui/splunk_gap_analysis_view.py +7 -4
- souleyez/ui/splunk_vulns_view.py +4 -1
- souleyez/ui/team_dashboard.py +7 -5
- souleyez/ui/template_selector.py +2 -1
- souleyez/ui/terminal.py +3 -2
- souleyez/ui/timeline_view.py +2 -1
- souleyez/ui/tool_setup.py +92 -31
- souleyez/ui/tutorial.py +7 -4
- souleyez/ui/tutorial_state.py +3 -2
- souleyez/ui/wazuh_vulns_view.py +5 -2
- souleyez/ui/wordlist_browser.py +4 -3
- souleyez/ui.py +13 -7
- souleyez/utils/tool_checker.py +61 -12
- souleyez/utils.py +4 -4
- souleyez/wordlists.py +1 -0
- {souleyez-2.43.34.dist-info → souleyez-3.0.7.dist-info}/METADATA +2 -2
- souleyez-3.0.7.dist-info/RECORD +445 -0
- souleyez-2.43.34.dist-info/RECORD +0 -443
- {souleyez-2.43.34.dist-info → souleyez-3.0.7.dist-info}/WHEEL +0 -0
- {souleyez-2.43.34.dist-info → souleyez-3.0.7.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.34.dist-info → souleyez-3.0.7.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.34.dist-info → souleyez-3.0.7.dist-info}/top_level.txt +0 -0
|
@@ -4,8 +4,9 @@ souleyez.parsers.sqlmap_parser
|
|
|
4
4
|
|
|
5
5
|
Parses SQLMap SQL injection detection output into structured findings.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import re
|
|
8
|
-
from typing import
|
|
9
|
+
from typing import Any, Dict
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def parse_sqlmap_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
@@ -181,6 +182,29 @@ def parse_sqlmap_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
181
182
|
elif method == "POST" and effective_post_data:
|
|
182
183
|
result["injectable_post_data"] = effective_post_data
|
|
183
184
|
|
|
185
|
+
# Look ahead for Type: lines to extract techniques
|
|
186
|
+
techniques = []
|
|
187
|
+
technique_str = None
|
|
188
|
+
for m in range(j + 1, min(j + 20, len(lines))):
|
|
189
|
+
type_line = lines[m].strip()
|
|
190
|
+
if type_line.startswith("Type:"):
|
|
191
|
+
tech_type = type_line.replace("Type:", "").strip()
|
|
192
|
+
techniques.append(tech_type)
|
|
193
|
+
if not technique_str:
|
|
194
|
+
technique_str = tech_type
|
|
195
|
+
elif type_line.startswith("---") and techniques:
|
|
196
|
+
break # End of technique block
|
|
197
|
+
elif type_line.startswith("[") and techniques:
|
|
198
|
+
break # Hit next section
|
|
199
|
+
|
|
200
|
+
# Determine technique string
|
|
201
|
+
if len(techniques) > 1:
|
|
202
|
+
technique_str = "multiple"
|
|
203
|
+
elif techniques:
|
|
204
|
+
technique_str = techniques[0]
|
|
205
|
+
else:
|
|
206
|
+
technique_str = "sqli"
|
|
207
|
+
|
|
184
208
|
# Add vulnerability entry
|
|
185
209
|
result["vulnerabilities"].append(
|
|
186
210
|
{
|
|
@@ -190,6 +214,8 @@ def parse_sqlmap_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
190
214
|
"injectable": True,
|
|
191
215
|
"severity": "critical",
|
|
192
216
|
"description": f"Parameter '{param}' is vulnerable to SQL injection (resumed from session)",
|
|
217
|
+
"technique": technique_str,
|
|
218
|
+
"dbms": "Unknown", # Will be updated later if found
|
|
193
219
|
}
|
|
194
220
|
)
|
|
195
221
|
|
|
@@ -199,7 +225,7 @@ def parse_sqlmap_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
199
225
|
"parameter": param,
|
|
200
226
|
"method": method,
|
|
201
227
|
"post_data": effective_post_data,
|
|
202
|
-
"techniques":
|
|
228
|
+
"techniques": techniques,
|
|
203
229
|
}
|
|
204
230
|
if not any(
|
|
205
231
|
ip["url"] == injection_point["url"]
|
|
@@ -498,6 +524,8 @@ def parse_sqlmap_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
498
524
|
"injectable": True,
|
|
499
525
|
"severity": "critical",
|
|
500
526
|
"description": f"Parameter '{param}' is vulnerable to SQL injection",
|
|
527
|
+
"technique": "sqli",
|
|
528
|
+
"dbms": result.get("dbms", "Unknown"),
|
|
501
529
|
}
|
|
502
530
|
)
|
|
503
531
|
|
|
@@ -829,6 +857,12 @@ def parse_sqlmap_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
829
857
|
if best["post_data"]:
|
|
830
858
|
result["injectable_post_data"] = best["post_data"]
|
|
831
859
|
|
|
860
|
+
# POST-PROCESSING: Update vulnerabilities with actual DBMS if it was parsed later
|
|
861
|
+
if result.get("dbms"):
|
|
862
|
+
for vuln in result["vulnerabilities"]:
|
|
863
|
+
if vuln.get("dbms") == "Unknown" or vuln.get("dbms") is None:
|
|
864
|
+
vuln["dbms"] = result["dbms"]
|
|
865
|
+
|
|
832
866
|
return result
|
|
833
867
|
|
|
834
868
|
|
|
@@ -4,8 +4,9 @@ souleyez.parsers.theharvester_parser
|
|
|
4
4
|
|
|
5
5
|
Parses theHarvester OSINT output into structured data.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import re
|
|
8
|
-
from typing import
|
|
9
|
+
from typing import Any, Dict
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def parse_theharvester_output(output: str, target: str = "") -> Dict[str, Any]:
|
souleyez/parsers/whois_parser.py
CHANGED
|
@@ -4,8 +4,9 @@ souleyez.parsers.whois_parser
|
|
|
4
4
|
|
|
5
5
|
Parses WHOIS domain information output into structured OSINT data.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import re
|
|
8
|
-
from typing import Dict, List
|
|
9
|
+
from typing import Any, Dict, List
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def parse_whois_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
@@ -4,9 +4,10 @@ souleyez.parsers.wpscan_parser
|
|
|
4
4
|
|
|
5
5
|
Parses WPScan WordPress vulnerability scan output into structured findings.
|
|
6
6
|
"""
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
import json
|
|
9
|
-
|
|
9
|
+
import re
|
|
10
|
+
from typing import Any, Dict, List, Optional
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def parse_wpscan_output(output: str, target: str = "") -> Dict[str, Any]:
|
souleyez/plugins/afp.py
CHANGED
|
@@ -5,12 +5,14 @@ souleyez.plugins.afp
|
|
|
5
5
|
AFP (Apple Filing Protocol) enumeration plugin.
|
|
6
6
|
Discovers AFP shares on macOS systems.
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
import subprocess
|
|
9
10
|
import time
|
|
10
11
|
from typing import List
|
|
11
12
|
|
|
13
|
+
from souleyez.security.validation import ValidationError, validate_target
|
|
14
|
+
|
|
12
15
|
from .plugin_base import PluginBase
|
|
13
|
-
from souleyez.security.validation import validate_target, ValidationError
|
|
14
16
|
|
|
15
17
|
HELP = {
|
|
16
18
|
"name": "AFP — Apple File Sharing Enumeration",
|
souleyez/plugins/afp_brute.py
CHANGED
|
@@ -5,12 +5,14 @@ souleyez.plugins.afp_brute
|
|
|
5
5
|
AFP brute force plugin using Hydra.
|
|
6
6
|
Attacks AFP file sharing on macOS systems.
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
import subprocess
|
|
9
10
|
import time
|
|
10
11
|
from typing import List
|
|
11
12
|
|
|
13
|
+
from souleyez.security.validation import ValidationError, validate_target
|
|
14
|
+
|
|
12
15
|
from .plugin_base import PluginBase
|
|
13
|
-
from souleyez.security.validation import validate_target, ValidationError
|
|
14
16
|
|
|
15
17
|
HELP = {
|
|
16
18
|
"name": "AFP Brute — Apple File Sharing Attack",
|
souleyez/plugins/ard.py
CHANGED
|
@@ -5,12 +5,14 @@ souleyez.plugins.ard
|
|
|
5
5
|
ARD/VNC (Apple Remote Desktop) enumeration plugin.
|
|
6
6
|
Discovers VNC/ARD services on macOS systems.
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
import subprocess
|
|
9
10
|
import time
|
|
10
11
|
from typing import List
|
|
11
12
|
|
|
13
|
+
from souleyez.security.validation import ValidationError, validate_target
|
|
14
|
+
|
|
12
15
|
from .plugin_base import PluginBase
|
|
13
|
-
from souleyez.security.validation import validate_target, ValidationError
|
|
14
16
|
|
|
15
17
|
HELP = {
|
|
16
18
|
"name": "ARD — Apple Remote Desktop/VNC Enumeration",
|
souleyez/plugins/bloodhound.py
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
"""
|
|
3
3
|
Bloodhound plugin - Active Directory attack path mapping.
|
|
4
4
|
"""
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
import json
|
|
7
|
-
|
|
7
|
+
import subprocess
|
|
8
8
|
from datetime import datetime
|
|
9
|
+
from pathlib import Path
|
|
9
10
|
|
|
10
11
|
HELP = {
|
|
11
12
|
"name": "Bloodhound - Active Directory Attack Path Mapping",
|
souleyez/plugins/certipy.py
CHANGED
souleyez/plugins/crackmapexec.py
CHANGED
|
@@ -4,12 +4,14 @@ souleyez.plugins.crackmapexec - Swiss army knife for Windows/AD pentesting
|
|
|
4
4
|
|
|
5
5
|
Note: Uses NetExec (netexec/nxc), the successor to CrackMapExec
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import subprocess
|
|
8
9
|
import time
|
|
9
10
|
from typing import List
|
|
10
11
|
|
|
12
|
+
from souleyez.security.validation import ValidationError, validate_target
|
|
13
|
+
|
|
11
14
|
from .plugin_base import PluginBase
|
|
12
|
-
from souleyez.security.validation import validate_target, ValidationError
|
|
13
15
|
|
|
14
16
|
HELP = {
|
|
15
17
|
"name": "CrackMapExec (CME) - Windows/AD Pentesting Tool",
|
|
@@ -248,6 +250,8 @@ class CrackMapExecPlugin(PluginBase):
|
|
|
248
250
|
elif protocol not in args:
|
|
249
251
|
cmd.extend(["--shares"])
|
|
250
252
|
|
|
253
|
+
# For anonymous enumeration, use null session with empty domain
|
|
254
|
+
# netexec 1.5.0 requires -d '' for proper null session (1.4.0 didn't need it)
|
|
251
255
|
has_creds = any(arg in cmd for arg in ["-u", "--username", "-p", "--password"])
|
|
252
256
|
has_enum = any(
|
|
253
257
|
arg in cmd
|
|
@@ -267,6 +271,8 @@ class CrackMapExecPlugin(PluginBase):
|
|
|
267
271
|
cmd.insert(insert_pos + 1, "")
|
|
268
272
|
cmd.insert(insert_pos + 2, "-p")
|
|
269
273
|
cmd.insert(insert_pos + 3, "")
|
|
274
|
+
cmd.insert(insert_pos + 4, "-d")
|
|
275
|
+
cmd.insert(insert_pos + 5, "")
|
|
270
276
|
|
|
271
277
|
return {"cmd": cmd, "timeout": 1800}
|
|
272
278
|
|
|
@@ -341,8 +347,8 @@ class CrackMapExecPlugin(PluginBase):
|
|
|
341
347
|
# No protocol specified in args, add default behavior
|
|
342
348
|
cmd.extend(["--shares"])
|
|
343
349
|
|
|
344
|
-
#
|
|
345
|
-
#
|
|
350
|
+
# For anonymous enumeration, use null session with empty domain
|
|
351
|
+
# netexec 1.5.0 requires -d '' for proper null session (1.4.0 didn't need it)
|
|
346
352
|
has_creds = any(arg in cmd for arg in ["-u", "--username", "-p", "--password"])
|
|
347
353
|
has_enum = any(
|
|
348
354
|
arg in cmd
|
|
@@ -357,15 +363,13 @@ class CrackMapExecPlugin(PluginBase):
|
|
|
357
363
|
)
|
|
358
364
|
|
|
359
365
|
if has_enum and not has_creds:
|
|
360
|
-
# Add null session credentials after ALL targets but before flags
|
|
361
|
-
# Position: 1 (netexec) + 1 (protocol) + len(target_list)
|
|
362
|
-
# Example: ['netexec', 'smb', '10.0.0.14', '10.0.0.82', '--shares']
|
|
363
|
-
# Insert at position 4: ['netexec', 'smb', '10.0.0.14', '10.0.0.82', '-u', '', '-p', '', '--shares']
|
|
364
366
|
insert_pos = 2 + len(target_list)
|
|
365
367
|
cmd.insert(insert_pos, "-u")
|
|
366
368
|
cmd.insert(insert_pos + 1, "")
|
|
367
369
|
cmd.insert(insert_pos + 2, "-p")
|
|
368
370
|
cmd.insert(insert_pos + 3, "")
|
|
371
|
+
cmd.insert(insert_pos + 4, "-d")
|
|
372
|
+
cmd.insert(insert_pos + 5, "")
|
|
369
373
|
|
|
370
374
|
if not log_path:
|
|
371
375
|
try:
|
souleyez/plugins/dalfox.py
CHANGED
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
"""
|
|
3
3
|
souleyez.plugins.dalfox - XSS vulnerability scanner
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
6
9
|
import subprocess
|
|
7
10
|
import time
|
|
8
|
-
import json
|
|
9
11
|
from typing import List
|
|
10
12
|
|
|
13
|
+
from souleyez.security.validation import ValidationError, validate_url
|
|
14
|
+
|
|
11
15
|
from .plugin_base import PluginBase
|
|
12
|
-
from souleyez.security.validation import validate_url, ValidationError
|
|
13
16
|
|
|
14
17
|
HELP = {
|
|
15
18
|
"name": "Dalfox - XSS Vulnerability Scanner",
|
souleyez/plugins/dns_hijack.py
CHANGED
|
@@ -5,12 +5,14 @@ souleyez.plugins.dns_hijack
|
|
|
5
5
|
DNS hijacking detection plugin.
|
|
6
6
|
Checks if a router is performing DNS hijacking/redirection.
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
import subprocess
|
|
9
10
|
import time
|
|
10
11
|
from typing import List
|
|
11
12
|
|
|
13
|
+
from souleyez.security.validation import ValidationError, validate_target
|
|
14
|
+
|
|
12
15
|
from .plugin_base import PluginBase
|
|
13
|
-
from souleyez.security.validation import validate_target, ValidationError
|
|
14
16
|
|
|
15
17
|
HELP = {
|
|
16
18
|
"name": "DNS Hijack — DNS Manipulation Detection",
|
souleyez/plugins/dnsrecon.py
CHANGED
|
@@ -4,12 +4,14 @@ souleyez.plugins.dnsrecon
|
|
|
4
4
|
|
|
5
5
|
DNSRecon DNS enumeration and reconnaissance plugin.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import subprocess
|
|
8
9
|
import time
|
|
9
10
|
from typing import List
|
|
10
11
|
|
|
12
|
+
from souleyez.security.validation import ValidationError, validate_target
|
|
13
|
+
|
|
11
14
|
from .plugin_base import PluginBase
|
|
12
|
-
from souleyez.security.validation import validate_target, ValidationError
|
|
13
15
|
|
|
14
16
|
HELP = {
|
|
15
17
|
"name": "DNSRecon — DNS Enumeration Tool",
|
souleyez/plugins/enum4linux.py
CHANGED
|
@@ -4,12 +4,14 @@ souleyez.plugins.enum4linux
|
|
|
4
4
|
|
|
5
5
|
Enum4linux SMB enumeration plugin with unified interface.
|
|
6
6
|
"""
|
|
7
|
+
|
|
7
8
|
import subprocess
|
|
8
9
|
import time
|
|
9
10
|
from typing import List
|
|
10
11
|
|
|
12
|
+
from souleyez.security.validation import ValidationError, validate_target
|
|
13
|
+
|
|
11
14
|
from .plugin_base import PluginBase
|
|
12
|
-
from souleyez.security.validation import validate_target, ValidationError
|
|
13
15
|
|
|
14
16
|
HELP = {
|
|
15
17
|
"name": "enum4linux (SMB Enumeration)",
|
souleyez/plugins/evil_winrm.py
CHANGED
souleyez/plugins/ffuf.py
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
"""
|
|
3
3
|
souleyez.plugins.ffuf - Fast web fuzzer
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
import subprocess
|
|
6
7
|
from typing import List
|
|
7
8
|
|
|
9
|
+
from souleyez.security.validation import ValidationError, validate_url
|
|
10
|
+
|
|
8
11
|
from .plugin_base import PluginBase
|
|
9
|
-
from souleyez.security.validation import validate_url, ValidationError
|
|
10
12
|
|
|
11
13
|
HELP = {
|
|
12
14
|
"name": "ffuf - Fast Web Fuzzer",
|
|
@@ -5,10 +5,11 @@ souleyez.plugins.firmware_extract
|
|
|
5
5
|
Firmware extraction and analysis plugin using binwalk.
|
|
6
6
|
Extracts and analyzes router firmware images.
|
|
7
7
|
"""
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
import os
|
|
9
10
|
import shutil
|
|
11
|
+
import subprocess
|
|
10
12
|
import time
|
|
11
|
-
import os
|
|
12
13
|
from typing import List
|
|
13
14
|
|
|
14
15
|
from .plugin_base import PluginBase
|
souleyez/plugins/gobuster.py
CHANGED
|
@@ -2,18 +2,21 @@
|
|
|
2
2
|
"""
|
|
3
3
|
souleyez.plugins.gobuster
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import re
|
|
6
9
|
import subprocess
|
|
7
10
|
import time
|
|
8
|
-
import re
|
|
9
11
|
import uuid
|
|
10
|
-
from typing import
|
|
12
|
+
from typing import Dict, List, Optional
|
|
11
13
|
from urllib.parse import urlparse
|
|
12
14
|
|
|
13
15
|
import requests
|
|
14
16
|
|
|
17
|
+
from souleyez.security.validation import ValidationError, validate_url
|
|
18
|
+
|
|
15
19
|
from .plugin_base import PluginBase
|
|
16
|
-
from souleyez.security.validation import validate_url, ValidationError
|
|
17
20
|
|
|
18
21
|
HELP = {
|
|
19
22
|
"name": "Gobuster — Directory, File & DNS/VHost Brute-Force Tool",
|
souleyez/plugins/gpp_extract.py
CHANGED
souleyez/plugins/hashcat.py
CHANGED
|
@@ -337,50 +337,79 @@ class HttpFingerprintPlugin(PluginBase):
|
|
|
337
337
|
target = f"http://{target}"
|
|
338
338
|
|
|
339
339
|
try:
|
|
340
|
-
#
|
|
341
|
-
|
|
340
|
+
# Use thread-based hard timeout to prevent indefinite hangs
|
|
341
|
+
# urllib timeouts don't always work if server accepts connection but stalls
|
|
342
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
343
|
+
from concurrent.futures import TimeoutError as FuturesTimeout
|
|
344
|
+
|
|
345
|
+
hard_timeout = timeout * 3 # 30 seconds max for entire probe operation
|
|
346
|
+
|
|
347
|
+
with ThreadPoolExecutor(max_workers=1) as executor:
|
|
348
|
+
future = executor.submit(self._smart_probe, target, timeout)
|
|
349
|
+
try:
|
|
350
|
+
result, effective_url = future.result(timeout=hard_timeout)
|
|
351
|
+
except FuturesTimeout:
|
|
352
|
+
# Hard timeout hit - server is unresponsive
|
|
353
|
+
result = {
|
|
354
|
+
"error": f"Timeout: server did not respond within {hard_timeout}s",
|
|
355
|
+
"status_code": None,
|
|
356
|
+
"server": None,
|
|
357
|
+
"waf": [],
|
|
358
|
+
"cdn": [],
|
|
359
|
+
"managed_hosting": None,
|
|
360
|
+
"technologies": [],
|
|
361
|
+
"headers": {},
|
|
362
|
+
"cookies": [],
|
|
363
|
+
"tls": None,
|
|
364
|
+
"redirect_url": None,
|
|
365
|
+
}
|
|
366
|
+
effective_url = target
|
|
367
|
+
|
|
342
368
|
output = self._format_output(effective_url, result, label)
|
|
343
369
|
|
|
344
370
|
if log_path:
|
|
345
371
|
with open(log_path, "a", encoding="utf-8", errors="replace") as fh:
|
|
346
372
|
fh.write(output)
|
|
347
|
-
# Fetch robots.txt and sitemap.xml for path discovery
|
|
348
|
-
robots_paths, sitemap_paths = self._fetch_robots_sitemap(
|
|
349
|
-
effective_url, timeout
|
|
350
|
-
)
|
|
351
|
-
result["robots_paths"] = robots_paths
|
|
352
|
-
result["sitemap_paths"] = sitemap_paths
|
|
353
|
-
|
|
354
|
-
# Quick path probing for CMS, admin panels, API endpoints
|
|
355
|
-
quick_probe = self._quick_path_probe(effective_url, timeout)
|
|
356
|
-
result["cms_detected"] = quick_probe.get("cms")
|
|
357
|
-
result["admin_panels"] = quick_probe.get("admin_panels", [])
|
|
358
|
-
result["api_endpoints"] = quick_probe.get("api_endpoints", [])
|
|
359
|
-
|
|
360
|
-
# Write additional detections to log
|
|
361
|
-
if quick_probe.get("cms"):
|
|
362
|
-
cms = quick_probe["cms"]
|
|
363
|
-
fh.write(f"\n{'=' * 40}\n")
|
|
364
|
-
fh.write(
|
|
365
|
-
f"CMS DETECTED: {cms['name']} ({cms['confidence']} confidence)\n"
|
|
366
|
-
)
|
|
367
|
-
for p in cms["paths"]:
|
|
368
|
-
fh.write(f" - {p['path']} (HTTP {p['status']})\n")
|
|
369
|
-
fh.write(f"{'=' * 40}\n")
|
|
370
373
|
|
|
371
|
-
if
|
|
372
|
-
|
|
373
|
-
for
|
|
374
|
+
# Skip additional probing if initial fingerprint failed
|
|
375
|
+
if not result.get("error"):
|
|
376
|
+
# Fetch robots.txt and sitemap.xml for path discovery
|
|
377
|
+
robots_paths, sitemap_paths = self._fetch_robots_sitemap(
|
|
378
|
+
effective_url, timeout
|
|
379
|
+
)
|
|
380
|
+
result["robots_paths"] = robots_paths
|
|
381
|
+
result["sitemap_paths"] = sitemap_paths
|
|
382
|
+
|
|
383
|
+
# Quick path probing for CMS, admin panels, API endpoints
|
|
384
|
+
quick_probe = self._quick_path_probe(effective_url, timeout)
|
|
385
|
+
result["cms_detected"] = quick_probe.get("cms")
|
|
386
|
+
result["admin_panels"] = quick_probe.get("admin_panels", [])
|
|
387
|
+
result["api_endpoints"] = quick_probe.get("api_endpoints", [])
|
|
388
|
+
|
|
389
|
+
# Write additional detections to log
|
|
390
|
+
if quick_probe.get("cms"):
|
|
391
|
+
cms = quick_probe["cms"]
|
|
392
|
+
fh.write(f"\n{'=' * 40}\n")
|
|
374
393
|
fh.write(
|
|
375
|
-
f"
|
|
394
|
+
f"CMS DETECTED: {cms['name']} ({cms['confidence']} confidence)\n"
|
|
376
395
|
)
|
|
396
|
+
for p in cms["paths"]:
|
|
397
|
+
fh.write(f" - {p['path']} (HTTP {p['status']})\n")
|
|
398
|
+
fh.write(f"{'=' * 40}\n")
|
|
399
|
+
|
|
400
|
+
if quick_probe.get("admin_panels"):
|
|
401
|
+
fh.write(f"\nADMIN PANELS FOUND:\n")
|
|
402
|
+
for panel in quick_probe["admin_panels"]:
|
|
403
|
+
fh.write(
|
|
404
|
+
f" - {panel['name']}: {panel['url']} (HTTP {panel['status']})\n"
|
|
405
|
+
)
|
|
377
406
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
407
|
+
if quick_probe.get("api_endpoints"):
|
|
408
|
+
fh.write(f"\nAPI ENDPOINTS FOUND:\n")
|
|
409
|
+
for api in quick_probe["api_endpoints"]:
|
|
410
|
+
fh.write(
|
|
411
|
+
f" - {api['type']}: {api['url']} (HTTP {api['status']})\n"
|
|
412
|
+
)
|
|
384
413
|
|
|
385
414
|
# Write JSON result for parsing
|
|
386
415
|
fh.write("\n\n=== JSON_RESULT ===\n")
|
|
@@ -413,8 +442,32 @@ class HttpFingerprintPlugin(PluginBase):
|
|
|
413
442
|
tuple: (result_dict, effective_url)
|
|
414
443
|
"""
|
|
415
444
|
parsed = urlparse(target)
|
|
445
|
+
|
|
446
|
+
# Quick connectivity check - fail fast if port isn't responding
|
|
416
447
|
host = parsed.hostname
|
|
417
448
|
port = parsed.port or (443 if parsed.scheme == "https" else 80)
|
|
449
|
+
try:
|
|
450
|
+
with socket.create_connection(
|
|
451
|
+
(host, port), timeout=min(timeout, 5)
|
|
452
|
+
) as sock:
|
|
453
|
+
pass # Just checking if we can connect
|
|
454
|
+
except (socket.timeout, socket.error, OSError) as e:
|
|
455
|
+
# Port not responding - return error result immediately
|
|
456
|
+
return {
|
|
457
|
+
"error": f"Connection failed: {e}",
|
|
458
|
+
"status_code": None,
|
|
459
|
+
"server": None,
|
|
460
|
+
"waf": [],
|
|
461
|
+
"cdn": [],
|
|
462
|
+
"managed_hosting": None,
|
|
463
|
+
"technologies": [],
|
|
464
|
+
"headers": {},
|
|
465
|
+
"cookies": [],
|
|
466
|
+
"tls": None,
|
|
467
|
+
"redirect_url": None,
|
|
468
|
+
"protocol_detection": "failed",
|
|
469
|
+
"effective_url": target,
|
|
470
|
+
}, target
|
|
418
471
|
|
|
419
472
|
# Build both URL variants
|
|
420
473
|
http_url = (
|
|
@@ -564,6 +617,11 @@ class HttpFingerprintPlugin(PluginBase):
|
|
|
564
617
|
import urllib.error
|
|
565
618
|
import urllib.request
|
|
566
619
|
|
|
620
|
+
# Set global socket timeout to prevent hanging on slow/unresponsive servers
|
|
621
|
+
# This is a safety net - individual requests also have timeouts
|
|
622
|
+
old_timeout = socket.getdefaulttimeout()
|
|
623
|
+
socket.setdefaulttimeout(timeout + 5) # Slightly longer than request timeout
|
|
624
|
+
|
|
567
625
|
result = {
|
|
568
626
|
"server": None,
|
|
569
627
|
"server_version": None,
|
|
@@ -700,6 +758,10 @@ class HttpFingerprintPlugin(PluginBase):
|
|
|
700
758
|
except Exception as e:
|
|
701
759
|
result["error"] = f"{type(e).__name__}: {e}"
|
|
702
760
|
|
|
761
|
+
finally:
|
|
762
|
+
# Restore original socket timeout
|
|
763
|
+
socket.setdefaulttimeout(old_timeout)
|
|
764
|
+
|
|
703
765
|
return result
|
|
704
766
|
|
|
705
767
|
def _detect_waf(self, headers: Dict[str, str], cookies: List[str]) -> List[str]:
|
|
@@ -1021,9 +1083,60 @@ class HttpFingerprintPlugin(PluginBase):
|
|
|
1021
1083
|
# Track CMS detections to avoid duplicates
|
|
1022
1084
|
cms_detected = {}
|
|
1023
1085
|
|
|
1086
|
+
# CMS-specific content markers to verify detection (prevents SPA false positives)
|
|
1087
|
+
cms_content_markers = {
|
|
1088
|
+
"WordPress": [
|
|
1089
|
+
b"wp-login",
|
|
1090
|
+
b"wp-includes",
|
|
1091
|
+
b"wp-content",
|
|
1092
|
+
b"wordpress",
|
|
1093
|
+
b"wlwmanifest",
|
|
1094
|
+
b"xmlrpc.php",
|
|
1095
|
+
],
|
|
1096
|
+
"Joomla": [b"joomla", b"com_content", b"/administrator/"],
|
|
1097
|
+
"Drupal": [b"drupal", b"sites/default", b"sites/all"],
|
|
1098
|
+
"TYPO3": [b"typo3", b"typo3conf"],
|
|
1099
|
+
"Sitecore": [b"sitecore"],
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1024
1102
|
for path, category, subtype in paths_to_check:
|
|
1025
1103
|
try:
|
|
1026
1104
|
url = base.rstrip("/") + path
|
|
1105
|
+
|
|
1106
|
+
# For CMS detection, use GET to verify content (prevents SPA false positives)
|
|
1107
|
+
# SPAs return 200 for all routes but with same content
|
|
1108
|
+
if category == "cms":
|
|
1109
|
+
req = urllib.request.Request(
|
|
1110
|
+
url,
|
|
1111
|
+
method="GET",
|
|
1112
|
+
headers={
|
|
1113
|
+
"User-Agent": "Mozilla/5.0 (compatible; SoulEyez/1.0)"
|
|
1114
|
+
},
|
|
1115
|
+
)
|
|
1116
|
+
try:
|
|
1117
|
+
with urllib.request.urlopen(
|
|
1118
|
+
req, timeout=timeout, context=ctx
|
|
1119
|
+
) as response:
|
|
1120
|
+
status = response.getcode()
|
|
1121
|
+
# Read first 4KB to check for CMS markers
|
|
1122
|
+
content = response.read(4096).lower()
|
|
1123
|
+
except urllib.error.HTTPError as e:
|
|
1124
|
+
status = e.code
|
|
1125
|
+
content = b""
|
|
1126
|
+
|
|
1127
|
+
# Verify response contains CMS-specific content
|
|
1128
|
+
if status in (200, 301, 302, 401, 403):
|
|
1129
|
+
markers = cms_content_markers.get(subtype, [])
|
|
1130
|
+
has_cms_content = any(marker in content for marker in markers)
|
|
1131
|
+
if has_cms_content:
|
|
1132
|
+
if subtype not in cms_detected:
|
|
1133
|
+
cms_detected[subtype] = []
|
|
1134
|
+
cms_detected[subtype].append(
|
|
1135
|
+
{"path": path, "status": status}
|
|
1136
|
+
)
|
|
1137
|
+
continue
|
|
1138
|
+
|
|
1139
|
+
# For admin/API detection, HEAD is fine (just checking existence)
|
|
1027
1140
|
req = urllib.request.Request(
|
|
1028
1141
|
url,
|
|
1029
1142
|
method="HEAD",
|
|
@@ -1040,11 +1153,7 @@ class HttpFingerprintPlugin(PluginBase):
|
|
|
1040
1153
|
|
|
1041
1154
|
# Consider 2xx, 3xx, 401, 403 as "exists"
|
|
1042
1155
|
if status in (200, 201, 204, 301, 302, 303, 307, 308, 401, 403):
|
|
1043
|
-
if category == "
|
|
1044
|
-
if subtype not in cms_detected:
|
|
1045
|
-
cms_detected[subtype] = []
|
|
1046
|
-
cms_detected[subtype].append({"path": path, "status": status})
|
|
1047
|
-
elif category == "admin":
|
|
1156
|
+
if category == "admin":
|
|
1048
1157
|
result["admin_panels"].append(
|
|
1049
1158
|
{
|
|
1050
1159
|
"path": path,
|