souleyez 2.43.29__py3-none-any.whl → 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- souleyez/__init__.py +1 -2
- souleyez/ai/__init__.py +21 -15
- souleyez/ai/action_mapper.py +249 -150
- souleyez/ai/chain_advisor.py +116 -100
- souleyez/ai/claude_provider.py +29 -28
- souleyez/ai/context_builder.py +80 -62
- souleyez/ai/executor.py +158 -117
- souleyez/ai/feedback_handler.py +136 -121
- souleyez/ai/llm_factory.py +27 -20
- souleyez/ai/llm_provider.py +4 -2
- souleyez/ai/ollama_provider.py +6 -9
- souleyez/ai/ollama_service.py +44 -37
- souleyez/ai/path_scorer.py +91 -76
- souleyez/ai/recommender.py +176 -144
- souleyez/ai/report_context.py +74 -73
- souleyez/ai/report_service.py +84 -66
- souleyez/ai/result_parser.py +222 -229
- souleyez/ai/safety.py +67 -44
- souleyez/auth/__init__.py +23 -22
- souleyez/auth/audit.py +36 -26
- souleyez/auth/engagement_access.py +65 -48
- souleyez/auth/permissions.py +14 -3
- souleyez/auth/session_manager.py +54 -37
- souleyez/auth/user_manager.py +109 -64
- souleyez/commands/audit.py +40 -43
- souleyez/commands/auth.py +35 -15
- souleyez/commands/deliverables.py +55 -50
- souleyez/commands/engagement.py +47 -28
- souleyez/commands/license.py +32 -23
- souleyez/commands/screenshots.py +36 -32
- souleyez/commands/user.py +82 -36
- souleyez/config.py +52 -44
- souleyez/core/credential_tester.py +87 -81
- souleyez/core/cve_mappings.py +179 -192
- souleyez/core/cve_matcher.py +162 -148
- souleyez/core/msf_auto_mapper.py +100 -83
- souleyez/core/msf_chain_engine.py +294 -256
- souleyez/core/msf_database.py +153 -70
- souleyez/core/msf_integration.py +679 -673
- souleyez/core/msf_rpc_client.py +40 -42
- souleyez/core/msf_rpc_manager.py +77 -79
- souleyez/core/msf_sync_manager.py +241 -181
- souleyez/core/network_utils.py +22 -15
- souleyez/core/parser_handler.py +34 -25
- souleyez/core/pending_chains.py +114 -63
- souleyez/core/templates.py +158 -107
- souleyez/core/tool_chaining.py +9564 -2881
- souleyez/core/version_utils.py +79 -94
- souleyez/core/vuln_correlation.py +136 -89
- souleyez/core/web_utils.py +33 -32
- souleyez/data/wordlists/ad_users.txt +378 -0
- souleyez/data/wordlists/api_endpoints_large.txt +769 -0
- souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
- souleyez/data/wordlists/lfi_payloads.txt +82 -0
- souleyez/data/wordlists/passwords_brute.txt +1548 -0
- souleyez/data/wordlists/passwords_crack.txt +2479 -0
- souleyez/data/wordlists/passwords_spray.txt +386 -0
- souleyez/data/wordlists/subdomains_large.txt +5057 -0
- souleyez/data/wordlists/usernames_common.txt +694 -0
- souleyez/data/wordlists/web_dirs_large.txt +4769 -0
- souleyez/detection/__init__.py +1 -1
- souleyez/detection/attack_signatures.py +12 -17
- souleyez/detection/mitre_mappings.py +61 -55
- souleyez/detection/validator.py +97 -86
- souleyez/devtools.py +23 -10
- souleyez/docs/README.md +4 -4
- souleyez/docs/api-reference/cli-commands.md +2 -2
- souleyez/docs/developer-guide/adding-new-tools.md +562 -0
- souleyez/docs/user-guide/auto-chaining.md +30 -8
- souleyez/docs/user-guide/getting-started.md +1 -1
- souleyez/docs/user-guide/installation.md +26 -3
- souleyez/docs/user-guide/metasploit-integration.md +2 -2
- souleyez/docs/user-guide/rbac.md +1 -1
- souleyez/docs/user-guide/scope-management.md +1 -1
- souleyez/docs/user-guide/siem-integration.md +1 -1
- souleyez/docs/user-guide/tools-reference.md +1 -8
- souleyez/docs/user-guide/worker-management.md +1 -1
- souleyez/engine/background.py +1239 -535
- souleyez/engine/base.py +4 -1
- souleyez/engine/job_status.py +17 -49
- souleyez/engine/log_sanitizer.py +103 -77
- souleyez/engine/manager.py +38 -7
- souleyez/engine/result_handler.py +2200 -1550
- souleyez/engine/worker_manager.py +50 -41
- souleyez/export/evidence_bundle.py +72 -62
- souleyez/feature_flags/features.py +16 -20
- souleyez/feature_flags.py +5 -9
- souleyez/handlers/__init__.py +11 -0
- souleyez/handlers/base.py +188 -0
- souleyez/handlers/bash_handler.py +277 -0
- souleyez/handlers/bloodhound_handler.py +243 -0
- souleyez/handlers/certipy_handler.py +311 -0
- souleyez/handlers/crackmapexec_handler.py +486 -0
- souleyez/handlers/dnsrecon_handler.py +344 -0
- souleyez/handlers/enum4linux_handler.py +400 -0
- souleyez/handlers/evil_winrm_handler.py +493 -0
- souleyez/handlers/ffuf_handler.py +815 -0
- souleyez/handlers/gobuster_handler.py +1114 -0
- souleyez/handlers/gpp_extract_handler.py +334 -0
- souleyez/handlers/hashcat_handler.py +444 -0
- souleyez/handlers/hydra_handler.py +564 -0
- souleyez/handlers/impacket_getuserspns_handler.py +343 -0
- souleyez/handlers/impacket_psexec_handler.py +222 -0
- souleyez/handlers/impacket_secretsdump_handler.py +426 -0
- souleyez/handlers/john_handler.py +286 -0
- souleyez/handlers/katana_handler.py +425 -0
- souleyez/handlers/kerbrute_handler.py +298 -0
- souleyez/handlers/ldapsearch_handler.py +636 -0
- souleyez/handlers/lfi_extract_handler.py +464 -0
- souleyez/handlers/msf_auxiliary_handler.py +409 -0
- souleyez/handlers/msf_exploit_handler.py +380 -0
- souleyez/handlers/nikto_handler.py +413 -0
- souleyez/handlers/nmap_handler.py +821 -0
- souleyez/handlers/nuclei_handler.py +359 -0
- souleyez/handlers/nxc_handler.py +417 -0
- souleyez/handlers/rdp_sec_check_handler.py +353 -0
- souleyez/handlers/registry.py +292 -0
- souleyez/handlers/responder_handler.py +232 -0
- souleyez/handlers/service_explorer_handler.py +434 -0
- souleyez/handlers/smbclient_handler.py +344 -0
- souleyez/handlers/smbmap_handler.py +510 -0
- souleyez/handlers/smbpasswd_handler.py +296 -0
- souleyez/handlers/sqlmap_handler.py +1116 -0
- souleyez/handlers/theharvester_handler.py +601 -0
- souleyez/handlers/web_login_test_handler.py +327 -0
- souleyez/handlers/whois_handler.py +277 -0
- souleyez/handlers/wpscan_handler.py +554 -0
- souleyez/history.py +32 -16
- souleyez/importers/msf_importer.py +106 -75
- souleyez/importers/smart_importer.py +208 -147
- souleyez/integrations/siem/__init__.py +10 -10
- souleyez/integrations/siem/base.py +17 -18
- souleyez/integrations/siem/elastic.py +108 -122
- souleyez/integrations/siem/factory.py +207 -80
- souleyez/integrations/siem/googlesecops.py +146 -154
- souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
- souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
- souleyez/integrations/siem/sentinel.py +107 -109
- souleyez/integrations/siem/splunk.py +246 -212
- souleyez/integrations/siem/wazuh.py +65 -71
- souleyez/integrations/wazuh/__init__.py +5 -5
- souleyez/integrations/wazuh/client.py +70 -93
- souleyez/integrations/wazuh/config.py +85 -57
- souleyez/integrations/wazuh/host_mapper.py +28 -36
- souleyez/integrations/wazuh/sync.py +78 -68
- souleyez/intelligence/__init__.py +4 -5
- souleyez/intelligence/correlation_analyzer.py +309 -295
- souleyez/intelligence/exploit_knowledge.py +661 -623
- souleyez/intelligence/exploit_suggestions.py +159 -139
- souleyez/intelligence/gap_analyzer.py +132 -97
- souleyez/intelligence/gap_detector.py +251 -214
- souleyez/intelligence/sensitive_tables.py +266 -129
- souleyez/intelligence/service_parser.py +137 -123
- souleyez/intelligence/surface_analyzer.py +407 -268
- souleyez/intelligence/target_parser.py +159 -162
- souleyez/licensing/__init__.py +6 -6
- souleyez/licensing/validator.py +17 -19
- souleyez/log_config.py +79 -54
- souleyez/main.py +1505 -687
- souleyez/migrations/fix_job_counter.py +16 -14
- souleyez/parsers/bloodhound_parser.py +41 -39
- souleyez/parsers/crackmapexec_parser.py +178 -111
- souleyez/parsers/dalfox_parser.py +72 -77
- souleyez/parsers/dnsrecon_parser.py +103 -91
- souleyez/parsers/enum4linux_parser.py +183 -153
- souleyez/parsers/ffuf_parser.py +29 -25
- souleyez/parsers/gobuster_parser.py +301 -41
- souleyez/parsers/hashcat_parser.py +324 -79
- souleyez/parsers/http_fingerprint_parser.py +350 -103
- souleyez/parsers/hydra_parser.py +131 -111
- souleyez/parsers/impacket_parser.py +231 -178
- souleyez/parsers/john_parser.py +98 -86
- souleyez/parsers/katana_parser.py +316 -0
- souleyez/parsers/msf_parser.py +943 -498
- souleyez/parsers/nikto_parser.py +346 -65
- souleyez/parsers/nmap_parser.py +262 -174
- souleyez/parsers/nuclei_parser.py +40 -44
- souleyez/parsers/responder_parser.py +26 -26
- souleyez/parsers/searchsploit_parser.py +74 -74
- souleyez/parsers/service_explorer_parser.py +279 -0
- souleyez/parsers/smbmap_parser.py +180 -124
- souleyez/parsers/sqlmap_parser.py +434 -308
- souleyez/parsers/theharvester_parser.py +75 -57
- souleyez/parsers/whois_parser.py +135 -94
- souleyez/parsers/wpscan_parser.py +278 -190
- souleyez/plugins/afp.py +44 -36
- souleyez/plugins/afp_brute.py +114 -46
- souleyez/plugins/ard.py +48 -37
- souleyez/plugins/bloodhound.py +95 -61
- souleyez/plugins/certipy.py +303 -0
- souleyez/plugins/crackmapexec.py +186 -85
- souleyez/plugins/dalfox.py +120 -59
- souleyez/plugins/dns_hijack.py +146 -41
- souleyez/plugins/dnsrecon.py +97 -61
- souleyez/plugins/enum4linux.py +91 -66
- souleyez/plugins/evil_winrm.py +291 -0
- souleyez/plugins/ffuf.py +166 -90
- souleyez/plugins/firmware_extract.py +133 -29
- souleyez/plugins/gobuster.py +387 -190
- souleyez/plugins/gpp_extract.py +393 -0
- souleyez/plugins/hashcat.py +100 -73
- souleyez/plugins/http_fingerprint.py +913 -267
- souleyez/plugins/hydra.py +566 -200
- souleyez/plugins/impacket_getnpusers.py +117 -69
- souleyez/plugins/impacket_psexec.py +84 -64
- souleyez/plugins/impacket_secretsdump.py +103 -69
- souleyez/plugins/impacket_smbclient.py +89 -75
- souleyez/plugins/john.py +86 -69
- souleyez/plugins/katana.py +313 -0
- souleyez/plugins/kerbrute.py +237 -0
- souleyez/plugins/lfi_extract.py +541 -0
- souleyez/plugins/macos_ssh.py +117 -48
- souleyez/plugins/mdns.py +35 -30
- souleyez/plugins/msf_auxiliary.py +253 -130
- souleyez/plugins/msf_exploit.py +239 -161
- souleyez/plugins/nikto.py +134 -78
- souleyez/plugins/nmap.py +275 -91
- souleyez/plugins/nuclei.py +180 -89
- souleyez/plugins/nxc.py +285 -0
- souleyez/plugins/plugin_base.py +35 -36
- souleyez/plugins/plugin_template.py +13 -5
- souleyez/plugins/rdp_sec_check.py +130 -0
- souleyez/plugins/responder.py +112 -71
- souleyez/plugins/router_http_brute.py +76 -65
- souleyez/plugins/router_ssh_brute.py +118 -41
- souleyez/plugins/router_telnet_brute.py +124 -42
- souleyez/plugins/routersploit.py +91 -59
- souleyez/plugins/routersploit_exploit.py +77 -55
- souleyez/plugins/searchsploit.py +91 -77
- souleyez/plugins/service_explorer.py +1160 -0
- souleyez/plugins/smbmap.py +122 -72
- souleyez/plugins/smbpasswd.py +215 -0
- souleyez/plugins/sqlmap.py +301 -113
- souleyez/plugins/theharvester.py +127 -75
- souleyez/plugins/tr069.py +79 -57
- souleyez/plugins/upnp.py +65 -47
- souleyez/plugins/upnp_abuse.py +73 -55
- souleyez/plugins/vnc_access.py +129 -42
- souleyez/plugins/vnc_brute.py +109 -38
- souleyez/plugins/web_login_test.py +417 -0
- souleyez/plugins/whois.py +77 -58
- souleyez/plugins/wpscan.py +219 -69
- souleyez/reporting/__init__.py +2 -1
- souleyez/reporting/attack_chain.py +411 -346
- souleyez/reporting/charts.py +436 -501
- souleyez/reporting/compliance_mappings.py +334 -201
- souleyez/reporting/detection_report.py +126 -125
- souleyez/reporting/formatters.py +828 -591
- souleyez/reporting/generator.py +386 -302
- souleyez/reporting/metrics.py +72 -75
- souleyez/scanner.py +35 -29
- souleyez/security/__init__.py +37 -11
- souleyez/security/scope_validator.py +175 -106
- souleyez/security/validation.py +237 -149
- souleyez/security.py +22 -6
- souleyez/storage/credentials.py +247 -186
- souleyez/storage/crypto.py +296 -129
- souleyez/storage/database.py +73 -50
- souleyez/storage/db.py +58 -36
- souleyez/storage/deliverable_evidence.py +177 -128
- souleyez/storage/deliverable_exporter.py +282 -246
- souleyez/storage/deliverable_templates.py +134 -116
- souleyez/storage/deliverables.py +135 -130
- souleyez/storage/engagements.py +109 -56
- souleyez/storage/evidence.py +181 -152
- souleyez/storage/execution_log.py +31 -17
- souleyez/storage/exploit_attempts.py +93 -57
- souleyez/storage/exploits.py +67 -36
- souleyez/storage/findings.py +48 -61
- souleyez/storage/hosts.py +176 -144
- souleyez/storage/migrate_to_engagements.py +43 -19
- souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
- souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
- souleyez/storage/migrations/_003_add_execution_log.py +14 -8
- souleyez/storage/migrations/_005_screenshots.py +13 -5
- souleyez/storage/migrations/_006_deliverables.py +13 -5
- souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
- souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
- souleyez/storage/migrations/_010_evidence_linking.py +17 -10
- souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
- souleyez/storage/migrations/_012_team_collaboration.py +34 -21
- souleyez/storage/migrations/_013_add_host_tags.py +12 -6
- souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
- souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
- souleyez/storage/migrations/_016_add_domain_field.py +10 -4
- souleyez/storage/migrations/_017_msf_sessions.py +16 -8
- souleyez/storage/migrations/_018_add_osint_target.py +10 -6
- souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
- souleyez/storage/migrations/_020_add_rbac.py +36 -15
- souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
- souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
- souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
- souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
- souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
- souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
- souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
- souleyez/storage/migrations/__init__.py +26 -26
- souleyez/storage/migrations/migration_manager.py +19 -19
- souleyez/storage/msf_sessions.py +100 -65
- souleyez/storage/osint.py +17 -24
- souleyez/storage/recommendation_engine.py +269 -235
- souleyez/storage/screenshots.py +33 -32
- souleyez/storage/smb_shares.py +136 -92
- souleyez/storage/sqlmap_data.py +183 -128
- souleyez/storage/team_collaboration.py +135 -141
- souleyez/storage/timeline_tracker.py +122 -94
- souleyez/storage/wazuh_vulns.py +64 -66
- souleyez/storage/web_paths.py +33 -37
- souleyez/testing/credential_tester.py +221 -205
- souleyez/ui/__init__.py +1 -1
- souleyez/ui/ai_quotes.py +12 -12
- souleyez/ui/attack_surface.py +2439 -1516
- souleyez/ui/chain_rules_view.py +914 -382
- souleyez/ui/correlation_view.py +312 -230
- souleyez/ui/dashboard.py +2382 -1130
- souleyez/ui/deliverables_view.py +148 -62
- souleyez/ui/design_system.py +13 -13
- souleyez/ui/errors.py +49 -49
- souleyez/ui/evidence_linking_view.py +284 -179
- souleyez/ui/evidence_vault.py +393 -285
- souleyez/ui/exploit_suggestions_view.py +555 -349
- souleyez/ui/export_view.py +100 -66
- souleyez/ui/gap_analysis_view.py +315 -171
- souleyez/ui/help_system.py +105 -97
- souleyez/ui/intelligence_view.py +436 -293
- souleyez/ui/interactive.py +23034 -10679
- souleyez/ui/interactive_selector.py +75 -68
- souleyez/ui/log_formatter.py +47 -39
- souleyez/ui/menu_components.py +22 -13
- souleyez/ui/msf_auxiliary_menu.py +184 -133
- souleyez/ui/pending_chains_view.py +336 -172
- souleyez/ui/progress_indicators.py +5 -3
- souleyez/ui/recommendations_view.py +195 -137
- souleyez/ui/rule_builder.py +343 -225
- souleyez/ui/setup_wizard.py +678 -284
- souleyez/ui/shortcuts.py +217 -165
- souleyez/ui/splunk_gap_analysis_view.py +452 -270
- souleyez/ui/splunk_vulns_view.py +139 -86
- souleyez/ui/team_dashboard.py +498 -335
- souleyez/ui/template_selector.py +196 -105
- souleyez/ui/terminal.py +6 -6
- souleyez/ui/timeline_view.py +198 -127
- souleyez/ui/tool_setup.py +264 -164
- souleyez/ui/tutorial.py +202 -72
- souleyez/ui/tutorial_state.py +40 -40
- souleyez/ui/wazuh_vulns_view.py +235 -141
- souleyez/ui/wordlist_browser.py +260 -107
- souleyez/ui.py +464 -312
- souleyez/utils/tool_checker.py +427 -367
- souleyez/utils.py +33 -29
- souleyez/wordlists.py +134 -167
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/METADATA +2 -2
- souleyez-3.0.0.dist-info/RECORD +443 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/WHEEL +1 -1
- souleyez-2.43.29.dist-info/RECORD +0 -379
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/top_level.txt +0 -0
souleyez/storage/evidence.py
CHANGED
|
@@ -9,7 +9,7 @@ from datetime import datetime, timedelta
|
|
|
9
9
|
|
|
10
10
|
class EvidenceManager:
|
|
11
11
|
"""Manages evidence collection across all data sources."""
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
def __init__(self):
|
|
14
14
|
# Import existing managers
|
|
15
15
|
from souleyez.storage.osint import OsintManager
|
|
@@ -17,17 +17,19 @@ class EvidenceManager:
|
|
|
17
17
|
from souleyez.storage.findings import FindingsManager
|
|
18
18
|
from souleyez.storage.credentials import CredentialsManager
|
|
19
19
|
from souleyez.storage.screenshots import ScreenshotManager
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
self.osint = OsintManager()
|
|
22
22
|
self.hosts = HostManager()
|
|
23
23
|
self.findings = FindingsManager()
|
|
24
24
|
self.creds = CredentialsManager()
|
|
25
25
|
self.screenshots = ScreenshotManager()
|
|
26
|
-
|
|
27
|
-
def get_all_evidence(
|
|
26
|
+
|
|
27
|
+
def get_all_evidence(
|
|
28
|
+
self, engagement_id: int, filters: Optional[Dict] = None
|
|
29
|
+
) -> Dict[str, List[Dict]]:
|
|
28
30
|
"""
|
|
29
31
|
Get all evidence organized by pentesting phase.
|
|
30
|
-
|
|
32
|
+
|
|
31
33
|
Returns:
|
|
32
34
|
{
|
|
33
35
|
'reconnaissance': [...],
|
|
@@ -37,42 +39,43 @@ class EvidenceManager:
|
|
|
37
39
|
}
|
|
38
40
|
"""
|
|
39
41
|
evidence = {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
"reconnaissance": [],
|
|
43
|
+
"enumeration": [],
|
|
44
|
+
"exploitation": [],
|
|
45
|
+
"post_exploitation": [],
|
|
44
46
|
}
|
|
45
|
-
|
|
47
|
+
|
|
46
48
|
# Get all jobs and categorize
|
|
47
49
|
from souleyez.engine.background import list_jobs
|
|
50
|
+
|
|
48
51
|
jobs = list_jobs()
|
|
49
|
-
|
|
52
|
+
|
|
50
53
|
# Filter jobs by engagement
|
|
51
|
-
engagement_jobs = [j for j in jobs if j.get(
|
|
52
|
-
|
|
54
|
+
engagement_jobs = [j for j in jobs if j.get("engagement_id") == engagement_id]
|
|
55
|
+
|
|
53
56
|
for job in engagement_jobs:
|
|
54
|
-
if job.get(
|
|
57
|
+
if job.get("status") not in ["done", "error"]:
|
|
55
58
|
continue # Only show completed jobs
|
|
56
|
-
|
|
57
|
-
phase = self._classify_phase(job[
|
|
59
|
+
|
|
60
|
+
phase = self._classify_phase(job["tool"])
|
|
58
61
|
item = self._job_to_evidence(job)
|
|
59
62
|
if self._matches_filters(item, filters):
|
|
60
63
|
evidence[phase].append(item)
|
|
61
|
-
|
|
64
|
+
|
|
62
65
|
# Get findings (exploitation phase)
|
|
63
66
|
findings = self.findings.list_findings(engagement_id)
|
|
64
67
|
for finding in findings:
|
|
65
68
|
item = self._finding_to_evidence(finding)
|
|
66
69
|
if self._matches_filters(item, filters):
|
|
67
|
-
evidence[
|
|
68
|
-
|
|
70
|
+
evidence["exploitation"].append(item)
|
|
71
|
+
|
|
69
72
|
# Get credentials (exploitation phase)
|
|
70
73
|
creds = self.creds.list_credentials(engagement_id)
|
|
71
74
|
for cred in creds:
|
|
72
75
|
item = self._credential_to_evidence(cred)
|
|
73
76
|
if self._matches_filters(item, filters):
|
|
74
|
-
evidence[
|
|
75
|
-
|
|
77
|
+
evidence["exploitation"].append(item)
|
|
78
|
+
|
|
76
79
|
# Get screenshots (all phases based on links)
|
|
77
80
|
screenshots = self.screenshots.list_screenshots(engagement_id)
|
|
78
81
|
for screenshot in screenshots:
|
|
@@ -81,38 +84,62 @@ class EvidenceManager:
|
|
|
81
84
|
# Determine phase based on linked entities
|
|
82
85
|
phase = self._classify_screenshot_phase(screenshot)
|
|
83
86
|
evidence[phase].append(item)
|
|
84
|
-
|
|
87
|
+
|
|
85
88
|
# Sort each phase by date (newest first)
|
|
86
89
|
for phase in evidence:
|
|
87
|
-
evidence[phase].sort(key=lambda x: x[
|
|
88
|
-
|
|
90
|
+
evidence[phase].sort(key=lambda x: x["created_at"], reverse=True)
|
|
91
|
+
|
|
89
92
|
return evidence
|
|
90
|
-
|
|
93
|
+
|
|
91
94
|
def _classify_phase(self, tool: str) -> str:
|
|
92
95
|
"""Classify tool into pentesting methodology phase."""
|
|
93
96
|
tool_lower = tool.lower()
|
|
94
|
-
|
|
97
|
+
|
|
95
98
|
# Reconnaissance tools
|
|
96
|
-
if tool_lower in [
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
if tool_lower in [
|
|
100
|
+
"nmap",
|
|
101
|
+
"theharvester",
|
|
102
|
+
"dnsrecon",
|
|
103
|
+
"whois",
|
|
104
|
+
"fierce",
|
|
105
|
+
"masscan",
|
|
106
|
+
]:
|
|
107
|
+
return "reconnaissance"
|
|
108
|
+
|
|
99
109
|
# Enumeration tools
|
|
100
|
-
if tool_lower in [
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
if tool_lower in [
|
|
111
|
+
"gobuster",
|
|
112
|
+
"dirb",
|
|
113
|
+
"wpscan",
|
|
114
|
+
"enum4linux",
|
|
115
|
+
"smbclient",
|
|
116
|
+
"smbmap",
|
|
117
|
+
"rpcclient",
|
|
118
|
+
"snmpwalk",
|
|
119
|
+
"nuclei",
|
|
120
|
+
]:
|
|
121
|
+
return "enumeration"
|
|
122
|
+
|
|
104
123
|
# Exploitation tools
|
|
105
|
-
if tool_lower in [
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
124
|
+
if tool_lower in [
|
|
125
|
+
"metasploit",
|
|
126
|
+
"sqlmap",
|
|
127
|
+
"hydra",
|
|
128
|
+
"medusa",
|
|
129
|
+
"john",
|
|
130
|
+
"hashcat",
|
|
131
|
+
"exploit",
|
|
132
|
+
"msfconsole",
|
|
133
|
+
]:
|
|
134
|
+
return "exploitation"
|
|
135
|
+
|
|
109
136
|
# Default to enumeration for unknown tools
|
|
110
|
-
return
|
|
111
|
-
|
|
137
|
+
return "enumeration"
|
|
138
|
+
|
|
112
139
|
def _job_to_evidence(self, job: Dict) -> Dict:
|
|
113
140
|
"""Convert job to evidence item."""
|
|
114
141
|
# Generate a meaningful title
|
|
115
|
-
label = job.get(
|
|
142
|
+
label = job.get("label", "").strip()
|
|
116
143
|
if label:
|
|
117
144
|
title = label
|
|
118
145
|
else:
|
|
@@ -120,30 +147,30 @@ class EvidenceManager:
|
|
|
120
147
|
title = self._generate_job_title(job)
|
|
121
148
|
|
|
122
149
|
return {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
150
|
+
"type": "job",
|
|
151
|
+
"id": job["id"],
|
|
152
|
+
"tool": job["tool"],
|
|
153
|
+
"target": job.get("target", "N/A"),
|
|
154
|
+
"title": title,
|
|
155
|
+
"label": label, # Keep label separate for display
|
|
156
|
+
"description": self._generate_job_summary(job),
|
|
157
|
+
"created_at": job.get("created_at", ""),
|
|
158
|
+
"status": job.get("status", "unknown"),
|
|
159
|
+
"log_path": job.get("log"),
|
|
160
|
+
"metadata": {
|
|
161
|
+
"job_id": job["id"],
|
|
162
|
+
"label": label,
|
|
163
|
+
"args": job.get("args", []),
|
|
164
|
+
},
|
|
138
165
|
}
|
|
139
166
|
|
|
140
167
|
def _generate_job_title(self, job: Dict) -> str:
|
|
141
168
|
"""Generate a meaningful title for jobs without labels."""
|
|
142
|
-
tool = job[
|
|
143
|
-
target = job.get(
|
|
169
|
+
tool = job["tool"].title()
|
|
170
|
+
target = job.get("target", "N/A")
|
|
144
171
|
|
|
145
172
|
# Handle multiple targets (space-separated IPs)
|
|
146
|
-
if
|
|
173
|
+
if " " in target:
|
|
147
174
|
targets = target.split()
|
|
148
175
|
if len(targets) > 3:
|
|
149
176
|
return f"{tool} scan ({len(targets)} hosts)"
|
|
@@ -151,158 +178,160 @@ class EvidenceManager:
|
|
|
151
178
|
return f"{tool} - {targets[0]} +{len(targets)-1} more"
|
|
152
179
|
|
|
153
180
|
# Handle CIDR notation
|
|
154
|
-
if
|
|
181
|
+
if "/" in target:
|
|
155
182
|
return f"{tool} - {target}"
|
|
156
183
|
|
|
157
184
|
# Single target - just show it
|
|
158
185
|
return f"{tool} - {target}"
|
|
159
|
-
|
|
186
|
+
|
|
160
187
|
def _finding_to_evidence(self, finding: Dict) -> Dict:
|
|
161
188
|
"""Convert finding to evidence item."""
|
|
162
|
-
target = finding.get(
|
|
189
|
+
target = finding.get("host") or finding.get("url", "Unknown")
|
|
163
190
|
return {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
191
|
+
"type": "finding",
|
|
192
|
+
"id": finding["id"],
|
|
193
|
+
"tool": finding.get("tool", "Unknown"),
|
|
194
|
+
"target": target,
|
|
195
|
+
"title": finding["title"],
|
|
196
|
+
"description": finding.get("description", "")[:200],
|
|
197
|
+
"created_at": finding.get("created_at", ""),
|
|
198
|
+
"severity": finding.get("severity", "info"),
|
|
199
|
+
"metadata": {
|
|
200
|
+
"finding_id": finding["id"],
|
|
201
|
+
"cvss": finding.get("cvss"),
|
|
202
|
+
"cve": finding.get("cve"),
|
|
203
|
+
},
|
|
177
204
|
}
|
|
178
|
-
|
|
205
|
+
|
|
179
206
|
def _credential_to_evidence(self, cred: Dict) -> Dict:
|
|
180
207
|
"""Convert credential to evidence item."""
|
|
181
208
|
return {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
209
|
+
"type": "credential",
|
|
210
|
+
"id": cred["id"],
|
|
211
|
+
"tool": cred.get("source", "Unknown"),
|
|
212
|
+
"target": f"{cred.get('host', 'N/A')}:{cred.get('port', '?')}",
|
|
213
|
+
"title": f"Credential: {cred.get('username', 'unknown')}",
|
|
214
|
+
"description": f"Service: {cred.get('service', 'unknown')}",
|
|
215
|
+
"created_at": cred.get("created_at", ""),
|
|
216
|
+
"metadata": {
|
|
217
|
+
"credential_id": cred["id"],
|
|
218
|
+
"username": cred.get("username"),
|
|
219
|
+
"service": cred.get("service"),
|
|
220
|
+
"status": cred.get("status"),
|
|
221
|
+
},
|
|
195
222
|
}
|
|
196
|
-
|
|
223
|
+
|
|
197
224
|
def _screenshot_to_evidence(self, screenshot: Dict) -> Dict:
|
|
198
225
|
"""Convert screenshot to evidence item."""
|
|
199
|
-
file_size = screenshot.get(
|
|
226
|
+
file_size = screenshot.get("file_size", 0)
|
|
200
227
|
if file_size < 1024:
|
|
201
228
|
size_str = f"{file_size} B"
|
|
202
229
|
elif file_size < 1024 * 1024:
|
|
203
230
|
size_str = f"{file_size / 1024:.1f} KB"
|
|
204
231
|
else:
|
|
205
232
|
size_str = f"{file_size / (1024 * 1024):.1f} MB"
|
|
206
|
-
|
|
233
|
+
|
|
207
234
|
return {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
235
|
+
"type": "screenshot",
|
|
236
|
+
"id": screenshot["id"],
|
|
237
|
+
"tool": "Screenshot",
|
|
238
|
+
"target": screenshot.get("title", screenshot.get("filename", "Unknown")),
|
|
239
|
+
"title": screenshot.get("title", screenshot.get("filename", "Untitled")),
|
|
240
|
+
"description": screenshot.get(
|
|
241
|
+
"description", f"Visual evidence ({size_str})"
|
|
242
|
+
),
|
|
243
|
+
"created_at": screenshot.get("created_at", ""),
|
|
244
|
+
"metadata": {
|
|
245
|
+
"screenshot_id": screenshot["id"],
|
|
246
|
+
"filename": screenshot.get("filename"),
|
|
247
|
+
"filepath": screenshot.get("filepath"),
|
|
248
|
+
"file_size": file_size,
|
|
249
|
+
"mime_type": screenshot.get("mime_type"),
|
|
250
|
+
"host_id": screenshot.get("host_id"),
|
|
251
|
+
"finding_id": screenshot.get("finding_id"),
|
|
252
|
+
"job_id": screenshot.get("job_id"),
|
|
253
|
+
},
|
|
225
254
|
}
|
|
226
|
-
|
|
255
|
+
|
|
227
256
|
def _classify_screenshot_phase(self, screenshot: Dict) -> str:
|
|
228
257
|
"""Classify screenshot into pentesting phase based on linked entities."""
|
|
229
258
|
# If linked to a finding, it's exploitation phase
|
|
230
|
-
if screenshot.get(
|
|
231
|
-
return
|
|
232
|
-
|
|
259
|
+
if screenshot.get("finding_id"):
|
|
260
|
+
return "exploitation"
|
|
261
|
+
|
|
233
262
|
# If linked to a job, classify by tool
|
|
234
|
-
if screenshot.get(
|
|
263
|
+
if screenshot.get("job_id"):
|
|
235
264
|
from souleyez.engine.background import get_job
|
|
236
|
-
|
|
265
|
+
|
|
266
|
+
job = get_job(screenshot["job_id"])
|
|
237
267
|
if job:
|
|
238
|
-
return self._classify_phase(job.get(
|
|
239
|
-
|
|
268
|
+
return self._classify_phase(job.get("tool", ""))
|
|
269
|
+
|
|
240
270
|
# Default to post-exploitation
|
|
241
|
-
return
|
|
242
|
-
|
|
271
|
+
return "post_exploitation"
|
|
272
|
+
|
|
243
273
|
def _generate_job_summary(self, job: Dict) -> str:
|
|
244
274
|
"""Generate human-readable summary from job."""
|
|
245
|
-
tool = job[
|
|
246
|
-
status = job.get(
|
|
247
|
-
|
|
248
|
-
if status ==
|
|
275
|
+
tool = job["tool"].lower()
|
|
276
|
+
status = job.get("status", "unknown")
|
|
277
|
+
|
|
278
|
+
if status == "error":
|
|
249
279
|
return "Completed with errors"
|
|
250
|
-
elif status ==
|
|
280
|
+
elif status == "killed":
|
|
251
281
|
return "Job was killed"
|
|
252
|
-
|
|
282
|
+
|
|
253
283
|
# Tool-specific summaries
|
|
254
|
-
if tool ==
|
|
284
|
+
if tool == "nmap":
|
|
255
285
|
return "Network port scan completed"
|
|
256
|
-
|
|
257
|
-
if tool ==
|
|
286
|
+
|
|
287
|
+
if tool == "theharvester":
|
|
258
288
|
return "OSINT data collection completed"
|
|
259
|
-
|
|
260
|
-
if tool ==
|
|
289
|
+
|
|
290
|
+
if tool == "nuclei":
|
|
261
291
|
return "Web vulnerability scan completed"
|
|
262
292
|
|
|
263
|
-
if tool ==
|
|
293
|
+
if tool == "gobuster":
|
|
264
294
|
return "Directory/file enumeration completed"
|
|
265
|
-
|
|
266
|
-
if tool ==
|
|
295
|
+
|
|
296
|
+
if tool == "sqlmap":
|
|
267
297
|
return "SQL injection testing completed"
|
|
268
|
-
|
|
269
|
-
if tool ==
|
|
298
|
+
|
|
299
|
+
if tool == "hydra":
|
|
270
300
|
return "Password brute force completed"
|
|
271
|
-
|
|
301
|
+
|
|
272
302
|
# Generic summary
|
|
273
303
|
return f"Scan completed: {status}"
|
|
274
|
-
|
|
304
|
+
|
|
275
305
|
def _matches_filters(self, item: Dict, filters: Optional[Dict]) -> bool:
|
|
276
306
|
"""Check if item matches filter criteria."""
|
|
277
307
|
if not filters:
|
|
278
308
|
return True
|
|
279
|
-
|
|
309
|
+
|
|
280
310
|
# Filter by tool
|
|
281
|
-
if
|
|
282
|
-
if item[
|
|
311
|
+
if "tool" in filters and filters["tool"] != "all":
|
|
312
|
+
if item["tool"].lower() != filters["tool"].lower():
|
|
283
313
|
return False
|
|
284
|
-
|
|
314
|
+
|
|
285
315
|
# Filter by host/target
|
|
286
|
-
if
|
|
287
|
-
if filters[
|
|
316
|
+
if "host" in filters and filters["host"] != "all":
|
|
317
|
+
if filters["host"] not in item["target"]:
|
|
288
318
|
return False
|
|
289
|
-
|
|
319
|
+
|
|
290
320
|
# Filter by date range
|
|
291
|
-
if
|
|
321
|
+
if "days" in filters:
|
|
292
322
|
try:
|
|
293
|
-
cutoff = datetime.now() - timedelta(days=filters[
|
|
294
|
-
item_date = datetime.fromisoformat(
|
|
323
|
+
cutoff = datetime.now() - timedelta(days=filters["days"])
|
|
324
|
+
item_date = datetime.fromisoformat(
|
|
325
|
+
item["created_at"].replace("Z", "+00:00")
|
|
326
|
+
)
|
|
295
327
|
if item_date < cutoff:
|
|
296
328
|
return False
|
|
297
329
|
except:
|
|
298
330
|
pass # Skip date filtering if parsing fails
|
|
299
|
-
|
|
331
|
+
|
|
300
332
|
return True
|
|
301
|
-
|
|
333
|
+
|
|
302
334
|
def get_evidence_count(self, engagement_id: int) -> Dict[str, int]:
|
|
303
335
|
"""Get count of evidence items per phase."""
|
|
304
336
|
evidence = self.get_all_evidence(engagement_id)
|
|
305
|
-
return {
|
|
306
|
-
phase: len(items)
|
|
307
|
-
for phase, items in evidence.items()
|
|
308
|
-
}
|
|
337
|
+
return {phase: len(items) for phase, items in evidence.items()}
|
|
@@ -12,7 +12,7 @@ from souleyez import config
|
|
|
12
12
|
|
|
13
13
|
def get_db_path():
|
|
14
14
|
"""Get database path."""
|
|
15
|
-
return Path(config.get(
|
|
15
|
+
return Path(config.get("database.path", "~/.souleyez/souleyez.db")).expanduser()
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class ExecutionLogManager:
|
|
@@ -28,11 +28,11 @@ class ExecutionLogManager:
|
|
|
28
28
|
command: str,
|
|
29
29
|
risk_level: str,
|
|
30
30
|
auto_approved: bool = False,
|
|
31
|
-
recommendation_id: Optional[str] = None
|
|
31
|
+
recommendation_id: Optional[str] = None,
|
|
32
32
|
) -> int:
|
|
33
33
|
"""
|
|
34
34
|
Log the start of an execution.
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
Args:
|
|
37
37
|
engagement_id: Engagement ID
|
|
38
38
|
action: Human-readable action description
|
|
@@ -40,18 +40,28 @@ class ExecutionLogManager:
|
|
|
40
40
|
risk_level: LOW/MEDIUM/HIGH
|
|
41
41
|
auto_approved: Whether it was auto-approved
|
|
42
42
|
recommendation_id: Optional ID linking to AI recommendation
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
Returns:
|
|
45
45
|
execution_id for updating later
|
|
46
46
|
"""
|
|
47
47
|
conn = sqlite3.connect(self.db_path)
|
|
48
48
|
cursor = conn.cursor()
|
|
49
49
|
|
|
50
|
-
cursor.execute(
|
|
50
|
+
cursor.execute(
|
|
51
|
+
"""
|
|
51
52
|
INSERT INTO execution_log
|
|
52
53
|
(engagement_id, recommendation_id, action, command, risk_level, auto_approved)
|
|
53
54
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
54
|
-
""",
|
|
55
|
+
""",
|
|
56
|
+
(
|
|
57
|
+
engagement_id,
|
|
58
|
+
recommendation_id,
|
|
59
|
+
action,
|
|
60
|
+
command,
|
|
61
|
+
risk_level,
|
|
62
|
+
auto_approved,
|
|
63
|
+
),
|
|
64
|
+
)
|
|
55
65
|
|
|
56
66
|
execution_id = cursor.lastrowid
|
|
57
67
|
conn.commit()
|
|
@@ -66,11 +76,11 @@ class ExecutionLogManager:
|
|
|
66
76
|
stdout: str,
|
|
67
77
|
stderr: str,
|
|
68
78
|
success: bool,
|
|
69
|
-
feedback_applied: Optional[Dict[str, Any]] = None
|
|
79
|
+
feedback_applied: Optional[Dict[str, Any]] = None,
|
|
70
80
|
):
|
|
71
81
|
"""
|
|
72
82
|
Update execution with results.
|
|
73
|
-
|
|
83
|
+
|
|
74
84
|
Args:
|
|
75
85
|
execution_id: Execution log ID
|
|
76
86
|
exit_code: Command exit code
|
|
@@ -85,7 +95,8 @@ class ExecutionLogManager:
|
|
|
85
95
|
# Convert feedback dict to JSON
|
|
86
96
|
feedback_json = json.dumps(feedback_applied) if feedback_applied else None
|
|
87
97
|
|
|
88
|
-
cursor.execute(
|
|
98
|
+
cursor.execute(
|
|
99
|
+
"""
|
|
89
100
|
UPDATE execution_log
|
|
90
101
|
SET exit_code = ?,
|
|
91
102
|
stdout = ?,
|
|
@@ -93,23 +104,23 @@ class ExecutionLogManager:
|
|
|
93
104
|
success = ?,
|
|
94
105
|
feedback_applied = ?
|
|
95
106
|
WHERE id = ?
|
|
96
|
-
""",
|
|
107
|
+
""",
|
|
108
|
+
(exit_code, stdout, stderr, success, feedback_json, execution_id),
|
|
109
|
+
)
|
|
97
110
|
|
|
98
111
|
conn.commit()
|
|
99
112
|
conn.close()
|
|
100
113
|
|
|
101
114
|
def get_recent_executions(
|
|
102
|
-
self,
|
|
103
|
-
engagement_id: int,
|
|
104
|
-
limit: int = 10
|
|
115
|
+
self, engagement_id: int, limit: int = 10
|
|
105
116
|
) -> List[Dict[str, Any]]:
|
|
106
117
|
"""
|
|
107
118
|
Get recent executions for an engagement.
|
|
108
|
-
|
|
119
|
+
|
|
109
120
|
Args:
|
|
110
121
|
engagement_id: Engagement ID
|
|
111
122
|
limit: Max results
|
|
112
|
-
|
|
123
|
+
|
|
113
124
|
Returns:
|
|
114
125
|
List of execution records
|
|
115
126
|
"""
|
|
@@ -117,13 +128,16 @@ class ExecutionLogManager:
|
|
|
117
128
|
conn.row_factory = sqlite3.Row
|
|
118
129
|
cursor = conn.cursor()
|
|
119
130
|
|
|
120
|
-
cursor.execute(
|
|
131
|
+
cursor.execute(
|
|
132
|
+
"""
|
|
121
133
|
SELECT *
|
|
122
134
|
FROM execution_log
|
|
123
135
|
WHERE engagement_id = ?
|
|
124
136
|
ORDER BY executed_at DESC
|
|
125
137
|
LIMIT ?
|
|
126
|
-
""",
|
|
138
|
+
""",
|
|
139
|
+
(engagement_id, limit),
|
|
140
|
+
)
|
|
127
141
|
|
|
128
142
|
rows = cursor.fetchall()
|
|
129
143
|
conn.close()
|