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/core/msf_rpc_client.py
CHANGED
|
@@ -14,10 +14,12 @@ import time
|
|
|
14
14
|
|
|
15
15
|
# Suppress SSL warnings for self-signed certs (msfrpcd uses self-signed)
|
|
16
16
|
from urllib3.exceptions import InsecureRequestWarning
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
warnings.filterwarnings("ignore", category=InsecureRequestWarning)
|
|
18
19
|
|
|
19
20
|
try:
|
|
20
21
|
import msgpack
|
|
22
|
+
|
|
21
23
|
MSGPACK_AVAILABLE = True
|
|
22
24
|
except ImportError:
|
|
23
25
|
MSGPACK_AVAILABLE = False
|
|
@@ -34,7 +36,7 @@ class MSFRPCClient:
|
|
|
34
36
|
port: int = 55553,
|
|
35
37
|
username: str = "msf",
|
|
36
38
|
password: str = "",
|
|
37
|
-
ssl: bool = False
|
|
39
|
+
ssl: bool = False,
|
|
38
40
|
):
|
|
39
41
|
"""
|
|
40
42
|
Initialize MSF RPC client
|
|
@@ -48,8 +50,7 @@ class MSFRPCClient:
|
|
|
48
50
|
"""
|
|
49
51
|
if not MSGPACK_AVAILABLE:
|
|
50
52
|
raise ImportError(
|
|
51
|
-
"msgpack is required for MSF RPC. "
|
|
52
|
-
"Install with: pip install msgpack"
|
|
53
|
+
"msgpack is required for MSF RPC. " "Install with: pip install msgpack"
|
|
53
54
|
)
|
|
54
55
|
|
|
55
56
|
self.host = host
|
|
@@ -58,9 +59,7 @@ class MSFRPCClient:
|
|
|
58
59
|
self.password = password
|
|
59
60
|
self.ssl = ssl
|
|
60
61
|
self.token = None
|
|
61
|
-
self.headers = {
|
|
62
|
-
'Content-Type': 'binary/message-pack'
|
|
63
|
-
}
|
|
62
|
+
self.headers = {"Content-Type": "binary/message-pack"}
|
|
64
63
|
|
|
65
64
|
@property
|
|
66
65
|
def url(self) -> str:
|
|
@@ -75,8 +74,7 @@ class MSFRPCClient:
|
|
|
75
74
|
"""
|
|
76
75
|
if isinstance(obj, dict):
|
|
77
76
|
return {
|
|
78
|
-
(k.decode() if isinstance(k, bytes) else k):
|
|
79
|
-
self._normalize_keys(v)
|
|
77
|
+
(k.decode() if isinstance(k, bytes) else k): self._normalize_keys(v)
|
|
80
78
|
for k, v in obj.items()
|
|
81
79
|
}
|
|
82
80
|
elif isinstance(obj, list):
|
|
@@ -112,7 +110,10 @@ class MSFRPCClient:
|
|
|
112
110
|
data=request_data,
|
|
113
111
|
headers=self.headers,
|
|
114
112
|
verify=False, # nosec B501 - Metasploit RPC uses self-signed certs
|
|
115
|
-
timeout=(
|
|
113
|
+
timeout=(
|
|
114
|
+
5,
|
|
115
|
+
30,
|
|
116
|
+
), # (connect_timeout, read_timeout) - fast fail on SSL mismatch
|
|
116
117
|
)
|
|
117
118
|
response.raise_for_status()
|
|
118
119
|
|
|
@@ -124,9 +125,11 @@ class MSFRPCClient:
|
|
|
124
125
|
|
|
125
126
|
# Check for errors
|
|
126
127
|
if isinstance(result, dict):
|
|
127
|
-
if
|
|
128
|
-
raise Exception(
|
|
129
|
-
|
|
128
|
+
if "error" in result:
|
|
129
|
+
raise Exception(
|
|
130
|
+
f"RPC error: {result.get('error_message', 'Unknown error')}"
|
|
131
|
+
)
|
|
132
|
+
if "error_message" in result:
|
|
130
133
|
raise Exception(f"RPC error: {result['error_message']}")
|
|
131
134
|
|
|
132
135
|
return result
|
|
@@ -143,8 +146,8 @@ class MSFRPCClient:
|
|
|
143
146
|
"""
|
|
144
147
|
try:
|
|
145
148
|
result = self._call("auth.login", self.username, self.password)
|
|
146
|
-
if isinstance(result, dict) and
|
|
147
|
-
self.token = result[
|
|
149
|
+
if isinstance(result, dict) and "token" in result:
|
|
150
|
+
self.token = result["token"]
|
|
148
151
|
logger.info(f"Authenticated with MSF RPC at {self.host}:{self.port}")
|
|
149
152
|
return True
|
|
150
153
|
logger.error("Authentication failed: No token received")
|
|
@@ -194,9 +197,13 @@ class MSFRPCClient:
|
|
|
194
197
|
List of module names
|
|
195
198
|
"""
|
|
196
199
|
try:
|
|
197
|
-
result = self._call(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
result = self._call(
|
|
201
|
+
"module.exploits"
|
|
202
|
+
if module_type == "exploit"
|
|
203
|
+
else f"module.{module_type}s"
|
|
204
|
+
)
|
|
205
|
+
if isinstance(result, dict) and "modules" in result:
|
|
206
|
+
return result["modules"]
|
|
200
207
|
return []
|
|
201
208
|
except Exception as e:
|
|
202
209
|
logger.error(f"Failed to list modules: {e}")
|
|
@@ -239,10 +246,7 @@ class MSFRPCClient:
|
|
|
239
246
|
return {}
|
|
240
247
|
|
|
241
248
|
def execute_module(
|
|
242
|
-
self,
|
|
243
|
-
module_type: str,
|
|
244
|
-
module_name: str,
|
|
245
|
-
options: Dict[str, Any]
|
|
249
|
+
self, module_type: str, module_name: str, options: Dict[str, Any]
|
|
246
250
|
) -> Dict[str, Any]:
|
|
247
251
|
"""
|
|
248
252
|
Execute a module
|
|
@@ -260,7 +264,7 @@ class MSFRPCClient:
|
|
|
260
264
|
return result
|
|
261
265
|
except Exception as e:
|
|
262
266
|
logger.error(f"Failed to execute module: {e}")
|
|
263
|
-
return {
|
|
267
|
+
return {"error": str(e)}
|
|
264
268
|
|
|
265
269
|
def list_sessions(self) -> Dict[str, Dict[str, Any]]:
|
|
266
270
|
"""
|
|
@@ -309,10 +313,7 @@ class MSFRPCClient:
|
|
|
309
313
|
return False
|
|
310
314
|
|
|
311
315
|
def run_session_command(
|
|
312
|
-
self,
|
|
313
|
-
session_id: int,
|
|
314
|
-
command: str,
|
|
315
|
-
timeout: int = 30
|
|
316
|
+
self, session_id: int, command: str, timeout: int = 30
|
|
316
317
|
) -> str:
|
|
317
318
|
"""
|
|
318
319
|
Run a command in a session
|
|
@@ -334,8 +335,8 @@ class MSFRPCClient:
|
|
|
334
335
|
|
|
335
336
|
# Read output
|
|
336
337
|
result = self._call("session.shell_read", str(session_id))
|
|
337
|
-
if isinstance(result, dict) and
|
|
338
|
-
return result[
|
|
338
|
+
if isinstance(result, dict) and "data" in result:
|
|
339
|
+
return result["data"]
|
|
339
340
|
return ""
|
|
340
341
|
except Exception as e:
|
|
341
342
|
logger.error(f"Failed to run session command: {e}")
|
|
@@ -400,8 +401,8 @@ class MSFRPCClient:
|
|
|
400
401
|
"""
|
|
401
402
|
try:
|
|
402
403
|
result = self._call("console.list")
|
|
403
|
-
if isinstance(result, dict) and
|
|
404
|
-
return result[
|
|
404
|
+
if isinstance(result, dict) and "consoles" in result:
|
|
405
|
+
return result["consoles"]
|
|
405
406
|
return []
|
|
406
407
|
except Exception as e:
|
|
407
408
|
logger.error(f"Failed to get console list: {e}")
|
|
@@ -416,8 +417,8 @@ class MSFRPCClient:
|
|
|
416
417
|
"""
|
|
417
418
|
try:
|
|
418
419
|
result = self._call("console.create")
|
|
419
|
-
if isinstance(result, dict) and
|
|
420
|
-
return result[
|
|
420
|
+
if isinstance(result, dict) and "id" in result:
|
|
421
|
+
return result["id"]
|
|
421
422
|
return None
|
|
422
423
|
except Exception as e:
|
|
423
424
|
logger.error(f"Failed to create console: {e}")
|
|
@@ -453,8 +454,8 @@ class MSFRPCClient:
|
|
|
453
454
|
"""
|
|
454
455
|
try:
|
|
455
456
|
result = self._call("console.write", console_id, command + "\n")
|
|
456
|
-
if isinstance(result, dict) and
|
|
457
|
-
return result[
|
|
457
|
+
if isinstance(result, dict) and "wrote" in result:
|
|
458
|
+
return result["wrote"]
|
|
458
459
|
return 0
|
|
459
460
|
except Exception as e:
|
|
460
461
|
logger.error(f"Failed to write to console: {e}")
|
|
@@ -473,8 +474,8 @@ class MSFRPCClient:
|
|
|
473
474
|
try:
|
|
474
475
|
result = self._call("console.read", console_id)
|
|
475
476
|
if isinstance(result, dict):
|
|
476
|
-
output = result.get(
|
|
477
|
-
busy = result.get(
|
|
477
|
+
output = result.get("data", "")
|
|
478
|
+
busy = result.get("busy", False)
|
|
478
479
|
return (output, busy)
|
|
479
480
|
return ("", False)
|
|
480
481
|
except Exception as e:
|
|
@@ -482,10 +483,7 @@ class MSFRPCClient:
|
|
|
482
483
|
return ("", False)
|
|
483
484
|
|
|
484
485
|
def run_console_command(
|
|
485
|
-
self,
|
|
486
|
-
console_id: str,
|
|
487
|
-
command: str,
|
|
488
|
-
timeout: int = 30
|
|
486
|
+
self, console_id: str, command: str, timeout: int = 30
|
|
489
487
|
) -> str:
|
|
490
488
|
"""
|
|
491
489
|
Run a command in console and wait for output
|
|
@@ -532,7 +530,7 @@ def test_msf_rpc_connection(
|
|
|
532
530
|
host: str = "127.0.0.1",
|
|
533
531
|
port: int = 55553,
|
|
534
532
|
username: str = "msf",
|
|
535
|
-
password: str = ""
|
|
533
|
+
password: str = "",
|
|
536
534
|
) -> bool:
|
|
537
535
|
"""
|
|
538
536
|
Test MSF RPC connection
|
souleyez/core/msf_rpc_manager.py
CHANGED
|
@@ -27,6 +27,7 @@ def is_pro_enabled() -> bool:
|
|
|
27
27
|
"""Check if user has an active Pro license."""
|
|
28
28
|
try:
|
|
29
29
|
from souleyez.licensing.validator import get_active_license
|
|
30
|
+
|
|
30
31
|
license_info = get_active_license()
|
|
31
32
|
if license_info and license_info.is_valid:
|
|
32
33
|
return license_info.tier.upper() == "PRO"
|
|
@@ -37,7 +38,7 @@ def is_pro_enabled() -> bool:
|
|
|
37
38
|
|
|
38
39
|
# Session file for sharing decrypted msfrpc password with background worker
|
|
39
40
|
# This file is written when vault is unlocked and cleared on logout
|
|
40
|
-
_SESSION_FILE = os.path.join(os.path.expanduser(
|
|
41
|
+
_SESSION_FILE = os.path.join(os.path.expanduser("~"), ".souleyez", ".msfrpc_session")
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
def write_msfrpc_session(password: str) -> bool:
|
|
@@ -51,11 +52,12 @@ def write_msfrpc_session(password: str) -> bool:
|
|
|
51
52
|
"""
|
|
52
53
|
try:
|
|
53
54
|
import stat
|
|
55
|
+
|
|
54
56
|
session_dir = os.path.dirname(_SESSION_FILE)
|
|
55
57
|
os.makedirs(session_dir, exist_ok=True)
|
|
56
58
|
|
|
57
59
|
# Write with secure permissions
|
|
58
|
-
with open(_SESSION_FILE,
|
|
60
|
+
with open(_SESSION_FILE, "w") as f:
|
|
59
61
|
f.write(password)
|
|
60
62
|
os.chmod(_SESSION_FILE, stat.S_IRUSR | stat.S_IWUSR) # 600
|
|
61
63
|
|
|
@@ -86,7 +88,7 @@ def _read_msfrpc_session() -> Optional[str]:
|
|
|
86
88
|
"""Read password from session file if it exists."""
|
|
87
89
|
try:
|
|
88
90
|
if os.path.exists(_SESSION_FILE):
|
|
89
|
-
with open(_SESSION_FILE,
|
|
91
|
+
with open(_SESSION_FILE, "r") as f:
|
|
90
92
|
password = f.read().strip()
|
|
91
93
|
if password:
|
|
92
94
|
return password
|
|
@@ -112,7 +114,8 @@ def get_msfrpc_password() -> Optional[str]:
|
|
|
112
114
|
# Fall back to decryption (works if vault is unlocked in this process)
|
|
113
115
|
try:
|
|
114
116
|
from souleyez.storage.crypto import get_crypto_manager
|
|
115
|
-
|
|
117
|
+
|
|
118
|
+
encrypted = config.get("msfrpc.password")
|
|
116
119
|
if not encrypted:
|
|
117
120
|
return None
|
|
118
121
|
crypto = get_crypto_manager()
|
|
@@ -131,6 +134,7 @@ def set_msfrpc_password(password: str) -> bool:
|
|
|
131
134
|
"""Encrypt and store msfrpc password in config."""
|
|
132
135
|
try:
|
|
133
136
|
from souleyez.storage.crypto import get_crypto_manager
|
|
137
|
+
|
|
134
138
|
crypto = get_crypto_manager()
|
|
135
139
|
if crypto:
|
|
136
140
|
encrypted = crypto.encrypt(password)
|
|
@@ -138,9 +142,9 @@ def set_msfrpc_password(password: str) -> bool:
|
|
|
138
142
|
encrypted = password # No crypto manager, store plain
|
|
139
143
|
|
|
140
144
|
cfg = config.read_config()
|
|
141
|
-
if
|
|
142
|
-
cfg[
|
|
143
|
-
cfg[
|
|
145
|
+
if "msfrpc" not in cfg:
|
|
146
|
+
cfg["msfrpc"] = {}
|
|
147
|
+
cfg["msfrpc"]["password"] = encrypted
|
|
144
148
|
config.write_config(cfg)
|
|
145
149
|
return True
|
|
146
150
|
except Exception as e:
|
|
@@ -169,7 +173,7 @@ class MSFRPCManager:
|
|
|
169
173
|
return cls._instance
|
|
170
174
|
|
|
171
175
|
@classmethod
|
|
172
|
-
def get_instance(cls) ->
|
|
176
|
+
def get_instance(cls) -> "MSFRPCManager":
|
|
173
177
|
"""Get singleton instance."""
|
|
174
178
|
if cls._instance is None:
|
|
175
179
|
cls._instance = cls()
|
|
@@ -202,7 +206,7 @@ class MSFRPCManager:
|
|
|
202
206
|
return False
|
|
203
207
|
|
|
204
208
|
# Check if enabled in config
|
|
205
|
-
if not config.get(
|
|
209
|
+
if not config.get("msfrpc.enabled", False):
|
|
206
210
|
logger.debug("MSF RPC unavailable: Not enabled in config")
|
|
207
211
|
return False
|
|
208
212
|
|
|
@@ -239,11 +243,11 @@ class MSFRPCManager:
|
|
|
239
243
|
# Create new client
|
|
240
244
|
try:
|
|
241
245
|
client = MSFRPCClient(
|
|
242
|
-
host=config.get(
|
|
243
|
-
port=config.get(
|
|
244
|
-
username=config.get(
|
|
245
|
-
password=get_msfrpc_password() or
|
|
246
|
-
ssl=config.get(
|
|
246
|
+
host=config.get("msfrpc.host", "127.0.0.1"),
|
|
247
|
+
port=config.get("msfrpc.port", 55553),
|
|
248
|
+
username=config.get("msfrpc.username", "msf"),
|
|
249
|
+
password=get_msfrpc_password() or "",
|
|
250
|
+
ssl=config.get("msfrpc.ssl", False),
|
|
247
251
|
)
|
|
248
252
|
|
|
249
253
|
if client.login():
|
|
@@ -263,7 +267,7 @@ class MSFRPCManager:
|
|
|
263
267
|
"""Public method to get RPC client."""
|
|
264
268
|
if not is_pro_enabled():
|
|
265
269
|
return None
|
|
266
|
-
if not config.get(
|
|
270
|
+
if not config.get("msfrpc.enabled", False):
|
|
267
271
|
return None
|
|
268
272
|
return self._get_client()
|
|
269
273
|
|
|
@@ -279,28 +283,25 @@ class MSFRPCManager:
|
|
|
279
283
|
# Check Pro license first
|
|
280
284
|
if not is_pro_enabled():
|
|
281
285
|
return {
|
|
282
|
-
|
|
283
|
-
|
|
286
|
+
"status": "no_license",
|
|
287
|
+
"reason": "Pro license required for msfrpcd integration",
|
|
284
288
|
}
|
|
285
289
|
|
|
286
290
|
if not MSGPACK_AVAILABLE:
|
|
287
291
|
return {
|
|
288
|
-
|
|
289
|
-
|
|
292
|
+
"status": "unavailable",
|
|
293
|
+
"reason": "msgpack not installed (pip install msgpack)",
|
|
290
294
|
}
|
|
291
295
|
|
|
292
|
-
if not config.get(
|
|
293
|
-
return {
|
|
294
|
-
'status': 'disabled',
|
|
295
|
-
'reason': 'msfrpc.enabled is False in config'
|
|
296
|
-
}
|
|
296
|
+
if not config.get("msfrpc.enabled", False):
|
|
297
|
+
return {"status": "disabled", "reason": "msfrpc.enabled is False in config"}
|
|
297
298
|
|
|
298
299
|
# Check if password can be retrieved (vault must be unlocked)
|
|
299
300
|
password = get_msfrpc_password()
|
|
300
|
-
if not password and config.get(
|
|
301
|
+
if not password and config.get("msfrpc.password"):
|
|
301
302
|
return {
|
|
302
|
-
|
|
303
|
-
|
|
303
|
+
"status": "vault_locked",
|
|
304
|
+
"reason": "Credential vault is locked - unlock to connect",
|
|
304
305
|
}
|
|
305
306
|
|
|
306
307
|
try:
|
|
@@ -309,26 +310,23 @@ class MSFRPCManager:
|
|
|
309
310
|
version = client.get_version()
|
|
310
311
|
sessions = client.list_sessions()
|
|
311
312
|
return {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
313
|
+
"status": "connected",
|
|
314
|
+
"version": version.get("version", "unknown"),
|
|
315
|
+
"ruby": version.get("ruby", "unknown"),
|
|
316
|
+
"active_sessions": len(sessions),
|
|
316
317
|
}
|
|
317
318
|
except Exception as e:
|
|
318
|
-
return {
|
|
319
|
+
return {"status": "error", "reason": str(e)}
|
|
319
320
|
|
|
320
|
-
return {
|
|
321
|
-
'status': 'unavailable',
|
|
322
|
-
'reason': 'Could not connect to msfrpcd'
|
|
323
|
-
}
|
|
321
|
+
return {"status": "unavailable", "reason": "Could not connect to msfrpcd"}
|
|
324
322
|
|
|
325
323
|
def get_start_command(self) -> str:
|
|
326
324
|
"""Get the command to start msfrpcd with current config."""
|
|
327
|
-
host = config.get(
|
|
328
|
-
port = config.get(
|
|
329
|
-
username = config.get(
|
|
330
|
-
password = get_msfrpc_password() or
|
|
331
|
-
ssl = config.get(
|
|
325
|
+
host = config.get("msfrpc.host", "127.0.0.1")
|
|
326
|
+
port = config.get("msfrpc.port", 55553)
|
|
327
|
+
username = config.get("msfrpc.username", "msf")
|
|
328
|
+
password = get_msfrpc_password() or "YOUR_PASSWORD"
|
|
329
|
+
ssl = config.get("msfrpc.ssl", False)
|
|
332
330
|
|
|
333
331
|
cmd = f"msfrpcd -U {username} -P {password} -a {host} -p {port}"
|
|
334
332
|
if not ssl:
|
|
@@ -345,19 +343,16 @@ class MSFRPCManager:
|
|
|
345
343
|
"""
|
|
346
344
|
# Check if msfrpcd is already running
|
|
347
345
|
if self.is_available():
|
|
348
|
-
return {
|
|
349
|
-
'success': True,
|
|
350
|
-
'message': 'msfrpcd is already running'
|
|
351
|
-
}
|
|
346
|
+
return {"success": True, "message": "msfrpcd is already running"}
|
|
352
347
|
|
|
353
348
|
# Check if msfrpcd binary exists
|
|
354
|
-
msfrpcd_path = shutil.which(
|
|
349
|
+
msfrpcd_path = shutil.which("msfrpcd")
|
|
355
350
|
if not msfrpcd_path:
|
|
356
351
|
# Check common MSF install locations
|
|
357
352
|
common_paths = [
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
353
|
+
"/opt/metasploit-framework/bin/msfrpcd",
|
|
354
|
+
"/usr/share/metasploit-framework/msfrpcd",
|
|
355
|
+
"/usr/bin/msfrpcd",
|
|
361
356
|
]
|
|
362
357
|
for path in common_paths:
|
|
363
358
|
if shutil.which(path):
|
|
@@ -366,43 +361,47 @@ class MSFRPCManager:
|
|
|
366
361
|
|
|
367
362
|
if not msfrpcd_path:
|
|
368
363
|
return {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
364
|
+
"success": False,
|
|
365
|
+
"message": "msfrpcd not found. Is Metasploit Framework installed?",
|
|
366
|
+
"command": self.get_start_command(),
|
|
372
367
|
}
|
|
373
368
|
|
|
374
369
|
# Check if password is configured
|
|
375
370
|
password = get_msfrpc_password()
|
|
376
371
|
if not password:
|
|
377
372
|
return {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
373
|
+
"success": False,
|
|
374
|
+
"message": "msfrpc password not configured. Set it in Settings first.",
|
|
375
|
+
"command": self.get_start_command(),
|
|
381
376
|
}
|
|
382
377
|
|
|
383
378
|
# Try to start msfrpcd
|
|
384
379
|
try:
|
|
385
|
-
host = config.get(
|
|
386
|
-
port = config.get(
|
|
387
|
-
username = config.get(
|
|
388
|
-
ssl = config.get(
|
|
380
|
+
host = config.get("msfrpc.host", "127.0.0.1")
|
|
381
|
+
port = config.get("msfrpc.port", 55553)
|
|
382
|
+
username = config.get("msfrpc.username", "msf")
|
|
383
|
+
ssl = config.get("msfrpc.ssl", False)
|
|
389
384
|
|
|
390
385
|
cmd = [
|
|
391
386
|
msfrpcd_path,
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
387
|
+
"-U",
|
|
388
|
+
username,
|
|
389
|
+
"-P",
|
|
390
|
+
password,
|
|
391
|
+
"-a",
|
|
392
|
+
host,
|
|
393
|
+
"-p",
|
|
394
|
+
str(port),
|
|
396
395
|
]
|
|
397
396
|
if not ssl:
|
|
398
|
-
cmd.append(
|
|
397
|
+
cmd.append("-S") # -S flag DISABLES SSL
|
|
399
398
|
|
|
400
399
|
# Start in background
|
|
401
400
|
proc = subprocess.Popen(
|
|
402
401
|
cmd,
|
|
403
402
|
stdout=subprocess.DEVNULL,
|
|
404
403
|
stderr=subprocess.DEVNULL,
|
|
405
|
-
start_new_session=True
|
|
404
|
+
start_new_session=True,
|
|
406
405
|
)
|
|
407
406
|
|
|
408
407
|
# Wait a moment for it to start
|
|
@@ -411,30 +410,27 @@ class MSFRPCManager:
|
|
|
411
410
|
# Check if it's running
|
|
412
411
|
if proc.poll() is not None:
|
|
413
412
|
return {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
413
|
+
"success": False,
|
|
414
|
+
"message": "msfrpcd failed to start. Check if port is in use.",
|
|
415
|
+
"command": self.get_start_command(),
|
|
417
416
|
}
|
|
418
417
|
|
|
419
418
|
# Try to connect
|
|
420
419
|
time.sleep(1)
|
|
421
420
|
if self.is_available():
|
|
422
|
-
return {
|
|
423
|
-
'success': True,
|
|
424
|
-
'message': f'msfrpcd started on {host}:{port}'
|
|
425
|
-
}
|
|
421
|
+
return {"success": True, "message": f"msfrpcd started on {host}:{port}"}
|
|
426
422
|
else:
|
|
427
423
|
return {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
424
|
+
"success": False,
|
|
425
|
+
"message": "msfrpcd started but connection failed. Check credentials.",
|
|
426
|
+
"command": self.get_start_command(),
|
|
431
427
|
}
|
|
432
428
|
|
|
433
429
|
except Exception as e:
|
|
434
430
|
return {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
431
|
+
"success": False,
|
|
432
|
+
"message": f"Failed to start msfrpcd: {e}",
|
|
433
|
+
"command": self.get_start_command(),
|
|
438
434
|
}
|
|
439
435
|
|
|
440
436
|
def list_sessions(self) -> Dict[str, Dict[str, Any]]:
|
|
@@ -470,7 +466,9 @@ class MSFRPCManager:
|
|
|
470
466
|
logger.error(f"Failed to kill session: {e}")
|
|
471
467
|
return False
|
|
472
468
|
|
|
473
|
-
def run_session_command(
|
|
469
|
+
def run_session_command(
|
|
470
|
+
self, session_id: int, command: str, timeout: int = 30
|
|
471
|
+
) -> str:
|
|
474
472
|
"""Run a command in a session."""
|
|
475
473
|
client = self.get_client()
|
|
476
474
|
if not client:
|