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
|
@@ -5,7 +5,7 @@ souleyez.parsers.gobuster_parser
|
|
|
5
5
|
Parses Gobuster directory/file enumeration output into structured data.
|
|
6
6
|
"""
|
|
7
7
|
import re
|
|
8
|
-
from typing import Dict, Any
|
|
8
|
+
from typing import Dict, Any, List
|
|
9
9
|
from urllib.parse import urlparse
|
|
10
10
|
|
|
11
11
|
|
|
@@ -50,38 +50,37 @@ def parse_gobuster_output(output: str, target: str = "") -> Dict[str, Any]:
|
|
|
50
50
|
]
|
|
51
51
|
}
|
|
52
52
|
"""
|
|
53
|
-
result = {
|
|
54
|
-
'target_url': target,
|
|
55
|
-
'paths': []
|
|
56
|
-
}
|
|
53
|
+
result = {"target_url": target, "paths": []}
|
|
57
54
|
|
|
58
55
|
# Strip ANSI escape codes from output (gobuster progress lines contain these)
|
|
59
|
-
ansi_escape = re.compile(r
|
|
60
|
-
output = ansi_escape.sub(
|
|
56
|
+
ansi_escape = re.compile(r"\x1b\[[0-9;]*[a-zA-Z]")
|
|
57
|
+
output = ansi_escape.sub("", output)
|
|
61
58
|
|
|
62
|
-
lines = output.split(
|
|
59
|
+
lines = output.split("\n")
|
|
63
60
|
|
|
64
61
|
for line in lines:
|
|
65
62
|
line = line.strip()
|
|
66
63
|
|
|
67
64
|
# Skip progress lines (gobuster v3.6+ outputs these on Ubuntu/newer systems)
|
|
68
65
|
# Format: "Progress: 12345 / 50798 (24.30%)"
|
|
69
|
-
if line.startswith(
|
|
66
|
+
if line.startswith("Progress:"):
|
|
70
67
|
continue
|
|
71
68
|
|
|
72
69
|
# Extract target URL from header
|
|
73
|
-
if line.startswith(
|
|
74
|
-
url_match = re.search(r
|
|
70
|
+
if line.startswith("[+] Url:"):
|
|
71
|
+
url_match = re.search(r"\[?\+\]?\s*Url:\s+(\S+)", line)
|
|
75
72
|
if url_match:
|
|
76
|
-
result[
|
|
73
|
+
result["target_url"] = url_match.group(1)
|
|
77
74
|
|
|
78
75
|
# Parse discovered paths
|
|
79
76
|
# Format (v3.6 and earlier): /path (Status: NNN) [Size: NNN] [--> redirect]
|
|
80
77
|
# Format (v3.8+): path (Status: NNN) [Size: NNN] [--> redirect]
|
|
81
|
-
elif
|
|
82
|
-
|
|
78
|
+
elif (
|
|
79
|
+
"(Status:" in line and not line.startswith("[") and not line.startswith("=")
|
|
80
|
+
):
|
|
81
|
+
path_data = _parse_path_line(line, result["target_url"])
|
|
83
82
|
if path_data:
|
|
84
|
-
result[
|
|
83
|
+
result["paths"].append(path_data)
|
|
85
84
|
|
|
86
85
|
return result
|
|
87
86
|
|
|
@@ -102,25 +101,25 @@ def _parse_path_line(line: str, base_url: str = "") -> Dict[str, Any]:
|
|
|
102
101
|
try:
|
|
103
102
|
# Extract path (everything before first parenthesis or multiple spaces)
|
|
104
103
|
# Handle both /path and path formats (v3.8+ outputs without leading /)
|
|
105
|
-
path_match = re.match(r
|
|
104
|
+
path_match = re.match(r"^(/?[^\s(]+)\s+", line)
|
|
106
105
|
if not path_match:
|
|
107
106
|
return None
|
|
108
107
|
|
|
109
108
|
path = path_match.group(1).strip()
|
|
110
109
|
# Ensure path starts with /
|
|
111
|
-
if not path.startswith(
|
|
112
|
-
path =
|
|
110
|
+
if not path.startswith("/"):
|
|
111
|
+
path = "/" + path
|
|
113
112
|
|
|
114
113
|
# Extract status code
|
|
115
|
-
status_match = re.search(r
|
|
114
|
+
status_match = re.search(r"\(Status:\s*(\d+)\)", line)
|
|
116
115
|
status_code = int(status_match.group(1)) if status_match else None
|
|
117
116
|
|
|
118
117
|
# Extract size
|
|
119
|
-
size_match = re.search(r
|
|
118
|
+
size_match = re.search(r"\[Size:\s*(\d+)\]", line)
|
|
120
119
|
size = int(size_match.group(1)) if size_match else None
|
|
121
120
|
|
|
122
121
|
# Extract redirect target if present
|
|
123
|
-
redirect_match = re.search(r
|
|
122
|
+
redirect_match = re.search(r"\[-+>\s*([^\]]+)\]", line)
|
|
124
123
|
redirect = redirect_match.group(1).strip() if redirect_match else None
|
|
125
124
|
|
|
126
125
|
# Build full URL
|
|
@@ -131,11 +130,11 @@ def _parse_path_line(line: str, base_url: str = "") -> Dict[str, Any]:
|
|
|
131
130
|
full_url = path
|
|
132
131
|
|
|
133
132
|
return {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
"path": path,
|
|
134
|
+
"url": full_url,
|
|
135
|
+
"status_code": status_code,
|
|
136
|
+
"size": size,
|
|
137
|
+
"redirect": redirect,
|
|
139
138
|
}
|
|
140
139
|
except Exception:
|
|
141
140
|
return None
|
|
@@ -151,19 +150,15 @@ def get_paths_stats(parsed: Dict[str, Any]) -> Dict[str, int]:
|
|
|
151
150
|
Returns:
|
|
152
151
|
Dict with counts by status code: {'200': 5, '301': 3, '403': 2, ...}
|
|
153
152
|
"""
|
|
154
|
-
stats = {
|
|
155
|
-
'total': len(parsed.get('paths', [])),
|
|
156
|
-
'redirects': 0,
|
|
157
|
-
'by_status': {}
|
|
158
|
-
}
|
|
153
|
+
stats = {"total": len(parsed.get("paths", [])), "redirects": 0, "by_status": {}}
|
|
159
154
|
|
|
160
|
-
for path in parsed.get(
|
|
161
|
-
status = str(path.get(
|
|
162
|
-
stats[
|
|
155
|
+
for path in parsed.get("paths", []):
|
|
156
|
+
status = str(path.get("status_code", "unknown"))
|
|
157
|
+
stats["by_status"][status] = stats["by_status"].get(status, 0) + 1
|
|
163
158
|
|
|
164
159
|
# Count redirects (301, 302, 303, 307, 308)
|
|
165
|
-
if path.get(
|
|
166
|
-
stats[
|
|
160
|
+
if path.get("redirect"):
|
|
161
|
+
stats["redirects"] += 1
|
|
167
162
|
|
|
168
163
|
return stats
|
|
169
164
|
|
|
@@ -175,12 +170,277 @@ def categorize_status(status_code: int) -> str:
|
|
|
175
170
|
Returns: 'success', 'redirect', 'client_error', 'server_error', 'unknown'
|
|
176
171
|
"""
|
|
177
172
|
if 200 <= status_code < 300:
|
|
178
|
-
return
|
|
173
|
+
return "success"
|
|
179
174
|
elif 300 <= status_code < 400:
|
|
180
|
-
return
|
|
175
|
+
return "redirect"
|
|
181
176
|
elif 400 <= status_code < 500:
|
|
182
|
-
return
|
|
177
|
+
return "client_error"
|
|
183
178
|
elif 500 <= status_code < 600:
|
|
184
|
-
return
|
|
179
|
+
return "server_error"
|
|
185
180
|
else:
|
|
186
|
-
return
|
|
181
|
+
return "unknown"
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def generate_next_steps(parsed: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
185
|
+
"""
|
|
186
|
+
Generate suggested next steps based on gobuster findings.
|
|
187
|
+
|
|
188
|
+
Each step includes:
|
|
189
|
+
- title: Short description of what to try
|
|
190
|
+
- commands: Example commands to run
|
|
191
|
+
- reason: Why this step is suggested
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
parsed: Output from parse_gobuster_output()
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
List of next step dicts
|
|
198
|
+
"""
|
|
199
|
+
next_steps = []
|
|
200
|
+
paths = parsed.get("paths", [])
|
|
201
|
+
base_url = parsed.get("target_url", "").rstrip("/")
|
|
202
|
+
|
|
203
|
+
if not paths:
|
|
204
|
+
return next_steps
|
|
205
|
+
|
|
206
|
+
# Categorize found paths
|
|
207
|
+
git_paths = []
|
|
208
|
+
env_paths = []
|
|
209
|
+
backup_paths = []
|
|
210
|
+
admin_paths = []
|
|
211
|
+
cgi_paths = []
|
|
212
|
+
wp_paths = []
|
|
213
|
+
api_paths = []
|
|
214
|
+
config_paths = []
|
|
215
|
+
upload_paths = []
|
|
216
|
+
|
|
217
|
+
for path_info in paths:
|
|
218
|
+
path = path_info.get("path", "").lower()
|
|
219
|
+
url = path_info.get("url", "")
|
|
220
|
+
status = path_info.get("status_code", 0)
|
|
221
|
+
|
|
222
|
+
# Skip 404s
|
|
223
|
+
if status == 404:
|
|
224
|
+
continue
|
|
225
|
+
|
|
226
|
+
# Git exposure
|
|
227
|
+
if ".git" in path:
|
|
228
|
+
git_paths.append(url)
|
|
229
|
+
# Environment files
|
|
230
|
+
elif ".env" in path or "env." in path:
|
|
231
|
+
env_paths.append(url)
|
|
232
|
+
# Backup files
|
|
233
|
+
elif any(
|
|
234
|
+
ext in path
|
|
235
|
+
for ext in [".bak", ".backup", ".old", ".orig", ".save", ".swp", "~"]
|
|
236
|
+
):
|
|
237
|
+
backup_paths.append(url)
|
|
238
|
+
# Config files
|
|
239
|
+
elif any(
|
|
240
|
+
kw in path
|
|
241
|
+
for kw in [
|
|
242
|
+
"config",
|
|
243
|
+
"settings",
|
|
244
|
+
"database",
|
|
245
|
+
".ini",
|
|
246
|
+
".yml",
|
|
247
|
+
".yaml",
|
|
248
|
+
".xml",
|
|
249
|
+
".conf",
|
|
250
|
+
]
|
|
251
|
+
):
|
|
252
|
+
config_paths.append(url)
|
|
253
|
+
# Admin panels
|
|
254
|
+
elif any(
|
|
255
|
+
kw in path
|
|
256
|
+
for kw in ["admin", "manager", "dashboard", "cpanel", "webadmin", "control"]
|
|
257
|
+
):
|
|
258
|
+
admin_paths.append(url)
|
|
259
|
+
# CGI scripts
|
|
260
|
+
elif (
|
|
261
|
+
"/cgi-bin/" in path
|
|
262
|
+
or path.endswith(".cgi")
|
|
263
|
+
or path.endswith(".pl")
|
|
264
|
+
or path.endswith(".sh")
|
|
265
|
+
):
|
|
266
|
+
cgi_paths.append(url)
|
|
267
|
+
# WordPress
|
|
268
|
+
elif any(
|
|
269
|
+
kw in path
|
|
270
|
+
for kw in ["wp-", "wordpress", "wp-content", "wp-admin", "wp-includes"]
|
|
271
|
+
):
|
|
272
|
+
wp_paths.append(url)
|
|
273
|
+
# API endpoints
|
|
274
|
+
elif any(
|
|
275
|
+
kw in path
|
|
276
|
+
for kw in [
|
|
277
|
+
"/api",
|
|
278
|
+
"/rest",
|
|
279
|
+
"/graphql",
|
|
280
|
+
"/v1/",
|
|
281
|
+
"/v2/",
|
|
282
|
+
"/swagger",
|
|
283
|
+
"/openapi",
|
|
284
|
+
]
|
|
285
|
+
):
|
|
286
|
+
api_paths.append(url)
|
|
287
|
+
# Upload directories
|
|
288
|
+
elif any(
|
|
289
|
+
kw in path for kw in ["upload", "uploads", "files", "media", "attachments"]
|
|
290
|
+
):
|
|
291
|
+
upload_paths.append(url)
|
|
292
|
+
|
|
293
|
+
# Git repository exposure
|
|
294
|
+
if git_paths:
|
|
295
|
+
next_steps.append(
|
|
296
|
+
{
|
|
297
|
+
"title": "Extract source code from exposed .git",
|
|
298
|
+
"commands": [
|
|
299
|
+
f"git-dumper {git_paths[0]} ./git-dump",
|
|
300
|
+
f"# Or manually: wget -r -np -nH --cut-dirs=1 {git_paths[0]}",
|
|
301
|
+
],
|
|
302
|
+
"reason": f"Found .git directory - may contain full source code and commit history",
|
|
303
|
+
}
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# Environment file exposure
|
|
307
|
+
if env_paths:
|
|
308
|
+
next_steps.append(
|
|
309
|
+
{
|
|
310
|
+
"title": "Check exposed environment files for secrets",
|
|
311
|
+
"commands": [f'curl -s "{url}"' for url in env_paths[:3]],
|
|
312
|
+
"reason": f"Found {len(env_paths)} .env file(s) - likely contains API keys, passwords, database creds",
|
|
313
|
+
}
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
# Backup files
|
|
317
|
+
if backup_paths:
|
|
318
|
+
next_steps.append(
|
|
319
|
+
{
|
|
320
|
+
"title": "Download backup files for source review",
|
|
321
|
+
"commands": [
|
|
322
|
+
f'curl -s "{url}" -o backup_file' for url in backup_paths[:3]
|
|
323
|
+
],
|
|
324
|
+
"reason": f"Found {len(backup_paths)} backup file(s) - may contain source code or sensitive data",
|
|
325
|
+
}
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
# Config files
|
|
329
|
+
if config_paths:
|
|
330
|
+
next_steps.append(
|
|
331
|
+
{
|
|
332
|
+
"title": "Review configuration files for sensitive data",
|
|
333
|
+
"commands": [f'curl -s "{url}"' for url in config_paths[:3]],
|
|
334
|
+
"reason": f"Found {len(config_paths)} config file(s) - check for hardcoded credentials",
|
|
335
|
+
}
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
# Admin panels
|
|
339
|
+
if admin_paths:
|
|
340
|
+
next_steps.append(
|
|
341
|
+
{
|
|
342
|
+
"title": "Test admin panel with default credentials",
|
|
343
|
+
"commands": [
|
|
344
|
+
f"# Check login form at: {admin_paths[0]}",
|
|
345
|
+
f'hydra -L data/wordlists/usernames_common.txt -P data/wordlists/top20_quick.txt {base_url} http-post-form "/admin:user=^USER^&pass=^PASS^:Invalid"',
|
|
346
|
+
],
|
|
347
|
+
"reason": f"Found {len(admin_paths)} admin panel(s) - try admin:admin, admin:password, etc.",
|
|
348
|
+
}
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
# CGI scripts
|
|
352
|
+
if cgi_paths:
|
|
353
|
+
example = cgi_paths[0]
|
|
354
|
+
next_steps.append(
|
|
355
|
+
{
|
|
356
|
+
"title": "Test CGI scripts for command injection",
|
|
357
|
+
"commands": [
|
|
358
|
+
f'curl "{example}?cmd=id"',
|
|
359
|
+
f'curl "{example}?file=/etc/passwd"',
|
|
360
|
+
],
|
|
361
|
+
"reason": f"Found {len(cgi_paths)} CGI script(s) - test for command injection and LFI",
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
next_steps.append(
|
|
365
|
+
{
|
|
366
|
+
"title": "Test for Shellshock (CVE-2014-6271)",
|
|
367
|
+
"commands": [
|
|
368
|
+
f"curl -A '() {{ :; }}; echo; /bin/id' \"{example}\"",
|
|
369
|
+
f'curl -H "Cookie: () {{ :; }}; /bin/id" "{example}"',
|
|
370
|
+
],
|
|
371
|
+
"reason": "CGI scripts may be vulnerable to Shellshock on older systems",
|
|
372
|
+
}
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
# WordPress paths
|
|
376
|
+
if wp_paths:
|
|
377
|
+
next_steps.append(
|
|
378
|
+
{
|
|
379
|
+
"title": "Run WPScan for WordPress enumeration",
|
|
380
|
+
"commands": [
|
|
381
|
+
f"wpscan --url {base_url} --enumerate u,p,t,cb",
|
|
382
|
+
f"wpscan --url {base_url} --passwords data/wordlists/passwords_brute.txt --usernames admin",
|
|
383
|
+
],
|
|
384
|
+
"reason": f"WordPress detected - enumerate users, plugins, themes for vulnerabilities",
|
|
385
|
+
}
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
# API endpoints
|
|
389
|
+
if api_paths:
|
|
390
|
+
next_steps.append(
|
|
391
|
+
{
|
|
392
|
+
"title": "Enumerate API endpoints",
|
|
393
|
+
"commands": [
|
|
394
|
+
f'curl -s "{api_paths[0]}" | jq .',
|
|
395
|
+
f'ffuf -u "{base_url}/api/FUZZ" -w data/wordlists/api_endpoints_large.txt',
|
|
396
|
+
],
|
|
397
|
+
"reason": f"Found {len(api_paths)} API endpoint(s) - test for auth bypass, IDOR, injection",
|
|
398
|
+
}
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
# Upload directories
|
|
402
|
+
if upload_paths:
|
|
403
|
+
next_steps.append(
|
|
404
|
+
{
|
|
405
|
+
"title": "Check upload directory for unrestricted file upload",
|
|
406
|
+
"commands": [
|
|
407
|
+
f'curl -s "{upload_paths[0]}"',
|
|
408
|
+
f'# If writable, test: curl -X PUT -d "@shell.php" "{upload_paths[0]}/shell.php"',
|
|
409
|
+
],
|
|
410
|
+
"reason": f"Found upload directory - check for directory listing and file upload vulnerabilities",
|
|
411
|
+
}
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
# If we found interesting 403 paths, suggest bypass techniques
|
|
415
|
+
forbidden_paths = [p for p in paths if p.get("status_code") == 403]
|
|
416
|
+
interesting_forbidden = [
|
|
417
|
+
p
|
|
418
|
+
for p in forbidden_paths
|
|
419
|
+
if any(
|
|
420
|
+
kw in p.get("path", "").lower()
|
|
421
|
+
for kw in [
|
|
422
|
+
"admin",
|
|
423
|
+
"api",
|
|
424
|
+
"config",
|
|
425
|
+
"backup",
|
|
426
|
+
"internal",
|
|
427
|
+
"private",
|
|
428
|
+
"secret",
|
|
429
|
+
]
|
|
430
|
+
)
|
|
431
|
+
]
|
|
432
|
+
if interesting_forbidden:
|
|
433
|
+
example = interesting_forbidden[0].get("url", "")
|
|
434
|
+
next_steps.append(
|
|
435
|
+
{
|
|
436
|
+
"title": "403 bypass techniques for restricted paths",
|
|
437
|
+
"commands": [
|
|
438
|
+
f'# Try path traversal: curl "{example}..;/"',
|
|
439
|
+
f'# Try header bypass: curl -H "X-Original-URL: {interesting_forbidden[0].get("path", "")}" "{base_url}"',
|
|
440
|
+
f'# Try method override: curl -X POST "{example}"',
|
|
441
|
+
],
|
|
442
|
+
"reason": f"Found {len(interesting_forbidden)} interesting 403 path(s) - worth trying bypass techniques",
|
|
443
|
+
}
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
return next_steps
|