souleyez 2.43.29__py3-none-any.whl → 2.43.34__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of souleyez might be problematic. Click here for more details.
- souleyez/__init__.py +1 -2
- souleyez/ai/__init__.py +21 -15
- souleyez/ai/action_mapper.py +249 -150
- souleyez/ai/chain_advisor.py +116 -100
- souleyez/ai/claude_provider.py +29 -28
- souleyez/ai/context_builder.py +80 -62
- souleyez/ai/executor.py +158 -117
- souleyez/ai/feedback_handler.py +136 -121
- souleyez/ai/llm_factory.py +27 -20
- souleyez/ai/llm_provider.py +4 -2
- souleyez/ai/ollama_provider.py +6 -9
- souleyez/ai/ollama_service.py +44 -37
- souleyez/ai/path_scorer.py +91 -76
- souleyez/ai/recommender.py +176 -144
- souleyez/ai/report_context.py +74 -73
- souleyez/ai/report_service.py +84 -66
- souleyez/ai/result_parser.py +222 -229
- souleyez/ai/safety.py +67 -44
- souleyez/auth/__init__.py +23 -22
- souleyez/auth/audit.py +36 -26
- souleyez/auth/engagement_access.py +65 -48
- souleyez/auth/permissions.py +14 -3
- souleyez/auth/session_manager.py +54 -37
- souleyez/auth/user_manager.py +109 -64
- souleyez/commands/audit.py +40 -43
- souleyez/commands/auth.py +35 -15
- souleyez/commands/deliverables.py +55 -50
- souleyez/commands/engagement.py +47 -28
- souleyez/commands/license.py +32 -23
- souleyez/commands/screenshots.py +36 -32
- souleyez/commands/user.py +82 -36
- souleyez/config.py +52 -44
- souleyez/core/credential_tester.py +87 -81
- souleyez/core/cve_mappings.py +179 -192
- souleyez/core/cve_matcher.py +162 -148
- souleyez/core/msf_auto_mapper.py +100 -83
- souleyez/core/msf_chain_engine.py +294 -256
- souleyez/core/msf_database.py +153 -70
- souleyez/core/msf_integration.py +679 -673
- souleyez/core/msf_rpc_client.py +40 -42
- souleyez/core/msf_rpc_manager.py +77 -79
- souleyez/core/msf_sync_manager.py +241 -181
- souleyez/core/network_utils.py +22 -15
- souleyez/core/parser_handler.py +34 -25
- souleyez/core/pending_chains.py +114 -63
- souleyez/core/templates.py +158 -107
- souleyez/core/tool_chaining.py +9526 -2879
- souleyez/core/version_utils.py +79 -94
- souleyez/core/vuln_correlation.py +136 -89
- souleyez/core/web_utils.py +33 -32
- souleyez/data/wordlists/ad_users.txt +378 -0
- souleyez/data/wordlists/api_endpoints_large.txt +769 -0
- souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
- souleyez/data/wordlists/lfi_payloads.txt +82 -0
- souleyez/data/wordlists/passwords_brute.txt +1548 -0
- souleyez/data/wordlists/passwords_crack.txt +2479 -0
- souleyez/data/wordlists/passwords_spray.txt +386 -0
- souleyez/data/wordlists/subdomains_large.txt +5057 -0
- souleyez/data/wordlists/usernames_common.txt +694 -0
- souleyez/data/wordlists/web_dirs_large.txt +4769 -0
- souleyez/detection/__init__.py +1 -1
- souleyez/detection/attack_signatures.py +12 -17
- souleyez/detection/mitre_mappings.py +61 -55
- souleyez/detection/validator.py +97 -86
- souleyez/devtools.py +23 -10
- souleyez/docs/README.md +4 -4
- souleyez/docs/api-reference/cli-commands.md +2 -2
- souleyez/docs/developer-guide/adding-new-tools.md +562 -0
- souleyez/docs/user-guide/auto-chaining.md +30 -8
- souleyez/docs/user-guide/getting-started.md +1 -1
- souleyez/docs/user-guide/installation.md +26 -3
- souleyez/docs/user-guide/metasploit-integration.md +2 -2
- souleyez/docs/user-guide/rbac.md +1 -1
- souleyez/docs/user-guide/scope-management.md +1 -1
- souleyez/docs/user-guide/siem-integration.md +1 -1
- souleyez/docs/user-guide/tools-reference.md +1 -8
- souleyez/docs/user-guide/worker-management.md +1 -1
- souleyez/engine/background.py +1239 -535
- souleyez/engine/base.py +4 -1
- souleyez/engine/job_status.py +17 -49
- souleyez/engine/log_sanitizer.py +103 -77
- souleyez/engine/manager.py +38 -7
- souleyez/engine/result_handler.py +2200 -1550
- souleyez/engine/worker_manager.py +50 -41
- souleyez/export/evidence_bundle.py +72 -62
- souleyez/feature_flags/features.py +16 -20
- souleyez/feature_flags.py +5 -9
- souleyez/handlers/__init__.py +11 -0
- souleyez/handlers/base.py +188 -0
- souleyez/handlers/bash_handler.py +277 -0
- souleyez/handlers/bloodhound_handler.py +243 -0
- souleyez/handlers/certipy_handler.py +311 -0
- souleyez/handlers/crackmapexec_handler.py +486 -0
- souleyez/handlers/dnsrecon_handler.py +344 -0
- souleyez/handlers/enum4linux_handler.py +400 -0
- souleyez/handlers/evil_winrm_handler.py +493 -0
- souleyez/handlers/ffuf_handler.py +815 -0
- souleyez/handlers/gobuster_handler.py +1114 -0
- souleyez/handlers/gpp_extract_handler.py +334 -0
- souleyez/handlers/hashcat_handler.py +444 -0
- souleyez/handlers/hydra_handler.py +563 -0
- souleyez/handlers/impacket_getuserspns_handler.py +343 -0
- souleyez/handlers/impacket_psexec_handler.py +222 -0
- souleyez/handlers/impacket_secretsdump_handler.py +426 -0
- souleyez/handlers/john_handler.py +286 -0
- souleyez/handlers/katana_handler.py +425 -0
- souleyez/handlers/kerbrute_handler.py +298 -0
- souleyez/handlers/ldapsearch_handler.py +636 -0
- souleyez/handlers/lfi_extract_handler.py +464 -0
- souleyez/handlers/msf_auxiliary_handler.py +408 -0
- souleyez/handlers/msf_exploit_handler.py +380 -0
- souleyez/handlers/nikto_handler.py +413 -0
- souleyez/handlers/nmap_handler.py +821 -0
- souleyez/handlers/nuclei_handler.py +359 -0
- souleyez/handlers/nxc_handler.py +371 -0
- souleyez/handlers/rdp_sec_check_handler.py +353 -0
- souleyez/handlers/registry.py +292 -0
- souleyez/handlers/responder_handler.py +232 -0
- souleyez/handlers/service_explorer_handler.py +434 -0
- souleyez/handlers/smbclient_handler.py +344 -0
- souleyez/handlers/smbmap_handler.py +510 -0
- souleyez/handlers/smbpasswd_handler.py +296 -0
- souleyez/handlers/sqlmap_handler.py +1116 -0
- souleyez/handlers/theharvester_handler.py +601 -0
- souleyez/handlers/web_login_test_handler.py +327 -0
- souleyez/handlers/whois_handler.py +277 -0
- souleyez/handlers/wpscan_handler.py +554 -0
- souleyez/history.py +32 -16
- souleyez/importers/msf_importer.py +106 -75
- souleyez/importers/smart_importer.py +208 -147
- souleyez/integrations/siem/__init__.py +10 -10
- souleyez/integrations/siem/base.py +17 -18
- souleyez/integrations/siem/elastic.py +108 -122
- souleyez/integrations/siem/factory.py +207 -80
- souleyez/integrations/siem/googlesecops.py +146 -154
- souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
- souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
- souleyez/integrations/siem/sentinel.py +107 -109
- souleyez/integrations/siem/splunk.py +246 -212
- souleyez/integrations/siem/wazuh.py +65 -71
- souleyez/integrations/wazuh/__init__.py +5 -5
- souleyez/integrations/wazuh/client.py +70 -93
- souleyez/integrations/wazuh/config.py +85 -57
- souleyez/integrations/wazuh/host_mapper.py +28 -36
- souleyez/integrations/wazuh/sync.py +78 -68
- souleyez/intelligence/__init__.py +4 -5
- souleyez/intelligence/correlation_analyzer.py +309 -295
- souleyez/intelligence/exploit_knowledge.py +661 -623
- souleyez/intelligence/exploit_suggestions.py +159 -139
- souleyez/intelligence/gap_analyzer.py +132 -97
- souleyez/intelligence/gap_detector.py +251 -214
- souleyez/intelligence/sensitive_tables.py +266 -129
- souleyez/intelligence/service_parser.py +137 -123
- souleyez/intelligence/surface_analyzer.py +407 -268
- souleyez/intelligence/target_parser.py +159 -162
- souleyez/licensing/__init__.py +6 -6
- souleyez/licensing/validator.py +17 -19
- souleyez/log_config.py +79 -54
- souleyez/main.py +1505 -687
- souleyez/migrations/fix_job_counter.py +16 -14
- souleyez/parsers/bloodhound_parser.py +41 -39
- souleyez/parsers/crackmapexec_parser.py +178 -111
- souleyez/parsers/dalfox_parser.py +72 -77
- souleyez/parsers/dnsrecon_parser.py +103 -91
- souleyez/parsers/enum4linux_parser.py +183 -153
- souleyez/parsers/ffuf_parser.py +29 -25
- souleyez/parsers/gobuster_parser.py +301 -41
- souleyez/parsers/hashcat_parser.py +324 -79
- souleyez/parsers/http_fingerprint_parser.py +350 -103
- souleyez/parsers/hydra_parser.py +131 -111
- souleyez/parsers/impacket_parser.py +231 -178
- souleyez/parsers/john_parser.py +98 -86
- souleyez/parsers/katana_parser.py +316 -0
- souleyez/parsers/msf_parser.py +943 -498
- souleyez/parsers/nikto_parser.py +346 -65
- souleyez/parsers/nmap_parser.py +262 -174
- souleyez/parsers/nuclei_parser.py +40 -44
- souleyez/parsers/responder_parser.py +26 -26
- souleyez/parsers/searchsploit_parser.py +74 -74
- souleyez/parsers/service_explorer_parser.py +279 -0
- souleyez/parsers/smbmap_parser.py +180 -124
- souleyez/parsers/sqlmap_parser.py +434 -308
- souleyez/parsers/theharvester_parser.py +75 -57
- souleyez/parsers/whois_parser.py +135 -94
- souleyez/parsers/wpscan_parser.py +278 -190
- souleyez/plugins/afp.py +44 -36
- souleyez/plugins/afp_brute.py +114 -46
- souleyez/plugins/ard.py +48 -37
- souleyez/plugins/bloodhound.py +95 -61
- souleyez/plugins/certipy.py +303 -0
- souleyez/plugins/crackmapexec.py +186 -85
- souleyez/plugins/dalfox.py +120 -59
- souleyez/plugins/dns_hijack.py +146 -41
- souleyez/plugins/dnsrecon.py +97 -61
- souleyez/plugins/enum4linux.py +91 -66
- souleyez/plugins/evil_winrm.py +291 -0
- souleyez/plugins/ffuf.py +166 -90
- souleyez/plugins/firmware_extract.py +133 -29
- souleyez/plugins/gobuster.py +387 -190
- souleyez/plugins/gpp_extract.py +393 -0
- souleyez/plugins/hashcat.py +100 -73
- souleyez/plugins/http_fingerprint.py +854 -267
- souleyez/plugins/hydra.py +566 -200
- souleyez/plugins/impacket_getnpusers.py +117 -69
- souleyez/plugins/impacket_psexec.py +84 -64
- souleyez/plugins/impacket_secretsdump.py +103 -69
- souleyez/plugins/impacket_smbclient.py +89 -75
- souleyez/plugins/john.py +86 -69
- souleyez/plugins/katana.py +313 -0
- souleyez/plugins/kerbrute.py +237 -0
- souleyez/plugins/lfi_extract.py +541 -0
- souleyez/plugins/macos_ssh.py +117 -48
- souleyez/plugins/mdns.py +35 -30
- souleyez/plugins/msf_auxiliary.py +253 -130
- souleyez/plugins/msf_exploit.py +239 -161
- souleyez/plugins/nikto.py +134 -78
- souleyez/plugins/nmap.py +275 -91
- souleyez/plugins/nuclei.py +180 -89
- souleyez/plugins/nxc.py +285 -0
- souleyez/plugins/plugin_base.py +35 -36
- souleyez/plugins/plugin_template.py +13 -5
- souleyez/plugins/rdp_sec_check.py +130 -0
- souleyez/plugins/responder.py +112 -71
- souleyez/plugins/router_http_brute.py +76 -65
- souleyez/plugins/router_ssh_brute.py +118 -41
- souleyez/plugins/router_telnet_brute.py +124 -42
- souleyez/plugins/routersploit.py +91 -59
- souleyez/plugins/routersploit_exploit.py +77 -55
- souleyez/plugins/searchsploit.py +91 -77
- souleyez/plugins/service_explorer.py +1160 -0
- souleyez/plugins/smbmap.py +122 -72
- souleyez/plugins/smbpasswd.py +215 -0
- souleyez/plugins/sqlmap.py +301 -113
- souleyez/plugins/theharvester.py +127 -75
- souleyez/plugins/tr069.py +79 -57
- souleyez/plugins/upnp.py +65 -47
- souleyez/plugins/upnp_abuse.py +73 -55
- souleyez/plugins/vnc_access.py +129 -42
- souleyez/plugins/vnc_brute.py +109 -38
- souleyez/plugins/web_login_test.py +417 -0
- souleyez/plugins/whois.py +77 -58
- souleyez/plugins/wpscan.py +173 -69
- souleyez/reporting/__init__.py +2 -1
- souleyez/reporting/attack_chain.py +411 -346
- souleyez/reporting/charts.py +436 -501
- souleyez/reporting/compliance_mappings.py +334 -201
- souleyez/reporting/detection_report.py +126 -125
- souleyez/reporting/formatters.py +828 -591
- souleyez/reporting/generator.py +386 -302
- souleyez/reporting/metrics.py +72 -75
- souleyez/scanner.py +35 -29
- souleyez/security/__init__.py +37 -11
- souleyez/security/scope_validator.py +175 -106
- souleyez/security/validation.py +223 -149
- souleyez/security.py +22 -6
- souleyez/storage/credentials.py +247 -186
- souleyez/storage/crypto.py +296 -129
- souleyez/storage/database.py +73 -50
- souleyez/storage/db.py +58 -36
- souleyez/storage/deliverable_evidence.py +177 -128
- souleyez/storage/deliverable_exporter.py +282 -246
- souleyez/storage/deliverable_templates.py +134 -116
- souleyez/storage/deliverables.py +135 -130
- souleyez/storage/engagements.py +109 -56
- souleyez/storage/evidence.py +181 -152
- souleyez/storage/execution_log.py +31 -17
- souleyez/storage/exploit_attempts.py +93 -57
- souleyez/storage/exploits.py +67 -36
- souleyez/storage/findings.py +48 -61
- souleyez/storage/hosts.py +176 -144
- souleyez/storage/migrate_to_engagements.py +43 -19
- souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
- souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
- souleyez/storage/migrations/_003_add_execution_log.py +14 -8
- souleyez/storage/migrations/_005_screenshots.py +13 -5
- souleyez/storage/migrations/_006_deliverables.py +13 -5
- souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
- souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
- souleyez/storage/migrations/_010_evidence_linking.py +17 -10
- souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
- souleyez/storage/migrations/_012_team_collaboration.py +34 -21
- souleyez/storage/migrations/_013_add_host_tags.py +12 -6
- souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
- souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
- souleyez/storage/migrations/_016_add_domain_field.py +10 -4
- souleyez/storage/migrations/_017_msf_sessions.py +16 -8
- souleyez/storage/migrations/_018_add_osint_target.py +10 -6
- souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
- souleyez/storage/migrations/_020_add_rbac.py +36 -15
- souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
- souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
- souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
- souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
- souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
- souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
- souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
- souleyez/storage/migrations/__init__.py +26 -26
- souleyez/storage/migrations/migration_manager.py +19 -19
- souleyez/storage/msf_sessions.py +100 -65
- souleyez/storage/osint.py +17 -24
- souleyez/storage/recommendation_engine.py +269 -235
- souleyez/storage/screenshots.py +33 -32
- souleyez/storage/smb_shares.py +136 -92
- souleyez/storage/sqlmap_data.py +183 -128
- souleyez/storage/team_collaboration.py +135 -141
- souleyez/storage/timeline_tracker.py +122 -94
- souleyez/storage/wazuh_vulns.py +64 -66
- souleyez/storage/web_paths.py +33 -37
- souleyez/testing/credential_tester.py +221 -205
- souleyez/ui/__init__.py +1 -1
- souleyez/ui/ai_quotes.py +12 -12
- souleyez/ui/attack_surface.py +2439 -1516
- souleyez/ui/chain_rules_view.py +914 -382
- souleyez/ui/correlation_view.py +312 -230
- souleyez/ui/dashboard.py +2382 -1130
- souleyez/ui/deliverables_view.py +148 -62
- souleyez/ui/design_system.py +13 -13
- souleyez/ui/errors.py +49 -49
- souleyez/ui/evidence_linking_view.py +284 -179
- souleyez/ui/evidence_vault.py +393 -285
- souleyez/ui/exploit_suggestions_view.py +555 -349
- souleyez/ui/export_view.py +100 -66
- souleyez/ui/gap_analysis_view.py +315 -171
- souleyez/ui/help_system.py +105 -97
- souleyez/ui/intelligence_view.py +436 -293
- souleyez/ui/interactive.py +22827 -10678
- souleyez/ui/interactive_selector.py +75 -68
- souleyez/ui/log_formatter.py +47 -39
- souleyez/ui/menu_components.py +22 -13
- souleyez/ui/msf_auxiliary_menu.py +184 -133
- souleyez/ui/pending_chains_view.py +336 -172
- souleyez/ui/progress_indicators.py +5 -3
- souleyez/ui/recommendations_view.py +195 -137
- souleyez/ui/rule_builder.py +343 -225
- souleyez/ui/setup_wizard.py +678 -284
- souleyez/ui/shortcuts.py +217 -165
- souleyez/ui/splunk_gap_analysis_view.py +452 -270
- souleyez/ui/splunk_vulns_view.py +139 -86
- souleyez/ui/team_dashboard.py +498 -335
- souleyez/ui/template_selector.py +196 -105
- souleyez/ui/terminal.py +6 -6
- souleyez/ui/timeline_view.py +198 -127
- souleyez/ui/tool_setup.py +264 -164
- souleyez/ui/tutorial.py +202 -72
- souleyez/ui/tutorial_state.py +40 -40
- souleyez/ui/wazuh_vulns_view.py +235 -141
- souleyez/ui/wordlist_browser.py +260 -107
- souleyez/ui.py +464 -312
- souleyez/utils/tool_checker.py +427 -367
- souleyez/utils.py +33 -29
- souleyez/wordlists.py +134 -167
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/METADATA +1 -1
- souleyez-2.43.34.dist-info/RECORD +443 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
- souleyez-2.43.29.dist-info/RECORD +0 -379
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
souleyez/ai/action_mapper.py
CHANGED
|
@@ -12,7 +12,7 @@ logger = logging.getLogger(__name__)
|
|
|
12
12
|
class ActionMapper:
|
|
13
13
|
"""
|
|
14
14
|
Maps AI recommendations to executable commands.
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
Handles translation of natural language actions into
|
|
17
17
|
concrete shell commands.
|
|
18
18
|
"""
|
|
@@ -20,12 +20,15 @@ class ActionMapper:
|
|
|
20
20
|
def __init__(self):
|
|
21
21
|
"""Initialize action mapper."""
|
|
22
22
|
from ..storage.credentials import CredentialsManager
|
|
23
|
+
|
|
23
24
|
self.creds_mgr = CredentialsManager()
|
|
24
25
|
|
|
25
|
-
def map_to_command(
|
|
26
|
+
def map_to_command(
|
|
27
|
+
self, recommendation: Dict[str, Any], engagement_id: Optional[int] = None
|
|
28
|
+
) -> Optional[str]:
|
|
26
29
|
"""
|
|
27
30
|
Map AI recommendation to executable command.
|
|
28
|
-
|
|
31
|
+
|
|
29
32
|
Args:
|
|
30
33
|
recommendation: Dict with keys:
|
|
31
34
|
- action: Human-readable action
|
|
@@ -34,150 +37,203 @@ class ActionMapper:
|
|
|
34
37
|
- expected_outcome: Expected result
|
|
35
38
|
- risk_level: Risk level
|
|
36
39
|
engagement_id: Optional engagement ID for credential lookup
|
|
37
|
-
|
|
40
|
+
|
|
38
41
|
Returns:
|
|
39
42
|
Shell command string or None if can't map
|
|
40
43
|
"""
|
|
41
|
-
action = recommendation.get(
|
|
42
|
-
target = recommendation.get(
|
|
43
|
-
rationale = recommendation.get(
|
|
44
|
-
|
|
44
|
+
action = recommendation.get("action", "").lower()
|
|
45
|
+
target = recommendation.get("target", "")
|
|
46
|
+
rationale = recommendation.get("rationale", "").lower()
|
|
47
|
+
|
|
45
48
|
# Extract IP and port from target
|
|
46
|
-
ip_match = re.search(r
|
|
47
|
-
port_match = re.search(r
|
|
48
|
-
|
|
49
|
+
ip_match = re.search(r"\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b", target)
|
|
50
|
+
port_match = re.search(r":(\d+)", target)
|
|
51
|
+
|
|
49
52
|
ip = ip_match.group(1) if ip_match else None
|
|
50
53
|
port = port_match.group(1) if port_match else None
|
|
51
|
-
|
|
54
|
+
|
|
52
55
|
if not ip:
|
|
53
56
|
logger.warning(f"Could not extract IP from target: {target}")
|
|
54
57
|
return None
|
|
55
|
-
|
|
58
|
+
|
|
56
59
|
# PostgreSQL credential testing (check before MySQL)
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
if ("postgres" in action or "postgresql" in action or "psql" in action) and (
|
|
61
|
+
"test" in action or "login" in action or "credential" in action
|
|
62
|
+
):
|
|
63
|
+
return self._map_postgresql_test(
|
|
64
|
+
ip, port or "5432", recommendation, engagement_id
|
|
65
|
+
)
|
|
66
|
+
|
|
61
67
|
# MySQL credential testing (check before SSH)
|
|
62
|
-
if
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
if "mysql" in action and (
|
|
69
|
+
"test" in action or "login" in action or "credential" in action
|
|
70
|
+
):
|
|
71
|
+
return self._map_mysql_test(
|
|
72
|
+
ip, port or "3306", recommendation, engagement_id
|
|
73
|
+
)
|
|
74
|
+
|
|
65
75
|
# MySQL enumeration (expanded patterns - check before SSH)
|
|
66
|
-
if
|
|
67
|
-
|
|
68
|
-
|
|
76
|
+
if "mysql" in action and (
|
|
77
|
+
"enum" in action or "database" in action or "data" in action
|
|
78
|
+
):
|
|
79
|
+
return self._map_mysql_enum(
|
|
80
|
+
ip, port or "3306", recommendation, engagement_id
|
|
81
|
+
)
|
|
82
|
+
|
|
69
83
|
# SMB credential testing
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
if (
|
|
85
|
+
"smb" in action
|
|
86
|
+
or "cifs" in action
|
|
87
|
+
or "smb" in target.lower()
|
|
88
|
+
or ("authenticate" in action or "login" in action or "credential" in action)
|
|
89
|
+
and ("445" in target or "139" in target or "smb" in rationale)
|
|
90
|
+
):
|
|
91
|
+
return self._map_smb_test(ip, port or "445", recommendation, engagement_id)
|
|
92
|
+
|
|
75
93
|
# RDP credential testing
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
94
|
+
if (
|
|
95
|
+
"rdp" in action
|
|
96
|
+
or "rdp" in target.lower()
|
|
97
|
+
or "remote desktop" in action
|
|
98
|
+
or ("authenticate" in action or "login" in action or "credential" in action)
|
|
99
|
+
and ("3389" in target or "rdp" in rationale)
|
|
100
|
+
):
|
|
101
|
+
return self._map_rdp_test(ip, port or "3389", recommendation, engagement_id)
|
|
102
|
+
|
|
81
103
|
# FTP credential testing
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
104
|
+
if (
|
|
105
|
+
"ftp" in action
|
|
106
|
+
or "ftp" in target.lower()
|
|
107
|
+
or ("authenticate" in action or "login" in action or "credential" in action)
|
|
108
|
+
and ("21" in target or "ftp" in rationale)
|
|
109
|
+
):
|
|
110
|
+
return self._map_ftp_test(ip, port or "21", recommendation, engagement_id)
|
|
111
|
+
|
|
87
112
|
# SSH credential testing (expanded patterns)
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
113
|
+
if (
|
|
114
|
+
"ssh" in action
|
|
115
|
+
or "ssh" in target.lower()
|
|
116
|
+
or ("authenticate" in action or "login" in action or "credential" in action)
|
|
117
|
+
and ("22" in target or "ssh" in rationale or not port)
|
|
118
|
+
):
|
|
119
|
+
return self._map_ssh_test(ip, port or "22", recommendation, engagement_id)
|
|
120
|
+
|
|
93
121
|
# HTTP/Web enumeration (BEFORE generic nmap scan)
|
|
94
|
-
if (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
122
|
+
if (
|
|
123
|
+
"http" in action
|
|
124
|
+
or "web" in action
|
|
125
|
+
or "directory" in action
|
|
126
|
+
or "path" in action
|
|
127
|
+
or "http" in target.lower()
|
|
128
|
+
or "web" in target.lower()
|
|
129
|
+
or ("enumerate" in action or "enum" in action)
|
|
130
|
+
and (
|
|
131
|
+
"http" in rationale
|
|
132
|
+
or "web" in rationale
|
|
133
|
+
or port in ["80", "443", "8080", "8443"]
|
|
134
|
+
)
|
|
135
|
+
):
|
|
98
136
|
return self._map_http_enum(ip, port, recommendation)
|
|
99
|
-
|
|
137
|
+
|
|
100
138
|
# Nmap port scan (keep as fallback, but more specific)
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
|
|
139
|
+
if (
|
|
140
|
+
"nmap" in action
|
|
141
|
+
or "port scan" in action
|
|
142
|
+
or ("scan" in action and "port" in action)
|
|
143
|
+
or ("discover" in action and "port" in action)
|
|
144
|
+
):
|
|
104
145
|
return self._map_nmap_scan(ip, recommendation)
|
|
105
|
-
|
|
146
|
+
|
|
106
147
|
# Service enumeration
|
|
107
|
-
if
|
|
148
|
+
if "enumerate" in action and "service" in action:
|
|
108
149
|
return self._map_service_enum(ip, port, recommendation)
|
|
109
|
-
|
|
150
|
+
|
|
110
151
|
logger.warning(f"No command mapping found for action: {action}")
|
|
111
152
|
return None
|
|
112
153
|
|
|
113
|
-
def _find_credentials(
|
|
154
|
+
def _find_credentials(
|
|
155
|
+
self, engagement_id: Optional[int], service: str, ip: Optional[str] = None
|
|
156
|
+
) -> Optional[tuple]:
|
|
114
157
|
"""
|
|
115
158
|
Find valid credentials from database.
|
|
116
|
-
|
|
159
|
+
|
|
117
160
|
Args:
|
|
118
161
|
engagement_id: Engagement ID
|
|
119
162
|
service: Service name (ssh, mysql, etc.)
|
|
120
163
|
ip: Optional IP to filter by
|
|
121
|
-
|
|
164
|
+
|
|
122
165
|
Returns:
|
|
123
166
|
Tuple of (username, password) or None
|
|
124
167
|
"""
|
|
125
168
|
if not engagement_id:
|
|
126
169
|
return None
|
|
127
|
-
|
|
170
|
+
|
|
128
171
|
try:
|
|
129
172
|
creds = self.creds_mgr.list_credentials(engagement_id)
|
|
130
|
-
|
|
173
|
+
|
|
131
174
|
# Look for valid credentials for this service
|
|
132
175
|
for cred in creds:
|
|
133
|
-
cred_service = cred.get(
|
|
134
|
-
cred_status = cred.get(
|
|
135
|
-
|
|
176
|
+
cred_service = cred.get("service", "").lower()
|
|
177
|
+
cred_status = cred.get("status", "untested")
|
|
178
|
+
|
|
136
179
|
if service.lower() in cred_service or cred_service in service.lower():
|
|
137
180
|
# Prefer valid credentials, but fall back to untested
|
|
138
|
-
if cred_status ==
|
|
139
|
-
return (cred.get(
|
|
140
|
-
|
|
181
|
+
if cred_status == "valid":
|
|
182
|
+
return (cred.get("username"), cred.get("password"))
|
|
183
|
+
|
|
141
184
|
# If no valid creds, try untested for same service
|
|
142
185
|
for cred in creds:
|
|
143
|
-
cred_service = cred.get(
|
|
144
|
-
cred_status = cred.get(
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
|
|
148
|
-
|
|
186
|
+
cred_service = cred.get("service", "").lower()
|
|
187
|
+
cred_status = cred.get("status", "untested")
|
|
188
|
+
|
|
189
|
+
if (
|
|
190
|
+
service.lower() in cred_service or cred_service in service.lower()
|
|
191
|
+
) and cred_status == "untested":
|
|
192
|
+
return (cred.get("username"), cred.get("password"))
|
|
193
|
+
|
|
149
194
|
# If still nothing and service is mysql, try SSH credentials (common on same host)
|
|
150
|
-
if service.lower() ==
|
|
195
|
+
if service.lower() == "mysql":
|
|
151
196
|
for cred in creds:
|
|
152
|
-
if
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
197
|
+
if (
|
|
198
|
+
cred.get("service", "").lower() == "ssh"
|
|
199
|
+
and cred.get("status") == "valid"
|
|
200
|
+
):
|
|
201
|
+
logger.info(
|
|
202
|
+
"Using SSH credentials for MySQL (common username on same host)"
|
|
203
|
+
)
|
|
204
|
+
return (cred.get("username"), cred.get("password"))
|
|
205
|
+
|
|
156
206
|
except Exception as e:
|
|
157
207
|
logger.error(f"Failed to lookup credentials: {e}")
|
|
158
|
-
|
|
208
|
+
|
|
159
209
|
return None
|
|
160
210
|
|
|
161
|
-
def _map_ssh_test(
|
|
211
|
+
def _map_ssh_test(
|
|
212
|
+
self,
|
|
213
|
+
ip: str,
|
|
214
|
+
port: str,
|
|
215
|
+
rec: Dict[str, Any],
|
|
216
|
+
engagement_id: Optional[int] = None,
|
|
217
|
+
) -> Optional[str]:
|
|
162
218
|
"""Map SSH credential testing to command."""
|
|
163
219
|
# Try to extract credentials from action or rationale
|
|
164
|
-
action = rec.get(
|
|
165
|
-
rationale = rec.get(
|
|
220
|
+
action = rec.get("action", "")
|
|
221
|
+
rationale = rec.get("rationale", "")
|
|
166
222
|
text = f"{action} {rationale}".lower()
|
|
167
|
-
|
|
223
|
+
|
|
168
224
|
# Look for credential patterns
|
|
169
|
-
cred_match = re.search(r
|
|
225
|
+
cred_match = re.search(r"(\w+):(\w+)", text)
|
|
170
226
|
if cred_match:
|
|
171
227
|
username = cred_match.group(1)
|
|
172
228
|
password = cred_match.group(2)
|
|
173
229
|
else:
|
|
174
230
|
# Try to find credentials from database
|
|
175
|
-
creds = self._find_credentials(engagement_id,
|
|
231
|
+
creds = self._find_credentials(engagement_id, "ssh", ip)
|
|
176
232
|
if not creds:
|
|
177
233
|
logger.warning("SSH test requested but no credentials found")
|
|
178
234
|
return None
|
|
179
235
|
username, password = creds
|
|
180
|
-
|
|
236
|
+
|
|
181
237
|
return (
|
|
182
238
|
f"sshpass -p '{password}' ssh -o ConnectTimeout=5 "
|
|
183
239
|
f"-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "
|
|
@@ -185,20 +241,26 @@ class ActionMapper:
|
|
|
185
241
|
f"-p {port} {username}@{ip} 'echo SSH_SUCCESS && whoami && id'"
|
|
186
242
|
)
|
|
187
243
|
|
|
188
|
-
def _map_ftp_test(
|
|
244
|
+
def _map_ftp_test(
|
|
245
|
+
self,
|
|
246
|
+
ip: str,
|
|
247
|
+
port: str,
|
|
248
|
+
rec: Dict[str, Any],
|
|
249
|
+
engagement_id: Optional[int] = None,
|
|
250
|
+
) -> Optional[str]:
|
|
189
251
|
"""Map FTP credential testing to command."""
|
|
190
|
-
action = rec.get(
|
|
191
|
-
rationale = rec.get(
|
|
252
|
+
action = rec.get("action", "")
|
|
253
|
+
rationale = rec.get("rationale", "")
|
|
192
254
|
text = f"{action} {rationale}".lower()
|
|
193
255
|
|
|
194
256
|
# Look for credential patterns
|
|
195
|
-
cred_match = re.search(r
|
|
257
|
+
cred_match = re.search(r"(\w+):(\w+)", text)
|
|
196
258
|
if cred_match:
|
|
197
259
|
username = cred_match.group(1)
|
|
198
260
|
password = cred_match.group(2)
|
|
199
261
|
else:
|
|
200
262
|
# Try to find credentials from database
|
|
201
|
-
creds = self._find_credentials(engagement_id,
|
|
263
|
+
creds = self._find_credentials(engagement_id, "ftp", ip)
|
|
202
264
|
if not creds:
|
|
203
265
|
logger.warning("FTP test requested but no credentials found")
|
|
204
266
|
return None
|
|
@@ -210,20 +272,26 @@ class ActionMapper:
|
|
|
210
272
|
f"echo 'FTP_FAILED'"
|
|
211
273
|
)
|
|
212
274
|
|
|
213
|
-
def _map_smb_test(
|
|
275
|
+
def _map_smb_test(
|
|
276
|
+
self,
|
|
277
|
+
ip: str,
|
|
278
|
+
port: str,
|
|
279
|
+
rec: Dict[str, Any],
|
|
280
|
+
engagement_id: Optional[int] = None,
|
|
281
|
+
) -> Optional[str]:
|
|
214
282
|
"""Map SMB credential testing to command."""
|
|
215
|
-
action = rec.get(
|
|
216
|
-
rationale = rec.get(
|
|
283
|
+
action = rec.get("action", "")
|
|
284
|
+
rationale = rec.get("rationale", "")
|
|
217
285
|
text = f"{action} {rationale}".lower()
|
|
218
286
|
|
|
219
287
|
# Look for credential patterns
|
|
220
|
-
cred_match = re.search(r
|
|
288
|
+
cred_match = re.search(r"(\w+):(\w+)", text)
|
|
221
289
|
if cred_match:
|
|
222
290
|
username = cred_match.group(1)
|
|
223
291
|
password = cred_match.group(2)
|
|
224
292
|
else:
|
|
225
293
|
# Try to find credentials from database
|
|
226
|
-
creds = self._find_credentials(engagement_id,
|
|
294
|
+
creds = self._find_credentials(engagement_id, "smb", ip)
|
|
227
295
|
if not creds:
|
|
228
296
|
logger.warning("SMB test requested but no credentials found")
|
|
229
297
|
return None
|
|
@@ -235,20 +303,26 @@ class ActionMapper:
|
|
|
235
303
|
f"-N 2>&1 || echo 'SMB_FAILED'"
|
|
236
304
|
)
|
|
237
305
|
|
|
238
|
-
def _map_rdp_test(
|
|
306
|
+
def _map_rdp_test(
|
|
307
|
+
self,
|
|
308
|
+
ip: str,
|
|
309
|
+
port: str,
|
|
310
|
+
rec: Dict[str, Any],
|
|
311
|
+
engagement_id: Optional[int] = None,
|
|
312
|
+
) -> Optional[str]:
|
|
239
313
|
"""Map RDP credential testing to command."""
|
|
240
|
-
action = rec.get(
|
|
241
|
-
rationale = rec.get(
|
|
314
|
+
action = rec.get("action", "")
|
|
315
|
+
rationale = rec.get("rationale", "")
|
|
242
316
|
text = f"{action} {rationale}".lower()
|
|
243
317
|
|
|
244
318
|
# Look for credential patterns
|
|
245
|
-
cred_match = re.search(r
|
|
319
|
+
cred_match = re.search(r"(\w+):(\w+)", text)
|
|
246
320
|
if cred_match:
|
|
247
321
|
username = cred_match.group(1)
|
|
248
322
|
password = cred_match.group(2)
|
|
249
323
|
else:
|
|
250
324
|
# Try to find credentials from database
|
|
251
|
-
creds = self._find_credentials(engagement_id,
|
|
325
|
+
creds = self._find_credentials(engagement_id, "rdp", ip)
|
|
252
326
|
if not creds:
|
|
253
327
|
logger.warning("RDP test requested but no credentials found")
|
|
254
328
|
return None
|
|
@@ -260,73 +334,91 @@ class ActionMapper:
|
|
|
260
334
|
f"/cert-ignore +auth-only /sec:nla 2>&1 || echo 'RDP_FAILED'"
|
|
261
335
|
)
|
|
262
336
|
|
|
263
|
-
def _map_mysql_test(
|
|
337
|
+
def _map_mysql_test(
|
|
338
|
+
self,
|
|
339
|
+
ip: str,
|
|
340
|
+
port: str,
|
|
341
|
+
rec: Dict[str, Any],
|
|
342
|
+
engagement_id: Optional[int] = None,
|
|
343
|
+
) -> Optional[str]:
|
|
264
344
|
"""Map MySQL credential testing to command."""
|
|
265
|
-
action = rec.get(
|
|
266
|
-
rationale = rec.get(
|
|
345
|
+
action = rec.get("action", "")
|
|
346
|
+
rationale = rec.get("rationale", "")
|
|
267
347
|
text = f"{action} {rationale}".lower()
|
|
268
|
-
|
|
348
|
+
|
|
269
349
|
# Look for credential patterns
|
|
270
|
-
cred_match = re.search(r
|
|
350
|
+
cred_match = re.search(r"(\w+):(\w+)", text)
|
|
271
351
|
if cred_match:
|
|
272
352
|
username = cred_match.group(1)
|
|
273
353
|
password = cred_match.group(2)
|
|
274
354
|
else:
|
|
275
355
|
# Try to find credentials from database
|
|
276
|
-
creds = self._find_credentials(engagement_id,
|
|
356
|
+
creds = self._find_credentials(engagement_id, "mysql", ip)
|
|
277
357
|
if not creds:
|
|
278
358
|
logger.warning("MySQL test requested but no credentials found")
|
|
279
359
|
return None
|
|
280
360
|
username, password = creds
|
|
281
|
-
|
|
361
|
+
|
|
282
362
|
return (
|
|
283
363
|
f"mysql -h {ip} -P {port} -u {username} -p'{password}' "
|
|
284
364
|
f"--skip-ssl "
|
|
285
365
|
f"-e 'SELECT version();' 2>&1"
|
|
286
366
|
)
|
|
287
367
|
|
|
288
|
-
def _map_mysql_enum(
|
|
368
|
+
def _map_mysql_enum(
|
|
369
|
+
self,
|
|
370
|
+
ip: str,
|
|
371
|
+
port: str,
|
|
372
|
+
rec: Dict[str, Any],
|
|
373
|
+
engagement_id: Optional[int] = None,
|
|
374
|
+
) -> Optional[str]:
|
|
289
375
|
"""Map MySQL enumeration to command."""
|
|
290
|
-
action = rec.get(
|
|
291
|
-
rationale = rec.get(
|
|
376
|
+
action = rec.get("action", "")
|
|
377
|
+
rationale = rec.get("rationale", "")
|
|
292
378
|
text = f"{action} {rationale}".lower()
|
|
293
|
-
|
|
379
|
+
|
|
294
380
|
# Look for credentials
|
|
295
|
-
cred_match = re.search(r
|
|
381
|
+
cred_match = re.search(r"(\w+):(\w+)", text)
|
|
296
382
|
if cred_match:
|
|
297
383
|
username = cred_match.group(1)
|
|
298
384
|
password = cred_match.group(2)
|
|
299
385
|
else:
|
|
300
386
|
# Try to find credentials from database
|
|
301
|
-
creds = self._find_credentials(engagement_id,
|
|
387
|
+
creds = self._find_credentials(engagement_id, "mysql", ip)
|
|
302
388
|
if not creds:
|
|
303
389
|
logger.warning("MySQL enumeration requested but no credentials found")
|
|
304
390
|
return None
|
|
305
391
|
username, password = creds
|
|
306
|
-
|
|
392
|
+
|
|
307
393
|
return (
|
|
308
394
|
f"mysql -h {ip} -P {port} -u {username} -p'{password}' "
|
|
309
395
|
f"--skip-ssl "
|
|
310
396
|
f"-e 'SHOW DATABASES; SELECT user,host FROM mysql.user;' 2>&1"
|
|
311
397
|
)
|
|
312
398
|
|
|
313
|
-
def _map_postgresql_test(
|
|
399
|
+
def _map_postgresql_test(
|
|
400
|
+
self,
|
|
401
|
+
ip: str,
|
|
402
|
+
port: str,
|
|
403
|
+
rec: Dict[str, Any],
|
|
404
|
+
engagement_id: Optional[int] = None,
|
|
405
|
+
) -> Optional[str]:
|
|
314
406
|
"""Map PostgreSQL credential testing to command."""
|
|
315
|
-
action = rec.get(
|
|
316
|
-
rationale = rec.get(
|
|
407
|
+
action = rec.get("action", "")
|
|
408
|
+
rationale = rec.get("rationale", "")
|
|
317
409
|
text = f"{action} {rationale}".lower()
|
|
318
410
|
|
|
319
411
|
# Look for credential patterns
|
|
320
|
-
cred_match = re.search(r
|
|
412
|
+
cred_match = re.search(r"(\w+):(\w+)", text)
|
|
321
413
|
if cred_match:
|
|
322
414
|
username = cred_match.group(1)
|
|
323
415
|
password = cred_match.group(2)
|
|
324
416
|
else:
|
|
325
417
|
# Try to find credentials from database
|
|
326
|
-
creds = self._find_credentials(engagement_id,
|
|
418
|
+
creds = self._find_credentials(engagement_id, "postgresql", ip)
|
|
327
419
|
if not creds:
|
|
328
420
|
# Also try 'postgres' service name
|
|
329
|
-
creds = self._find_credentials(engagement_id,
|
|
421
|
+
creds = self._find_credentials(engagement_id, "postgres", ip)
|
|
330
422
|
if not creds:
|
|
331
423
|
logger.warning("PostgreSQL test requested but no credentials found")
|
|
332
424
|
return None
|
|
@@ -339,12 +431,12 @@ class ActionMapper:
|
|
|
339
431
|
|
|
340
432
|
def _map_nmap_scan(self, ip: str, rec: Dict[str, Any]) -> str:
|
|
341
433
|
"""Map nmap scanning to command."""
|
|
342
|
-
action = rec.get(
|
|
343
|
-
|
|
434
|
+
action = rec.get("action", "").lower()
|
|
435
|
+
|
|
344
436
|
# Quick scan by default
|
|
345
|
-
if
|
|
437
|
+
if "full" in action or "all" in action:
|
|
346
438
|
return f"nmap -sV -p- {ip}"
|
|
347
|
-
elif
|
|
439
|
+
elif "quick" in action or "fast" in action:
|
|
348
440
|
return f"nmap -F {ip}"
|
|
349
441
|
else:
|
|
350
442
|
# Default: top 1000 ports with version detection
|
|
@@ -353,51 +445,58 @@ class ActionMapper:
|
|
|
353
445
|
def _map_http_enum(self, ip: str, port: Optional[str], rec: Dict[str, Any]) -> str:
|
|
354
446
|
"""
|
|
355
447
|
Map HTTP/web enumeration to appropriate tools.
|
|
356
|
-
|
|
448
|
+
|
|
357
449
|
Uses gobuster for web content discovery and vulnerability identification.
|
|
358
450
|
"""
|
|
359
|
-
action = rec.get(
|
|
360
|
-
target_info = rec.get(
|
|
361
|
-
|
|
451
|
+
action = rec.get("action", "").lower()
|
|
452
|
+
target_info = rec.get("target", "").lower()
|
|
453
|
+
|
|
362
454
|
# Determine port
|
|
363
455
|
if not port:
|
|
364
456
|
# Try to extract from target or default based on protocol
|
|
365
|
-
if
|
|
366
|
-
port =
|
|
457
|
+
if "https" in target_info or "443" in target_info:
|
|
458
|
+
port = "443"
|
|
367
459
|
else:
|
|
368
|
-
port =
|
|
369
|
-
|
|
460
|
+
port = "80"
|
|
461
|
+
|
|
370
462
|
# Build URL
|
|
371
|
-
protocol =
|
|
463
|
+
protocol = "https" if port in ["443", "8443"] else "http"
|
|
372
464
|
url = f"{protocol}://{ip}:{port}"
|
|
373
|
-
|
|
465
|
+
|
|
374
466
|
# Prefer gobuster for directory/path enumeration
|
|
375
|
-
if
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
467
|
+
if (
|
|
468
|
+
"directory" in action
|
|
469
|
+
or "path" in action
|
|
470
|
+
or "dir" in action
|
|
471
|
+
or "file" in action
|
|
472
|
+
):
|
|
473
|
+
ssl_flag = " -k" if protocol == "https" else ""
|
|
474
|
+
return f"gobuster dir -u {url} -w data/wordlists/web_dirs_common.txt -t 10{ssl_flag}"
|
|
475
|
+
|
|
379
476
|
# Use gobuster for web vulnerability and content discovery
|
|
380
|
-
elif
|
|
381
|
-
ssl_flag =
|
|
382
|
-
return f"gobuster dir -u {url} -w /
|
|
383
|
-
|
|
477
|
+
elif "vulnerab" in action or "vuln" in action or "scan" in action:
|
|
478
|
+
ssl_flag = " -k" if protocol == "https" else ""
|
|
479
|
+
return f"gobuster dir -u {url} -w data/wordlists/web_dirs_common.txt -t 10{ssl_flag}"
|
|
480
|
+
|
|
384
481
|
# Default to gobuster for general HTTP enumeration
|
|
385
482
|
else:
|
|
386
|
-
ssl_flag =
|
|
387
|
-
return f"gobuster dir -u {url} -w /
|
|
483
|
+
ssl_flag = " -k" if protocol == "https" else ""
|
|
484
|
+
return f"gobuster dir -u {url} -w data/wordlists/web_dirs_common.txt -t 10{ssl_flag}"
|
|
388
485
|
|
|
389
|
-
def _map_service_enum(
|
|
486
|
+
def _map_service_enum(
|
|
487
|
+
self, ip: str, port: Optional[str], rec: Dict[str, Any]
|
|
488
|
+
) -> Optional[str]:
|
|
390
489
|
"""Map service enumeration to command."""
|
|
391
490
|
if not port:
|
|
392
491
|
return f"nmap -sV {ip}"
|
|
393
|
-
|
|
394
|
-
service = rec.get(
|
|
395
|
-
|
|
396
|
-
if
|
|
492
|
+
|
|
493
|
+
service = rec.get("target", "").lower()
|
|
494
|
+
|
|
495
|
+
if "http" in service or port in ["80", "443", "8080"]:
|
|
397
496
|
return f"curl -I http://{ip}:{port}/ 2>&1"
|
|
398
|
-
elif
|
|
497
|
+
elif "ssh" in service or port == "22":
|
|
399
498
|
return f"ssh -V {ip} 2>&1 | head -1"
|
|
400
|
-
elif
|
|
499
|
+
elif "mysql" in service or port == "3306":
|
|
401
500
|
return f"nmap -sV -p {port} {ip}"
|
|
402
501
|
else:
|
|
403
502
|
return f"nc -zv {ip} {port} 2>&1"
|