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
|
@@ -8,10 +8,10 @@ from souleyez.storage.database import get_db
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
# Valid status values
|
|
11
|
-
STATUS_NOT_TRIED =
|
|
12
|
-
STATUS_ATTEMPTED =
|
|
13
|
-
STATUS_FAILED =
|
|
14
|
-
STATUS_SUCCESS =
|
|
11
|
+
STATUS_NOT_TRIED = "not_tried"
|
|
12
|
+
STATUS_ATTEMPTED = "attempted"
|
|
13
|
+
STATUS_FAILED = "failed"
|
|
14
|
+
STATUS_SUCCESS = "success"
|
|
15
15
|
|
|
16
16
|
VALID_STATUSES = [STATUS_NOT_TRIED, STATUS_ATTEMPTED, STATUS_FAILED, STATUS_SUCCESS]
|
|
17
17
|
|
|
@@ -23,7 +23,7 @@ def record_attempt(
|
|
|
23
23
|
exploit_title: str,
|
|
24
24
|
status: str,
|
|
25
25
|
service_id: Optional[int] = None,
|
|
26
|
-
notes: Optional[str] = None
|
|
26
|
+
notes: Optional[str] = None,
|
|
27
27
|
) -> int:
|
|
28
28
|
"""
|
|
29
29
|
Record an exploit attempt. Creates new record or updates existing one.
|
|
@@ -47,15 +47,19 @@ def record_attempt(
|
|
|
47
47
|
conn = db.get_connection()
|
|
48
48
|
|
|
49
49
|
# Check if record exists
|
|
50
|
-
existing = conn.execute(
|
|
50
|
+
existing = conn.execute(
|
|
51
|
+
"""
|
|
51
52
|
SELECT id FROM exploit_attempts
|
|
52
53
|
WHERE engagement_id = ? AND host_id = ? AND service_id IS ? AND exploit_identifier = ?
|
|
53
|
-
""",
|
|
54
|
+
""",
|
|
55
|
+
(engagement_id, host_id, service_id, exploit_identifier),
|
|
56
|
+
).fetchone()
|
|
54
57
|
|
|
55
58
|
if existing:
|
|
56
59
|
# Update existing record
|
|
57
|
-
attempt_id = existing[
|
|
58
|
-
conn.execute(
|
|
60
|
+
attempt_id = existing["id"]
|
|
61
|
+
conn.execute(
|
|
62
|
+
"""
|
|
59
63
|
UPDATE exploit_attempts
|
|
60
64
|
SET status = ?,
|
|
61
65
|
exploit_title = ?,
|
|
@@ -63,18 +67,29 @@ def record_attempt(
|
|
|
63
67
|
attempted_at = ?,
|
|
64
68
|
updated_at = CURRENT_TIMESTAMP
|
|
65
69
|
WHERE id = ?
|
|
66
|
-
""",
|
|
70
|
+
""",
|
|
71
|
+
(status, exploit_title, notes, datetime.now(), attempt_id),
|
|
72
|
+
)
|
|
67
73
|
else:
|
|
68
74
|
# Create new record
|
|
69
|
-
cursor = conn.execute(
|
|
75
|
+
cursor = conn.execute(
|
|
76
|
+
"""
|
|
70
77
|
INSERT INTO exploit_attempts (
|
|
71
78
|
engagement_id, host_id, service_id, exploit_identifier,
|
|
72
79
|
exploit_title, status, attempted_at, notes
|
|
73
80
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
74
|
-
""",
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
""",
|
|
82
|
+
(
|
|
83
|
+
engagement_id,
|
|
84
|
+
host_id,
|
|
85
|
+
service_id,
|
|
86
|
+
exploit_identifier,
|
|
87
|
+
exploit_title,
|
|
88
|
+
status,
|
|
89
|
+
datetime.now() if status != STATUS_NOT_TRIED else None,
|
|
90
|
+
notes,
|
|
91
|
+
),
|
|
92
|
+
)
|
|
78
93
|
attempt_id = cursor.lastrowid
|
|
79
94
|
|
|
80
95
|
conn.commit()
|
|
@@ -87,7 +102,7 @@ def get_attempt_status(
|
|
|
87
102
|
engagement_id: int,
|
|
88
103
|
host_id: int,
|
|
89
104
|
exploit_identifier: str,
|
|
90
|
-
service_id: Optional[int] = None
|
|
105
|
+
service_id: Optional[int] = None,
|
|
91
106
|
) -> Optional[str]:
|
|
92
107
|
"""
|
|
93
108
|
Get the status of a specific exploit attempt.
|
|
@@ -98,14 +113,17 @@ def get_attempt_status(
|
|
|
98
113
|
db = get_db()
|
|
99
114
|
conn = db.get_connection()
|
|
100
115
|
|
|
101
|
-
result = conn.execute(
|
|
116
|
+
result = conn.execute(
|
|
117
|
+
"""
|
|
102
118
|
SELECT status FROM exploit_attempts
|
|
103
119
|
WHERE engagement_id = ? AND host_id = ? AND service_id IS ? AND exploit_identifier = ?
|
|
104
|
-
""",
|
|
120
|
+
""",
|
|
121
|
+
(engagement_id, host_id, service_id, exploit_identifier),
|
|
122
|
+
).fetchone()
|
|
105
123
|
|
|
106
124
|
conn.close()
|
|
107
125
|
|
|
108
|
-
return result[
|
|
126
|
+
return result["status"] if result else None
|
|
109
127
|
|
|
110
128
|
|
|
111
129
|
def get_attempts_by_host(host_id: int) -> List[Dict[str, Any]]:
|
|
@@ -113,7 +131,8 @@ def get_attempts_by_host(host_id: int) -> List[Dict[str, Any]]:
|
|
|
113
131
|
db = get_db()
|
|
114
132
|
conn = db.get_connection()
|
|
115
133
|
|
|
116
|
-
results = conn.execute(
|
|
134
|
+
results = conn.execute(
|
|
135
|
+
"""
|
|
117
136
|
SELECT
|
|
118
137
|
ea.*,
|
|
119
138
|
s.port,
|
|
@@ -125,14 +144,18 @@ def get_attempts_by_host(host_id: int) -> List[Dict[str, Any]]:
|
|
|
125
144
|
LEFT JOIN hosts h ON ea.host_id = h.id
|
|
126
145
|
WHERE ea.host_id = ?
|
|
127
146
|
ORDER BY ea.updated_at DESC
|
|
128
|
-
""",
|
|
147
|
+
""",
|
|
148
|
+
(host_id,),
|
|
149
|
+
).fetchall()
|
|
129
150
|
|
|
130
151
|
conn.close()
|
|
131
152
|
|
|
132
153
|
return [dict(r) for r in results]
|
|
133
154
|
|
|
134
155
|
|
|
135
|
-
def get_attempts_by_engagement(
|
|
156
|
+
def get_attempts_by_engagement(
|
|
157
|
+
engagement_id: int, status_filter: Optional[str] = None
|
|
158
|
+
) -> List[Dict[str, Any]]:
|
|
136
159
|
"""
|
|
137
160
|
Get all exploit attempts for an engagement, optionally filtered by status.
|
|
138
161
|
|
|
@@ -162,7 +185,9 @@ def get_attempts_by_engagement(engagement_id: int, status_filter: Optional[str]
|
|
|
162
185
|
|
|
163
186
|
if status_filter:
|
|
164
187
|
if status_filter not in VALID_STATUSES:
|
|
165
|
-
raise ValueError(
|
|
188
|
+
raise ValueError(
|
|
189
|
+
f"Invalid status filter. Must be one of: {', '.join(VALID_STATUSES)}"
|
|
190
|
+
)
|
|
166
191
|
query += " AND ea.status = ?"
|
|
167
192
|
params.append(status_filter)
|
|
168
193
|
|
|
@@ -186,43 +211,43 @@ def get_attempt_stats(engagement_id: int) -> Dict[str, Any]:
|
|
|
186
211
|
conn = db.get_connection()
|
|
187
212
|
|
|
188
213
|
# Get status breakdown
|
|
189
|
-
status_counts = conn.execute(
|
|
214
|
+
status_counts = conn.execute(
|
|
215
|
+
"""
|
|
190
216
|
SELECT status, COUNT(*) as count
|
|
191
217
|
FROM exploit_attempts
|
|
192
218
|
WHERE engagement_id = ?
|
|
193
219
|
GROUP BY status
|
|
194
|
-
""",
|
|
220
|
+
""",
|
|
221
|
+
(engagement_id,),
|
|
222
|
+
).fetchall()
|
|
195
223
|
|
|
196
|
-
stats = {
|
|
197
|
-
'total': 0,
|
|
198
|
-
'not_tried': 0,
|
|
199
|
-
'attempted': 0,
|
|
200
|
-
'failed': 0,
|
|
201
|
-
'success': 0
|
|
202
|
-
}
|
|
224
|
+
stats = {"total": 0, "not_tried": 0, "attempted": 0, "failed": 0, "success": 0}
|
|
203
225
|
|
|
204
226
|
for row in status_counts:
|
|
205
|
-
stats[
|
|
206
|
-
stats[row[
|
|
227
|
+
stats["total"] += row["count"]
|
|
228
|
+
stats[row["status"]] = row["count"]
|
|
207
229
|
|
|
208
230
|
# Get success rate if attempts have been made
|
|
209
|
-
total_attempts = stats[
|
|
231
|
+
total_attempts = stats["attempted"] + stats["failed"] + stats["success"]
|
|
210
232
|
if total_attempts > 0:
|
|
211
|
-
stats[
|
|
233
|
+
stats["success_rate"] = (stats["success"] / total_attempts) * 100
|
|
212
234
|
else:
|
|
213
|
-
stats[
|
|
235
|
+
stats["success_rate"] = 0
|
|
214
236
|
|
|
215
237
|
# Get host coverage
|
|
216
|
-
host_coverage = conn.execute(
|
|
238
|
+
host_coverage = conn.execute(
|
|
239
|
+
"""
|
|
217
240
|
SELECT
|
|
218
241
|
COUNT(DISTINCT host_id) as hosts_with_attempts,
|
|
219
242
|
(SELECT COUNT(*) FROM hosts WHERE engagement_id = ?) as total_hosts
|
|
220
243
|
FROM exploit_attempts
|
|
221
244
|
WHERE engagement_id = ?
|
|
222
|
-
""",
|
|
245
|
+
""",
|
|
246
|
+
(engagement_id, engagement_id),
|
|
247
|
+
).fetchone()
|
|
223
248
|
|
|
224
|
-
stats[
|
|
225
|
-
stats[
|
|
249
|
+
stats["hosts_with_attempts"] = host_coverage["hosts_with_attempts"]
|
|
250
|
+
stats["total_hosts"] = host_coverage["total_hosts"]
|
|
226
251
|
|
|
227
252
|
conn.close()
|
|
228
253
|
|
|
@@ -230,9 +255,7 @@ def get_attempt_stats(engagement_id: int) -> Dict[str, Any]:
|
|
|
230
255
|
|
|
231
256
|
|
|
232
257
|
def update_attempt_status(
|
|
233
|
-
attempt_id: int,
|
|
234
|
-
status: str,
|
|
235
|
-
notes: Optional[str] = None
|
|
258
|
+
attempt_id: int, status: str, notes: Optional[str] = None
|
|
236
259
|
) -> bool:
|
|
237
260
|
"""
|
|
238
261
|
Update the status of an existing attempt.
|
|
@@ -251,14 +274,22 @@ def update_attempt_status(
|
|
|
251
274
|
db = get_db()
|
|
252
275
|
conn = db.get_connection()
|
|
253
276
|
|
|
254
|
-
cursor = conn.execute(
|
|
277
|
+
cursor = conn.execute(
|
|
278
|
+
"""
|
|
255
279
|
UPDATE exploit_attempts
|
|
256
280
|
SET status = ?,
|
|
257
281
|
notes = ?,
|
|
258
282
|
attempted_at = ?,
|
|
259
283
|
updated_at = CURRENT_TIMESTAMP
|
|
260
284
|
WHERE id = ?
|
|
261
|
-
""",
|
|
285
|
+
""",
|
|
286
|
+
(
|
|
287
|
+
status,
|
|
288
|
+
notes,
|
|
289
|
+
datetime.now() if status != STATUS_NOT_TRIED else None,
|
|
290
|
+
attempt_id,
|
|
291
|
+
),
|
|
292
|
+
)
|
|
262
293
|
|
|
263
294
|
rows_updated = cursor.rowcount
|
|
264
295
|
|
|
@@ -287,7 +318,9 @@ def delete_attempts_by_engagement(engagement_id: int) -> int:
|
|
|
287
318
|
db = get_db()
|
|
288
319
|
conn = db.get_connection()
|
|
289
320
|
|
|
290
|
-
cursor = conn.execute(
|
|
321
|
+
cursor = conn.execute(
|
|
322
|
+
"DELETE FROM exploit_attempts WHERE engagement_id = ?", (engagement_id,)
|
|
323
|
+
)
|
|
291
324
|
rows_deleted = cursor.rowcount
|
|
292
325
|
|
|
293
326
|
conn.commit()
|
|
@@ -327,13 +360,13 @@ def bulk_record_attempts(attempts: List[Dict[str, Any]]) -> int:
|
|
|
327
360
|
count = 0
|
|
328
361
|
for attempt in attempts:
|
|
329
362
|
record_attempt(
|
|
330
|
-
engagement_id=attempt[
|
|
331
|
-
host_id=attempt[
|
|
332
|
-
exploit_identifier=attempt[
|
|
333
|
-
exploit_title=attempt[
|
|
334
|
-
status=attempt[
|
|
335
|
-
service_id=attempt.get(
|
|
336
|
-
notes=attempt.get(
|
|
363
|
+
engagement_id=attempt["engagement_id"],
|
|
364
|
+
host_id=attempt["host_id"],
|
|
365
|
+
exploit_identifier=attempt["exploit_identifier"],
|
|
366
|
+
exploit_title=attempt["exploit_title"],
|
|
367
|
+
status=attempt["status"],
|
|
368
|
+
service_id=attempt.get("service_id"),
|
|
369
|
+
notes=attempt.get("notes"),
|
|
337
370
|
)
|
|
338
371
|
count += 1
|
|
339
372
|
|
|
@@ -352,12 +385,15 @@ def get_untried_exploits_for_host(engagement_id: int, host_id: int) -> List[str]
|
|
|
352
385
|
db = get_db()
|
|
353
386
|
conn = db.get_connection()
|
|
354
387
|
|
|
355
|
-
results = conn.execute(
|
|
388
|
+
results = conn.execute(
|
|
389
|
+
"""
|
|
356
390
|
SELECT exploit_identifier
|
|
357
391
|
FROM exploit_attempts
|
|
358
392
|
WHERE engagement_id = ? AND host_id = ? AND status = ?
|
|
359
|
-
""",
|
|
393
|
+
""",
|
|
394
|
+
(engagement_id, host_id, STATUS_NOT_TRIED),
|
|
395
|
+
).fetchall()
|
|
360
396
|
|
|
361
397
|
conn.close()
|
|
362
398
|
|
|
363
|
-
return [r[
|
|
399
|
+
return [r["exploit_identifier"] for r in results]
|
souleyez/storage/exploits.py
CHANGED
|
@@ -15,26 +15,36 @@ def add_exploit(
|
|
|
15
15
|
url: str,
|
|
16
16
|
date_published: str,
|
|
17
17
|
search_term: str,
|
|
18
|
-
service_id: Optional[int] = None
|
|
18
|
+
service_id: Optional[int] = None,
|
|
19
19
|
) -> int:
|
|
20
20
|
"""Add a new exploit to the database."""
|
|
21
21
|
db = get_db()
|
|
22
22
|
conn = db.get_connection()
|
|
23
|
-
|
|
24
|
-
cursor = conn.execute(
|
|
23
|
+
|
|
24
|
+
cursor = conn.execute(
|
|
25
|
+
"""
|
|
25
26
|
INSERT INTO exploits (
|
|
26
27
|
engagement_id, service_id, edb_id, title, platform,
|
|
27
28
|
type, url, date_published, search_term
|
|
28
29
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
29
|
-
""",
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
""",
|
|
31
|
+
(
|
|
32
|
+
engagement_id,
|
|
33
|
+
service_id,
|
|
34
|
+
edb_id,
|
|
35
|
+
title,
|
|
36
|
+
platform,
|
|
37
|
+
exploit_type,
|
|
38
|
+
url,
|
|
39
|
+
date_published,
|
|
40
|
+
search_term,
|
|
41
|
+
),
|
|
42
|
+
)
|
|
43
|
+
|
|
34
44
|
exploit_id = cursor.lastrowid
|
|
35
45
|
conn.commit()
|
|
36
46
|
conn.close()
|
|
37
|
-
|
|
47
|
+
|
|
38
48
|
return exploit_id
|
|
39
49
|
|
|
40
50
|
|
|
@@ -42,8 +52,9 @@ def get_exploits_by_engagement(engagement_id: int) -> List[Dict[str, Any]]:
|
|
|
42
52
|
"""Get all exploits for an engagement."""
|
|
43
53
|
db = get_db()
|
|
44
54
|
conn = db.get_connection()
|
|
45
|
-
|
|
46
|
-
results = conn.execute(
|
|
55
|
+
|
|
56
|
+
results = conn.execute(
|
|
57
|
+
"""
|
|
47
58
|
SELECT
|
|
48
59
|
e.*,
|
|
49
60
|
s.port,
|
|
@@ -55,10 +66,12 @@ def get_exploits_by_engagement(engagement_id: int) -> List[Dict[str, Any]]:
|
|
|
55
66
|
LEFT JOIN hosts h ON s.host_id = h.id
|
|
56
67
|
WHERE e.engagement_id = ?
|
|
57
68
|
ORDER BY e.found_at DESC
|
|
58
|
-
""",
|
|
59
|
-
|
|
69
|
+
""",
|
|
70
|
+
(engagement_id,),
|
|
71
|
+
).fetchall()
|
|
72
|
+
|
|
60
73
|
conn.close()
|
|
61
|
-
|
|
74
|
+
|
|
62
75
|
return [dict(r) for r in results]
|
|
63
76
|
|
|
64
77
|
|
|
@@ -66,15 +79,18 @@ def get_exploits_by_service(service_id: int) -> List[Dict[str, Any]]:
|
|
|
66
79
|
"""Get all exploits for a specific service."""
|
|
67
80
|
db = get_db()
|
|
68
81
|
conn = db.get_connection()
|
|
69
|
-
|
|
70
|
-
results = conn.execute(
|
|
82
|
+
|
|
83
|
+
results = conn.execute(
|
|
84
|
+
"""
|
|
71
85
|
SELECT * FROM exploits
|
|
72
86
|
WHERE service_id = ?
|
|
73
87
|
ORDER BY found_at DESC
|
|
74
|
-
""",
|
|
75
|
-
|
|
88
|
+
""",
|
|
89
|
+
(service_id,),
|
|
90
|
+
).fetchall()
|
|
91
|
+
|
|
76
92
|
conn.close()
|
|
77
|
-
|
|
93
|
+
|
|
78
94
|
return [dict(r) for r in results]
|
|
79
95
|
|
|
80
96
|
|
|
@@ -84,7 +100,8 @@ def get_exploit_stats(engagement_id: int) -> Dict[str, Any]:
|
|
|
84
100
|
conn = db.get_connection()
|
|
85
101
|
|
|
86
102
|
# Get basic stats
|
|
87
|
-
stats = conn.execute(
|
|
103
|
+
stats = conn.execute(
|
|
104
|
+
"""
|
|
88
105
|
SELECT
|
|
89
106
|
COUNT(*) as total,
|
|
90
107
|
COUNT(DISTINCT platform) as platforms,
|
|
@@ -92,36 +109,48 @@ def get_exploit_stats(engagement_id: int) -> Dict[str, Any]:
|
|
|
92
109
|
COUNT(DISTINCT service_id) as services_with_exploits
|
|
93
110
|
FROM exploits
|
|
94
111
|
WHERE engagement_id = ?
|
|
95
|
-
""",
|
|
112
|
+
""",
|
|
113
|
+
(engagement_id,),
|
|
114
|
+
).fetchone()
|
|
96
115
|
|
|
97
|
-
result =
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
116
|
+
result = (
|
|
117
|
+
dict(stats)
|
|
118
|
+
if stats
|
|
119
|
+
else {"total": 0, "platforms": 0, "types": 0, "services_with_exploits": 0}
|
|
120
|
+
)
|
|
103
121
|
|
|
104
122
|
# Get platform breakdown (top 5)
|
|
105
|
-
platform_breakdown = conn.execute(
|
|
123
|
+
platform_breakdown = conn.execute(
|
|
124
|
+
"""
|
|
106
125
|
SELECT platform, COUNT(*) as count
|
|
107
126
|
FROM exploits
|
|
108
127
|
WHERE engagement_id = ?
|
|
109
128
|
GROUP BY platform
|
|
110
129
|
ORDER BY count DESC
|
|
111
130
|
LIMIT 5
|
|
112
|
-
""",
|
|
113
|
-
|
|
131
|
+
""",
|
|
132
|
+
(engagement_id,),
|
|
133
|
+
).fetchall()
|
|
134
|
+
result["platform_breakdown"] = [
|
|
135
|
+
{"platform": row["platform"], "count": row["count"]}
|
|
136
|
+
for row in platform_breakdown
|
|
137
|
+
]
|
|
114
138
|
|
|
115
139
|
# Get type breakdown (top 5)
|
|
116
|
-
type_breakdown = conn.execute(
|
|
140
|
+
type_breakdown = conn.execute(
|
|
141
|
+
"""
|
|
117
142
|
SELECT type, COUNT(*) as count
|
|
118
143
|
FROM exploits
|
|
119
144
|
WHERE engagement_id = ?
|
|
120
145
|
GROUP BY type
|
|
121
146
|
ORDER BY count DESC
|
|
122
147
|
LIMIT 5
|
|
123
|
-
""",
|
|
124
|
-
|
|
148
|
+
""",
|
|
149
|
+
(engagement_id,),
|
|
150
|
+
).fetchall()
|
|
151
|
+
result["type_breakdown"] = [
|
|
152
|
+
{"type": row["type"], "count": row["count"]} for row in type_breakdown
|
|
153
|
+
]
|
|
125
154
|
|
|
126
155
|
conn.close()
|
|
127
156
|
|
|
@@ -147,7 +176,9 @@ def delete_exploits_by_engagement(engagement_id: int) -> int:
|
|
|
147
176
|
db = get_db()
|
|
148
177
|
conn = db.get_connection()
|
|
149
178
|
|
|
150
|
-
cursor = conn.execute(
|
|
179
|
+
cursor = conn.execute(
|
|
180
|
+
"DELETE FROM exploits WHERE engagement_id = ?", (engagement_id,)
|
|
181
|
+
)
|
|
151
182
|
rows_deleted = cursor.rowcount
|
|
152
183
|
|
|
153
184
|
conn.commit()
|
|
@@ -164,7 +195,7 @@ def delete_exploits_by_ids(exploit_ids: List[int]) -> int:
|
|
|
164
195
|
db = get_db()
|
|
165
196
|
conn = db.get_connection()
|
|
166
197
|
|
|
167
|
-
placeholders =
|
|
198
|
+
placeholders = ",".join("?" * len(exploit_ids))
|
|
168
199
|
query = f"DELETE FROM exploits WHERE id IN ({placeholders})"
|
|
169
200
|
|
|
170
201
|
cursor = conn.execute(query, exploit_ids)
|
|
@@ -210,7 +241,7 @@ def search_exploits(engagement_id: int, search_term: str) -> List[Dict[str, Any]
|
|
|
210
241
|
)
|
|
211
242
|
"""
|
|
212
243
|
# Add three parameters (one for each field) for this keyword
|
|
213
|
-
keyword_pattern = f
|
|
244
|
+
keyword_pattern = f"%{keyword}%"
|
|
214
245
|
params.extend([keyword_pattern, keyword_pattern, keyword_pattern])
|
|
215
246
|
|
|
216
247
|
query += "ORDER BY e.found_at DESC"
|