souleyez 2.43.26__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.
- 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 +23434 -10286
- 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.26.dist-info → souleyez-2.43.34.dist-info}/METADATA +1 -1
- souleyez-2.43.34.dist-info/RECORD +443 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
- souleyez-2.43.26.dist-info/RECORD +0 -379
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
souleyez/plugins/nxc.py
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
souleyez.plugins.nxc - NetExec (successor to CrackMapExec) for SMB/WinRM/etc
|
|
4
|
+
"""
|
|
5
|
+
import subprocess
|
|
6
|
+
import time
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
from .plugin_base import PluginBase
|
|
10
|
+
|
|
11
|
+
HELP = {
|
|
12
|
+
"name": "NetExec - Network Service Exploitation",
|
|
13
|
+
"description": (
|
|
14
|
+
"NetExec (nxc) is the successor to CrackMapExec.\n\n"
|
|
15
|
+
"Use it for:\n"
|
|
16
|
+
"- SMB share enumeration\n"
|
|
17
|
+
"- Credential validation and spraying\n"
|
|
18
|
+
"- WinRM/RDP/MSSQL/LDAP attacks\n"
|
|
19
|
+
"- Pass-the-hash/Pass-the-ticket\n"
|
|
20
|
+
"- Command execution on compromised hosts\n\n"
|
|
21
|
+
"Quick tips:\n"
|
|
22
|
+
"- Use --shares to enumerate shares\n"
|
|
23
|
+
"- Use --users to enumerate users\n"
|
|
24
|
+
"- Use -x to execute commands\n"
|
|
25
|
+
"- (Pwn3d!) means admin access achieved\n"
|
|
26
|
+
),
|
|
27
|
+
"usage": 'souleyez jobs enqueue nxc <target> --args "smb <target> -u <user> -p <pass> --shares"',
|
|
28
|
+
"examples": [
|
|
29
|
+
"souleyez jobs enqueue nxc 10.0.0.82 --args \"smb 10.0.0.82 -u guest -p '' --shares\"",
|
|
30
|
+
'souleyez jobs enqueue nxc 10.0.0.82 --args "smb 10.0.0.82 -u admin -p Password1 --shares"',
|
|
31
|
+
'souleyez jobs enqueue nxc 10.0.0.82 --args "smb 10.0.0.82 -u users.txt -p passwords.txt --no-bruteforce"',
|
|
32
|
+
'souleyez jobs enqueue nxc 10.0.0.82 --args "smb 10.0.0.82 -u admin -H <nthash> --shares"',
|
|
33
|
+
'souleyez jobs enqueue nxc 10.0.0.82 --args "winrm 10.0.0.82 -u admin -p Password1"',
|
|
34
|
+
],
|
|
35
|
+
"flags": [
|
|
36
|
+
["smb", "Target SMB service (port 445)"],
|
|
37
|
+
["winrm", "Target WinRM service (port 5985/5986)"],
|
|
38
|
+
["rdp", "Target RDP service (port 3389)"],
|
|
39
|
+
["ldap", "Target LDAP service (port 389/636)"],
|
|
40
|
+
["mssql", "Target MSSQL service (port 1433)"],
|
|
41
|
+
["-u <user>", "Username or file with usernames"],
|
|
42
|
+
["-p <pass>", "Password or file with passwords"],
|
|
43
|
+
["-H <hash>", "NTLM hash for pass-the-hash"],
|
|
44
|
+
["--shares", "Enumerate SMB shares"],
|
|
45
|
+
["--users", "Enumerate domain users"],
|
|
46
|
+
["--groups", "Enumerate domain groups"],
|
|
47
|
+
["--pass-pol", "Get password policy"],
|
|
48
|
+
["-x <cmd>", "Execute command on target"],
|
|
49
|
+
["--no-bruteforce", "Test user:pass pairs only (not combinations)"],
|
|
50
|
+
["--continue-on-success", "Continue after finding valid creds"],
|
|
51
|
+
],
|
|
52
|
+
"preset_categories": {
|
|
53
|
+
"enumeration": [
|
|
54
|
+
{
|
|
55
|
+
"name": "Guest Share Enum",
|
|
56
|
+
"args": ["smb", "<target>", "-u", "guest", "-p", "", "--shares"],
|
|
57
|
+
"desc": "Enumerate shares with guest account",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "Null Session Shares",
|
|
61
|
+
"args": ["smb", "<target>", "-u", "", "-p", "", "--shares"],
|
|
62
|
+
"desc": "Enumerate shares with null session",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"name": "User Enumeration",
|
|
66
|
+
"args": ["smb", "<target>", "-u", "<user>", "-p", "<pass>", "--users"],
|
|
67
|
+
"desc": "Enumerate domain users",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "Password Policy",
|
|
71
|
+
"args": [
|
|
72
|
+
"smb",
|
|
73
|
+
"<target>",
|
|
74
|
+
"-u",
|
|
75
|
+
"<user>",
|
|
76
|
+
"-p",
|
|
77
|
+
"<pass>",
|
|
78
|
+
"--pass-pol",
|
|
79
|
+
],
|
|
80
|
+
"desc": "Get domain password policy",
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
"credential_attacks": [
|
|
84
|
+
{
|
|
85
|
+
"name": "Username=Password Spray",
|
|
86
|
+
"args": [
|
|
87
|
+
"smb",
|
|
88
|
+
"<target>",
|
|
89
|
+
"-u",
|
|
90
|
+
"users.txt",
|
|
91
|
+
"-p",
|
|
92
|
+
"users.txt",
|
|
93
|
+
"--no-bruteforce",
|
|
94
|
+
"--continue-on-success",
|
|
95
|
+
],
|
|
96
|
+
"desc": "Test username as password",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"name": "Password Spray",
|
|
100
|
+
"args": [
|
|
101
|
+
"smb",
|
|
102
|
+
"<target>",
|
|
103
|
+
"-u",
|
|
104
|
+
"users.txt",
|
|
105
|
+
"-p",
|
|
106
|
+
"<password>",
|
|
107
|
+
"--continue-on-success",
|
|
108
|
+
],
|
|
109
|
+
"desc": "Spray single password",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"name": "Pass-the-Hash",
|
|
113
|
+
"args": ["smb", "<target>", "-u", "<user>", "-H", "<nthash>"],
|
|
114
|
+
"desc": "Authenticate with NTLM hash",
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
"execution": [
|
|
118
|
+
{
|
|
119
|
+
"name": "WinRM Check",
|
|
120
|
+
"args": ["winrm", "<target>", "-u", "<user>", "-p", "<pass>"],
|
|
121
|
+
"desc": "Check WinRM access",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"name": "Command Execution",
|
|
125
|
+
"args": [
|
|
126
|
+
"smb",
|
|
127
|
+
"<target>",
|
|
128
|
+
"-u",
|
|
129
|
+
"<user>",
|
|
130
|
+
"-p",
|
|
131
|
+
"<pass>",
|
|
132
|
+
"-x",
|
|
133
|
+
"whoami",
|
|
134
|
+
],
|
|
135
|
+
"desc": "Execute command via SMB",
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
"presets": [],
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# Flatten presets
|
|
143
|
+
for category_presets in HELP["preset_categories"].values():
|
|
144
|
+
HELP["presets"].extend(category_presets)
|
|
145
|
+
|
|
146
|
+
HELP["help_sections"] = [
|
|
147
|
+
{
|
|
148
|
+
"title": "What is NetExec?",
|
|
149
|
+
"color": "cyan",
|
|
150
|
+
"content": [
|
|
151
|
+
{
|
|
152
|
+
"title": "Overview",
|
|
153
|
+
"desc": "NetExec (nxc) is a network service exploitation tool that supports SMB, WinRM, RDP, LDAP, MSSQL and more.",
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"title": "Key Features",
|
|
157
|
+
"desc": "Multi-protocol support",
|
|
158
|
+
"tips": [
|
|
159
|
+
"SMB share enumeration and access",
|
|
160
|
+
"Credential spraying and validation",
|
|
161
|
+
"Pass-the-hash and pass-the-ticket",
|
|
162
|
+
"Command execution on compromised hosts",
|
|
163
|
+
"Domain enumeration (users, groups, policies)",
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"title": "How to Use",
|
|
170
|
+
"color": "green",
|
|
171
|
+
"content": [
|
|
172
|
+
{
|
|
173
|
+
"title": "Basic Workflow",
|
|
174
|
+
"desc": "1. Enumerate shares with guest/null session\n 2. Test credentials (spray or PTH)\n 3. Enumerate domain with valid creds\n 4. Execute commands if admin",
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"title": "Success Indicators",
|
|
178
|
+
"desc": "What to look for",
|
|
179
|
+
"tips": [
|
|
180
|
+
"(Pwn3d!) = Admin access achieved",
|
|
181
|
+
"[+] = Successful operation",
|
|
182
|
+
"READ,WRITE = Share permissions",
|
|
183
|
+
"STATUS_LOGON_FAILURE = Invalid creds",
|
|
184
|
+
],
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class NxcPlugin(PluginBase):
|
|
192
|
+
name = "NetExec"
|
|
193
|
+
tool = "nxc"
|
|
194
|
+
category = "credential_access"
|
|
195
|
+
HELP = HELP
|
|
196
|
+
|
|
197
|
+
def build_command(
|
|
198
|
+
self, target: str, args: List[str] = None, label: str = "", log_path: str = None
|
|
199
|
+
):
|
|
200
|
+
"""Build command for background execution with PID tracking."""
|
|
201
|
+
args = args or []
|
|
202
|
+
|
|
203
|
+
# Replace placeholders
|
|
204
|
+
args = [arg.replace("<target>", target) for arg in args]
|
|
205
|
+
|
|
206
|
+
# Build command
|
|
207
|
+
cmd = ["nxc"]
|
|
208
|
+
cmd.extend(args)
|
|
209
|
+
|
|
210
|
+
return {"cmd": cmd, "timeout": 1800}
|
|
211
|
+
|
|
212
|
+
def run(
|
|
213
|
+
self, target: str, args: List[str] = None, label: str = "", log_path: str = None
|
|
214
|
+
) -> int:
|
|
215
|
+
"""Execute nxc and write output to log_path."""
|
|
216
|
+
|
|
217
|
+
args = args or []
|
|
218
|
+
|
|
219
|
+
# Replace placeholders
|
|
220
|
+
args = [arg.replace("<target>", target) for arg in args]
|
|
221
|
+
|
|
222
|
+
# Build command
|
|
223
|
+
cmd = ["nxc"]
|
|
224
|
+
cmd.extend(args)
|
|
225
|
+
|
|
226
|
+
if not log_path:
|
|
227
|
+
try:
|
|
228
|
+
proc = subprocess.run(
|
|
229
|
+
cmd, capture_output=True, timeout=600, check=False
|
|
230
|
+
)
|
|
231
|
+
return proc.returncode
|
|
232
|
+
except Exception:
|
|
233
|
+
return 1
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
# Create metadata header
|
|
237
|
+
with open(log_path, "w", encoding="utf-8", errors="replace") as fh:
|
|
238
|
+
fh.write(f"=== Plugin: NetExec (nxc) ===\n")
|
|
239
|
+
fh.write(f"Target: {target}\n")
|
|
240
|
+
fh.write(f"Args: {args}\n")
|
|
241
|
+
fh.write(f"Label: {label}\n")
|
|
242
|
+
fh.write(
|
|
243
|
+
f"Started: {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())}\n"
|
|
244
|
+
)
|
|
245
|
+
fh.write(f"Command: {' '.join(cmd)}\n\n")
|
|
246
|
+
|
|
247
|
+
# Run nxc
|
|
248
|
+
proc = subprocess.run(
|
|
249
|
+
cmd, capture_output=True, timeout=1800, check=False, text=True
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
# Write output
|
|
253
|
+
with open(log_path, "a", encoding="utf-8", errors="replace") as fh:
|
|
254
|
+
if proc.stdout:
|
|
255
|
+
fh.write(proc.stdout)
|
|
256
|
+
|
|
257
|
+
if proc.stderr:
|
|
258
|
+
fh.write(f"\n{proc.stderr}")
|
|
259
|
+
|
|
260
|
+
fh.write(
|
|
261
|
+
f"\n\n=== Completed: {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())} ===\n"
|
|
262
|
+
)
|
|
263
|
+
fh.write(f"Exit Code: {proc.returncode}\n")
|
|
264
|
+
|
|
265
|
+
return proc.returncode
|
|
266
|
+
|
|
267
|
+
except subprocess.TimeoutExpired:
|
|
268
|
+
with open(log_path, "a", encoding="utf-8", errors="replace") as fh:
|
|
269
|
+
fh.write("\n\nERROR: nxc timed out after 1800 seconds\n")
|
|
270
|
+
return 124
|
|
271
|
+
|
|
272
|
+
except FileNotFoundError:
|
|
273
|
+
with open(log_path, "w", encoding="utf-8", errors="replace") as fh:
|
|
274
|
+
fh.write("ERROR: nxc not found in PATH\n")
|
|
275
|
+
fh.write("Install: pipx install netexec\n")
|
|
276
|
+
fh.write("Or: sudo apt install netexec\n")
|
|
277
|
+
return 127
|
|
278
|
+
|
|
279
|
+
except Exception as e:
|
|
280
|
+
with open(log_path, "a", encoding="utf-8", errors="replace") as fh:
|
|
281
|
+
fh.write(f"\n\nERROR: {type(e).__name__}: {e}\n")
|
|
282
|
+
return 1
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
plugin = NxcPlugin()
|
souleyez/plugins/plugin_base.py
CHANGED
|
@@ -36,23 +36,20 @@ class PluginBase:
|
|
|
36
36
|
# Check if tool exists in PATH
|
|
37
37
|
tool_path = shutil.which(self.tool)
|
|
38
38
|
if not tool_path:
|
|
39
|
-
return
|
|
39
|
+
return (
|
|
40
|
+
False,
|
|
41
|
+
f"{self.tool} not found in PATH. Install with: sudo apt install {self.tool}",
|
|
42
|
+
)
|
|
40
43
|
|
|
41
44
|
# Try running with --version or --help to check if it works
|
|
42
45
|
try:
|
|
43
46
|
result = subprocess.run(
|
|
44
|
-
[self.tool,
|
|
45
|
-
capture_output=True,
|
|
46
|
-
timeout=10,
|
|
47
|
-
text=True
|
|
47
|
+
[self.tool, "--version"], capture_output=True, timeout=10, text=True
|
|
48
48
|
)
|
|
49
49
|
# Some tools don't support --version, try --help
|
|
50
50
|
if result.returncode != 0:
|
|
51
51
|
result = subprocess.run(
|
|
52
|
-
[self.tool,
|
|
53
|
-
capture_output=True,
|
|
54
|
-
timeout=10,
|
|
55
|
-
text=True
|
|
52
|
+
[self.tool, "--help"], capture_output=True, timeout=10, text=True
|
|
56
53
|
)
|
|
57
54
|
return True, None
|
|
58
55
|
except subprocess.TimeoutExpired:
|
|
@@ -62,23 +59,25 @@ class PluginBase:
|
|
|
62
59
|
except Exception as e:
|
|
63
60
|
# Tool might have Python import issues (like impacket pickle error)
|
|
64
61
|
error_str = str(e)
|
|
65
|
-
if
|
|
62
|
+
if "pickle" in error_str.lower() or "import" in error_str.lower():
|
|
66
63
|
return False, f"{self.tool} has Python dependency issues: {error_str}"
|
|
67
64
|
return True, None # Assume available if error is unexpected
|
|
68
65
|
|
|
69
|
-
def build_command(
|
|
66
|
+
def build_command(
|
|
67
|
+
self, target: str, args: List[str] = None, label: str = "", log_path: str = None
|
|
68
|
+
) -> Optional[Dict[str, Any]]:
|
|
70
69
|
"""
|
|
71
70
|
Build command specification for background execution.
|
|
72
|
-
|
|
71
|
+
|
|
73
72
|
This method should be implemented by plugins instead of run() to enable
|
|
74
73
|
proper PID tracking, status updates, and kill handling.
|
|
75
|
-
|
|
74
|
+
|
|
76
75
|
Args:
|
|
77
76
|
target: Target host/URL/file to scan
|
|
78
77
|
args: Additional command-line arguments
|
|
79
78
|
label: Optional job label
|
|
80
79
|
log_path: Path where logs should be written
|
|
81
|
-
|
|
80
|
+
|
|
82
81
|
Returns:
|
|
83
82
|
Dictionary with command specification:
|
|
84
83
|
{
|
|
@@ -88,9 +87,9 @@ class PluginBase:
|
|
|
88
87
|
'cwd': str, # Working directory (optional)
|
|
89
88
|
'needs_shell': bool # Use shell=True (optional, default: False)
|
|
90
89
|
}
|
|
91
|
-
|
|
90
|
+
|
|
92
91
|
Return None to indicate command cannot be built (validation failure, etc.)
|
|
93
|
-
|
|
92
|
+
|
|
94
93
|
Example:
|
|
95
94
|
return {
|
|
96
95
|
'cmd': ['nmap', '-sV', '-p', '1-1000', target],
|
|
@@ -99,13 +98,15 @@ class PluginBase:
|
|
|
99
98
|
"""
|
|
100
99
|
return None
|
|
101
100
|
|
|
102
|
-
def run(
|
|
101
|
+
def run(
|
|
102
|
+
self, target: str, args: List[str] = None, label: str = "", log_path: str = None
|
|
103
|
+
) -> int:
|
|
103
104
|
"""
|
|
104
105
|
Execute the plugin action synchronously.
|
|
105
|
-
|
|
106
|
+
|
|
106
107
|
DEPRECATED: New plugins should implement build_command() instead.
|
|
107
108
|
This method is maintained for backward compatibility.
|
|
108
|
-
|
|
109
|
+
|
|
109
110
|
If build_command() is implemented, run() will use it automatically.
|
|
110
111
|
"""
|
|
111
112
|
# Try to use build_command() if available
|
|
@@ -114,25 +115,25 @@ class PluginBase:
|
|
|
114
115
|
# build_command() is implemented, execute via subprocess
|
|
115
116
|
import subprocess
|
|
116
117
|
import os
|
|
117
|
-
|
|
118
|
-
cmd = cmd_spec.get(
|
|
118
|
+
|
|
119
|
+
cmd = cmd_spec.get("cmd")
|
|
119
120
|
if not cmd:
|
|
120
121
|
return 1
|
|
121
|
-
|
|
122
|
-
timeout = cmd_spec.get(
|
|
123
|
-
env = cmd_spec.get(
|
|
124
|
-
cwd = cmd_spec.get(
|
|
125
|
-
needs_shell = cmd_spec.get(
|
|
126
|
-
|
|
122
|
+
|
|
123
|
+
timeout = cmd_spec.get("timeout", 3600)
|
|
124
|
+
env = cmd_spec.get("env")
|
|
125
|
+
cwd = cmd_spec.get("cwd")
|
|
126
|
+
needs_shell = cmd_spec.get("needs_shell", False)
|
|
127
|
+
|
|
127
128
|
# Prepare environment
|
|
128
129
|
proc_env = os.environ.copy()
|
|
129
130
|
if env:
|
|
130
131
|
proc_env.update(env)
|
|
131
|
-
|
|
132
|
+
|
|
132
133
|
# Execute command
|
|
133
134
|
try:
|
|
134
135
|
if log_path:
|
|
135
|
-
with open(log_path,
|
|
136
|
+
with open(log_path, "a", encoding="utf-8", errors="replace") as fh:
|
|
136
137
|
result = subprocess.run(
|
|
137
138
|
cmd,
|
|
138
139
|
stdout=fh,
|
|
@@ -140,7 +141,7 @@ class PluginBase:
|
|
|
140
141
|
timeout=timeout,
|
|
141
142
|
env=proc_env if env else None,
|
|
142
143
|
cwd=cwd,
|
|
143
|
-
shell=needs_shell
|
|
144
|
+
shell=needs_shell,
|
|
144
145
|
)
|
|
145
146
|
return result.returncode
|
|
146
147
|
else:
|
|
@@ -150,14 +151,14 @@ class PluginBase:
|
|
|
150
151
|
env=proc_env if env else None,
|
|
151
152
|
cwd=cwd,
|
|
152
153
|
shell=needs_shell,
|
|
153
|
-
capture_output=True
|
|
154
|
+
capture_output=True,
|
|
154
155
|
)
|
|
155
156
|
return result.returncode
|
|
156
157
|
except subprocess.TimeoutExpired:
|
|
157
158
|
return 124
|
|
158
159
|
except Exception:
|
|
159
160
|
return 1
|
|
160
|
-
|
|
161
|
+
|
|
161
162
|
# build_command() not implemented, require subclass implementation
|
|
162
163
|
raise NotImplementedError(f"{self.__class__.__name__}.run() not implemented")
|
|
163
164
|
|
|
@@ -165,11 +166,9 @@ class PluginBase:
|
|
|
165
166
|
"""Enqueue the plugin action for background processing."""
|
|
166
167
|
try:
|
|
167
168
|
from ..engine.background import enqueue_job
|
|
169
|
+
|
|
168
170
|
job_id = enqueue_job(
|
|
169
|
-
tool=self.tool,
|
|
170
|
-
target=target,
|
|
171
|
-
args=args or [],
|
|
172
|
-
label=label or ""
|
|
171
|
+
tool=self.tool, target=target, args=args or [], label=label or ""
|
|
173
172
|
)
|
|
174
173
|
return job_id
|
|
175
174
|
except ImportError:
|
|
@@ -22,15 +22,23 @@ def _now_ts():
|
|
|
22
22
|
class Plugin(ScannerPlugin):
|
|
23
23
|
name = "template"
|
|
24
24
|
|
|
25
|
-
def prepare(
|
|
26
|
-
|
|
25
|
+
def prepare(
|
|
26
|
+
self, target: str, args: List[str], label: Optional[str] = None
|
|
27
|
+
) -> Dict[str, Any]:
|
|
28
|
+
outdir = (
|
|
29
|
+
Path.home() / ".souleyez" / "artifacts" / f"{self.name}_{int(time.time())}"
|
|
30
|
+
)
|
|
27
31
|
outdir.mkdir(parents=True, exist_ok=True)
|
|
28
32
|
return {"target": target, "args": args, "label": label, "outdir": str(outdir)}
|
|
29
33
|
|
|
30
34
|
def run(self, prepared: Dict[str, Any]) -> ScanResult:
|
|
31
35
|
# Example minimal command (safe)
|
|
32
|
-
cmd = ["echo", "placeholder", str(prepared.get("target"))] + (
|
|
33
|
-
|
|
36
|
+
cmd = ["echo", "placeholder", str(prepared.get("target"))] + (
|
|
37
|
+
prepared.get("args") or []
|
|
38
|
+
)
|
|
39
|
+
p = subprocess.run(
|
|
40
|
+
cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True
|
|
41
|
+
)
|
|
34
42
|
rawfile = Path(prepared["outdir"]) / f"{self.name}.txt"
|
|
35
43
|
rawfile.write_text(p.stdout or "")
|
|
36
44
|
return {
|
|
@@ -44,5 +52,5 @@ class Plugin(ScannerPlugin):
|
|
|
44
52
|
"summary": {"note": "template run"},
|
|
45
53
|
"per_host": [],
|
|
46
54
|
"status": "done",
|
|
47
|
-
"rc": p.returncode
|
|
55
|
+
"rc": p.returncode,
|
|
48
56
|
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
souleyez.plugins.rdp_sec_check - RDP security configuration checker
|
|
4
|
+
"""
|
|
5
|
+
import subprocess
|
|
6
|
+
import time
|
|
7
|
+
from typing import List
|
|
8
|
+
|
|
9
|
+
from .plugin_base import PluginBase
|
|
10
|
+
|
|
11
|
+
HELP = {
|
|
12
|
+
"name": "RDP Security Check",
|
|
13
|
+
"description": (
|
|
14
|
+
"Check RDP security configuration and identify misconfigurations.\n\n"
|
|
15
|
+
"rdp-sec-check tests Remote Desktop Protocol security settings:\n"
|
|
16
|
+
"- Network Level Authentication (NLA) requirements\n"
|
|
17
|
+
"- Encryption levels (None/Low/Client/High/FIPS)\n"
|
|
18
|
+
"- Supported protocols (RDP/TLS/CredSSP)\n\n"
|
|
19
|
+
"Use when:\n"
|
|
20
|
+
"- RDP (port 3389) is detected on a target\n"
|
|
21
|
+
"- Assessing Windows server security posture\n"
|
|
22
|
+
"- Checking for BlueKeep/MITM vulnerability prerequisites\n"
|
|
23
|
+
),
|
|
24
|
+
"usage": 'souleyez jobs enqueue rdp-sec-check <target> --args "<target>"',
|
|
25
|
+
"examples": [
|
|
26
|
+
'souleyez jobs enqueue rdp-sec-check 10.0.0.1 --args "10.0.0.1"',
|
|
27
|
+
'souleyez jobs enqueue rdp-sec-check 10.0.0.1 --args "10.0.0.1:3389"',
|
|
28
|
+
],
|
|
29
|
+
"flags": [
|
|
30
|
+
["<target>", "Target IP or IP:port (default port 3389)"],
|
|
31
|
+
],
|
|
32
|
+
"preset_categories": {
|
|
33
|
+
"scanning": [
|
|
34
|
+
{
|
|
35
|
+
"name": "RDP Security Scan",
|
|
36
|
+
"args": ["<target>"],
|
|
37
|
+
"desc": "Check RDP security configuration",
|
|
38
|
+
},
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"presets": [],
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# Flatten presets
|
|
45
|
+
for category_presets in HELP["preset_categories"].values():
|
|
46
|
+
HELP["presets"].extend(category_presets)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class RdpSecCheckPlugin(PluginBase):
|
|
50
|
+
name = "RDP Security Check"
|
|
51
|
+
tool = "rdp-sec-check"
|
|
52
|
+
category = "scanning"
|
|
53
|
+
HELP = HELP
|
|
54
|
+
|
|
55
|
+
def build_command(
|
|
56
|
+
self, target: str, args: List[str] = None, label: str = "", log_path: str = None
|
|
57
|
+
):
|
|
58
|
+
"""Build command for background execution."""
|
|
59
|
+
args = args or [target]
|
|
60
|
+
args = [arg.replace("<target>", target) for arg in args]
|
|
61
|
+
|
|
62
|
+
cmd = ["rdp-sec-check"]
|
|
63
|
+
cmd.extend(args)
|
|
64
|
+
|
|
65
|
+
return {"cmd": cmd, "timeout": 300} # 5 minutes should be plenty
|
|
66
|
+
|
|
67
|
+
def run(
|
|
68
|
+
self, target: str, args: List[str] = None, label: str = "", log_path: str = None
|
|
69
|
+
) -> int:
|
|
70
|
+
"""Execute rdp-sec-check and write output to log_path."""
|
|
71
|
+
args = args or [target]
|
|
72
|
+
args = [arg.replace("<target>", target) for arg in args]
|
|
73
|
+
|
|
74
|
+
cmd = ["rdp-sec-check"]
|
|
75
|
+
cmd.extend(args)
|
|
76
|
+
|
|
77
|
+
if not log_path:
|
|
78
|
+
try:
|
|
79
|
+
proc = subprocess.run(
|
|
80
|
+
cmd, capture_output=True, timeout=300, check=False
|
|
81
|
+
)
|
|
82
|
+
return proc.returncode
|
|
83
|
+
except Exception:
|
|
84
|
+
return 1
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
with open(log_path, "w", encoding="utf-8", errors="replace") as fh:
|
|
88
|
+
fh.write(f"=== Plugin: RDP Security Check ===\n")
|
|
89
|
+
fh.write(f"Target: {target}\n")
|
|
90
|
+
fh.write(f"Args: {args}\n")
|
|
91
|
+
fh.write(
|
|
92
|
+
f"Started: {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())}\n"
|
|
93
|
+
)
|
|
94
|
+
fh.write(f"Command: {' '.join(cmd)}\n\n")
|
|
95
|
+
|
|
96
|
+
proc = subprocess.run(
|
|
97
|
+
cmd, capture_output=True, timeout=300, check=False, text=True
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
with open(log_path, "a", encoding="utf-8", errors="replace") as fh:
|
|
101
|
+
if proc.stdout:
|
|
102
|
+
fh.write(proc.stdout)
|
|
103
|
+
if proc.stderr:
|
|
104
|
+
fh.write(f"\n{proc.stderr}")
|
|
105
|
+
fh.write(
|
|
106
|
+
f"\n\n=== Completed: {time.strftime('%Y-%m-%d %H:%M:%S UTC', time.gmtime())} ===\n"
|
|
107
|
+
)
|
|
108
|
+
fh.write(f"Exit Code: {proc.returncode}\n")
|
|
109
|
+
|
|
110
|
+
return proc.returncode
|
|
111
|
+
|
|
112
|
+
except subprocess.TimeoutExpired:
|
|
113
|
+
with open(log_path, "a", encoding="utf-8", errors="replace") as fh:
|
|
114
|
+
fh.write("\n\nERROR: rdp-sec-check timed out after 300 seconds\n")
|
|
115
|
+
return 124
|
|
116
|
+
|
|
117
|
+
except FileNotFoundError:
|
|
118
|
+
with open(log_path, "w", encoding="utf-8", errors="replace") as fh:
|
|
119
|
+
fh.write("ERROR: rdp-sec-check not found in PATH\n")
|
|
120
|
+
fh.write("Install on Kali: sudo apt install rdp-sec-check\n")
|
|
121
|
+
fh.write("Install on Ubuntu: See docs for manual installation\n")
|
|
122
|
+
return 127
|
|
123
|
+
|
|
124
|
+
except Exception as e:
|
|
125
|
+
with open(log_path, "a", encoding="utf-8", errors="replace") as fh:
|
|
126
|
+
fh.write(f"\n\nERROR: {type(e).__name__}: {e}\n")
|
|
127
|
+
return 1
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
plugin = RdpSecCheckPlugin()
|