souleyez 2.43.29__py3-none-any.whl → 2.43.34__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- souleyez/__init__.py +1 -2
- souleyez/ai/__init__.py +21 -15
- souleyez/ai/action_mapper.py +249 -150
- souleyez/ai/chain_advisor.py +116 -100
- souleyez/ai/claude_provider.py +29 -28
- souleyez/ai/context_builder.py +80 -62
- souleyez/ai/executor.py +158 -117
- souleyez/ai/feedback_handler.py +136 -121
- souleyez/ai/llm_factory.py +27 -20
- souleyez/ai/llm_provider.py +4 -2
- souleyez/ai/ollama_provider.py +6 -9
- souleyez/ai/ollama_service.py +44 -37
- souleyez/ai/path_scorer.py +91 -76
- souleyez/ai/recommender.py +176 -144
- souleyez/ai/report_context.py +74 -73
- souleyez/ai/report_service.py +84 -66
- souleyez/ai/result_parser.py +222 -229
- souleyez/ai/safety.py +67 -44
- souleyez/auth/__init__.py +23 -22
- souleyez/auth/audit.py +36 -26
- souleyez/auth/engagement_access.py +65 -48
- souleyez/auth/permissions.py +14 -3
- souleyez/auth/session_manager.py +54 -37
- souleyez/auth/user_manager.py +109 -64
- souleyez/commands/audit.py +40 -43
- souleyez/commands/auth.py +35 -15
- souleyez/commands/deliverables.py +55 -50
- souleyez/commands/engagement.py +47 -28
- souleyez/commands/license.py +32 -23
- souleyez/commands/screenshots.py +36 -32
- souleyez/commands/user.py +82 -36
- souleyez/config.py +52 -44
- souleyez/core/credential_tester.py +87 -81
- souleyez/core/cve_mappings.py +179 -192
- souleyez/core/cve_matcher.py +162 -148
- souleyez/core/msf_auto_mapper.py +100 -83
- souleyez/core/msf_chain_engine.py +294 -256
- souleyez/core/msf_database.py +153 -70
- souleyez/core/msf_integration.py +679 -673
- souleyez/core/msf_rpc_client.py +40 -42
- souleyez/core/msf_rpc_manager.py +77 -79
- souleyez/core/msf_sync_manager.py +241 -181
- souleyez/core/network_utils.py +22 -15
- souleyez/core/parser_handler.py +34 -25
- souleyez/core/pending_chains.py +114 -63
- souleyez/core/templates.py +158 -107
- souleyez/core/tool_chaining.py +9526 -2879
- souleyez/core/version_utils.py +79 -94
- souleyez/core/vuln_correlation.py +136 -89
- souleyez/core/web_utils.py +33 -32
- souleyez/data/wordlists/ad_users.txt +378 -0
- souleyez/data/wordlists/api_endpoints_large.txt +769 -0
- souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
- souleyez/data/wordlists/lfi_payloads.txt +82 -0
- souleyez/data/wordlists/passwords_brute.txt +1548 -0
- souleyez/data/wordlists/passwords_crack.txt +2479 -0
- souleyez/data/wordlists/passwords_spray.txt +386 -0
- souleyez/data/wordlists/subdomains_large.txt +5057 -0
- souleyez/data/wordlists/usernames_common.txt +694 -0
- souleyez/data/wordlists/web_dirs_large.txt +4769 -0
- souleyez/detection/__init__.py +1 -1
- souleyez/detection/attack_signatures.py +12 -17
- souleyez/detection/mitre_mappings.py +61 -55
- souleyez/detection/validator.py +97 -86
- souleyez/devtools.py +23 -10
- souleyez/docs/README.md +4 -4
- souleyez/docs/api-reference/cli-commands.md +2 -2
- souleyez/docs/developer-guide/adding-new-tools.md +562 -0
- souleyez/docs/user-guide/auto-chaining.md +30 -8
- souleyez/docs/user-guide/getting-started.md +1 -1
- souleyez/docs/user-guide/installation.md +26 -3
- souleyez/docs/user-guide/metasploit-integration.md +2 -2
- souleyez/docs/user-guide/rbac.md +1 -1
- souleyez/docs/user-guide/scope-management.md +1 -1
- souleyez/docs/user-guide/siem-integration.md +1 -1
- souleyez/docs/user-guide/tools-reference.md +1 -8
- souleyez/docs/user-guide/worker-management.md +1 -1
- souleyez/engine/background.py +1239 -535
- souleyez/engine/base.py +4 -1
- souleyez/engine/job_status.py +17 -49
- souleyez/engine/log_sanitizer.py +103 -77
- souleyez/engine/manager.py +38 -7
- souleyez/engine/result_handler.py +2200 -1550
- souleyez/engine/worker_manager.py +50 -41
- souleyez/export/evidence_bundle.py +72 -62
- souleyez/feature_flags/features.py +16 -20
- souleyez/feature_flags.py +5 -9
- souleyez/handlers/__init__.py +11 -0
- souleyez/handlers/base.py +188 -0
- souleyez/handlers/bash_handler.py +277 -0
- souleyez/handlers/bloodhound_handler.py +243 -0
- souleyez/handlers/certipy_handler.py +311 -0
- souleyez/handlers/crackmapexec_handler.py +486 -0
- souleyez/handlers/dnsrecon_handler.py +344 -0
- souleyez/handlers/enum4linux_handler.py +400 -0
- souleyez/handlers/evil_winrm_handler.py +493 -0
- souleyez/handlers/ffuf_handler.py +815 -0
- souleyez/handlers/gobuster_handler.py +1114 -0
- souleyez/handlers/gpp_extract_handler.py +334 -0
- souleyez/handlers/hashcat_handler.py +444 -0
- souleyez/handlers/hydra_handler.py +563 -0
- souleyez/handlers/impacket_getuserspns_handler.py +343 -0
- souleyez/handlers/impacket_psexec_handler.py +222 -0
- souleyez/handlers/impacket_secretsdump_handler.py +426 -0
- souleyez/handlers/john_handler.py +286 -0
- souleyez/handlers/katana_handler.py +425 -0
- souleyez/handlers/kerbrute_handler.py +298 -0
- souleyez/handlers/ldapsearch_handler.py +636 -0
- souleyez/handlers/lfi_extract_handler.py +464 -0
- souleyez/handlers/msf_auxiliary_handler.py +408 -0
- souleyez/handlers/msf_exploit_handler.py +380 -0
- souleyez/handlers/nikto_handler.py +413 -0
- souleyez/handlers/nmap_handler.py +821 -0
- souleyez/handlers/nuclei_handler.py +359 -0
- souleyez/handlers/nxc_handler.py +371 -0
- souleyez/handlers/rdp_sec_check_handler.py +353 -0
- souleyez/handlers/registry.py +292 -0
- souleyez/handlers/responder_handler.py +232 -0
- souleyez/handlers/service_explorer_handler.py +434 -0
- souleyez/handlers/smbclient_handler.py +344 -0
- souleyez/handlers/smbmap_handler.py +510 -0
- souleyez/handlers/smbpasswd_handler.py +296 -0
- souleyez/handlers/sqlmap_handler.py +1116 -0
- souleyez/handlers/theharvester_handler.py +601 -0
- souleyez/handlers/web_login_test_handler.py +327 -0
- souleyez/handlers/whois_handler.py +277 -0
- souleyez/handlers/wpscan_handler.py +554 -0
- souleyez/history.py +32 -16
- souleyez/importers/msf_importer.py +106 -75
- souleyez/importers/smart_importer.py +208 -147
- souleyez/integrations/siem/__init__.py +10 -10
- souleyez/integrations/siem/base.py +17 -18
- souleyez/integrations/siem/elastic.py +108 -122
- souleyez/integrations/siem/factory.py +207 -80
- souleyez/integrations/siem/googlesecops.py +146 -154
- souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
- souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
- souleyez/integrations/siem/sentinel.py +107 -109
- souleyez/integrations/siem/splunk.py +246 -212
- souleyez/integrations/siem/wazuh.py +65 -71
- souleyez/integrations/wazuh/__init__.py +5 -5
- souleyez/integrations/wazuh/client.py +70 -93
- souleyez/integrations/wazuh/config.py +85 -57
- souleyez/integrations/wazuh/host_mapper.py +28 -36
- souleyez/integrations/wazuh/sync.py +78 -68
- souleyez/intelligence/__init__.py +4 -5
- souleyez/intelligence/correlation_analyzer.py +309 -295
- souleyez/intelligence/exploit_knowledge.py +661 -623
- souleyez/intelligence/exploit_suggestions.py +159 -139
- souleyez/intelligence/gap_analyzer.py +132 -97
- souleyez/intelligence/gap_detector.py +251 -214
- souleyez/intelligence/sensitive_tables.py +266 -129
- souleyez/intelligence/service_parser.py +137 -123
- souleyez/intelligence/surface_analyzer.py +407 -268
- souleyez/intelligence/target_parser.py +159 -162
- souleyez/licensing/__init__.py +6 -6
- souleyez/licensing/validator.py +17 -19
- souleyez/log_config.py +79 -54
- souleyez/main.py +1505 -687
- souleyez/migrations/fix_job_counter.py +16 -14
- souleyez/parsers/bloodhound_parser.py +41 -39
- souleyez/parsers/crackmapexec_parser.py +178 -111
- souleyez/parsers/dalfox_parser.py +72 -77
- souleyez/parsers/dnsrecon_parser.py +103 -91
- souleyez/parsers/enum4linux_parser.py +183 -153
- souleyez/parsers/ffuf_parser.py +29 -25
- souleyez/parsers/gobuster_parser.py +301 -41
- souleyez/parsers/hashcat_parser.py +324 -79
- souleyez/parsers/http_fingerprint_parser.py +350 -103
- souleyez/parsers/hydra_parser.py +131 -111
- souleyez/parsers/impacket_parser.py +231 -178
- souleyez/parsers/john_parser.py +98 -86
- souleyez/parsers/katana_parser.py +316 -0
- souleyez/parsers/msf_parser.py +943 -498
- souleyez/parsers/nikto_parser.py +346 -65
- souleyez/parsers/nmap_parser.py +262 -174
- souleyez/parsers/nuclei_parser.py +40 -44
- souleyez/parsers/responder_parser.py +26 -26
- souleyez/parsers/searchsploit_parser.py +74 -74
- souleyez/parsers/service_explorer_parser.py +279 -0
- souleyez/parsers/smbmap_parser.py +180 -124
- souleyez/parsers/sqlmap_parser.py +434 -308
- souleyez/parsers/theharvester_parser.py +75 -57
- souleyez/parsers/whois_parser.py +135 -94
- souleyez/parsers/wpscan_parser.py +278 -190
- souleyez/plugins/afp.py +44 -36
- souleyez/plugins/afp_brute.py +114 -46
- souleyez/plugins/ard.py +48 -37
- souleyez/plugins/bloodhound.py +95 -61
- souleyez/plugins/certipy.py +303 -0
- souleyez/plugins/crackmapexec.py +186 -85
- souleyez/plugins/dalfox.py +120 -59
- souleyez/plugins/dns_hijack.py +146 -41
- souleyez/plugins/dnsrecon.py +97 -61
- souleyez/plugins/enum4linux.py +91 -66
- souleyez/plugins/evil_winrm.py +291 -0
- souleyez/plugins/ffuf.py +166 -90
- souleyez/plugins/firmware_extract.py +133 -29
- souleyez/plugins/gobuster.py +387 -190
- souleyez/plugins/gpp_extract.py +393 -0
- souleyez/plugins/hashcat.py +100 -73
- souleyez/plugins/http_fingerprint.py +854 -267
- souleyez/plugins/hydra.py +566 -200
- souleyez/plugins/impacket_getnpusers.py +117 -69
- souleyez/plugins/impacket_psexec.py +84 -64
- souleyez/plugins/impacket_secretsdump.py +103 -69
- souleyez/plugins/impacket_smbclient.py +89 -75
- souleyez/plugins/john.py +86 -69
- souleyez/plugins/katana.py +313 -0
- souleyez/plugins/kerbrute.py +237 -0
- souleyez/plugins/lfi_extract.py +541 -0
- souleyez/plugins/macos_ssh.py +117 -48
- souleyez/plugins/mdns.py +35 -30
- souleyez/plugins/msf_auxiliary.py +253 -130
- souleyez/plugins/msf_exploit.py +239 -161
- souleyez/plugins/nikto.py +134 -78
- souleyez/plugins/nmap.py +275 -91
- souleyez/plugins/nuclei.py +180 -89
- souleyez/plugins/nxc.py +285 -0
- souleyez/plugins/plugin_base.py +35 -36
- souleyez/plugins/plugin_template.py +13 -5
- souleyez/plugins/rdp_sec_check.py +130 -0
- souleyez/plugins/responder.py +112 -71
- souleyez/plugins/router_http_brute.py +76 -65
- souleyez/plugins/router_ssh_brute.py +118 -41
- souleyez/plugins/router_telnet_brute.py +124 -42
- souleyez/plugins/routersploit.py +91 -59
- souleyez/plugins/routersploit_exploit.py +77 -55
- souleyez/plugins/searchsploit.py +91 -77
- souleyez/plugins/service_explorer.py +1160 -0
- souleyez/plugins/smbmap.py +122 -72
- souleyez/plugins/smbpasswd.py +215 -0
- souleyez/plugins/sqlmap.py +301 -113
- souleyez/plugins/theharvester.py +127 -75
- souleyez/plugins/tr069.py +79 -57
- souleyez/plugins/upnp.py +65 -47
- souleyez/plugins/upnp_abuse.py +73 -55
- souleyez/plugins/vnc_access.py +129 -42
- souleyez/plugins/vnc_brute.py +109 -38
- souleyez/plugins/web_login_test.py +417 -0
- souleyez/plugins/whois.py +77 -58
- souleyez/plugins/wpscan.py +173 -69
- souleyez/reporting/__init__.py +2 -1
- souleyez/reporting/attack_chain.py +411 -346
- souleyez/reporting/charts.py +436 -501
- souleyez/reporting/compliance_mappings.py +334 -201
- souleyez/reporting/detection_report.py +126 -125
- souleyez/reporting/formatters.py +828 -591
- souleyez/reporting/generator.py +386 -302
- souleyez/reporting/metrics.py +72 -75
- souleyez/scanner.py +35 -29
- souleyez/security/__init__.py +37 -11
- souleyez/security/scope_validator.py +175 -106
- souleyez/security/validation.py +223 -149
- souleyez/security.py +22 -6
- souleyez/storage/credentials.py +247 -186
- souleyez/storage/crypto.py +296 -129
- souleyez/storage/database.py +73 -50
- souleyez/storage/db.py +58 -36
- souleyez/storage/deliverable_evidence.py +177 -128
- souleyez/storage/deliverable_exporter.py +282 -246
- souleyez/storage/deliverable_templates.py +134 -116
- souleyez/storage/deliverables.py +135 -130
- souleyez/storage/engagements.py +109 -56
- souleyez/storage/evidence.py +181 -152
- souleyez/storage/execution_log.py +31 -17
- souleyez/storage/exploit_attempts.py +93 -57
- souleyez/storage/exploits.py +67 -36
- souleyez/storage/findings.py +48 -61
- souleyez/storage/hosts.py +176 -144
- souleyez/storage/migrate_to_engagements.py +43 -19
- souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
- souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
- souleyez/storage/migrations/_003_add_execution_log.py +14 -8
- souleyez/storage/migrations/_005_screenshots.py +13 -5
- souleyez/storage/migrations/_006_deliverables.py +13 -5
- souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
- souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
- souleyez/storage/migrations/_010_evidence_linking.py +17 -10
- souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
- souleyez/storage/migrations/_012_team_collaboration.py +34 -21
- souleyez/storage/migrations/_013_add_host_tags.py +12 -6
- souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
- souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
- souleyez/storage/migrations/_016_add_domain_field.py +10 -4
- souleyez/storage/migrations/_017_msf_sessions.py +16 -8
- souleyez/storage/migrations/_018_add_osint_target.py +10 -6
- souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
- souleyez/storage/migrations/_020_add_rbac.py +36 -15
- souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
- souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
- souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
- souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
- souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
- souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
- souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
- souleyez/storage/migrations/__init__.py +26 -26
- souleyez/storage/migrations/migration_manager.py +19 -19
- souleyez/storage/msf_sessions.py +100 -65
- souleyez/storage/osint.py +17 -24
- souleyez/storage/recommendation_engine.py +269 -235
- souleyez/storage/screenshots.py +33 -32
- souleyez/storage/smb_shares.py +136 -92
- souleyez/storage/sqlmap_data.py +183 -128
- souleyez/storage/team_collaboration.py +135 -141
- souleyez/storage/timeline_tracker.py +122 -94
- souleyez/storage/wazuh_vulns.py +64 -66
- souleyez/storage/web_paths.py +33 -37
- souleyez/testing/credential_tester.py +221 -205
- souleyez/ui/__init__.py +1 -1
- souleyez/ui/ai_quotes.py +12 -12
- souleyez/ui/attack_surface.py +2439 -1516
- souleyez/ui/chain_rules_view.py +914 -382
- souleyez/ui/correlation_view.py +312 -230
- souleyez/ui/dashboard.py +2382 -1130
- souleyez/ui/deliverables_view.py +148 -62
- souleyez/ui/design_system.py +13 -13
- souleyez/ui/errors.py +49 -49
- souleyez/ui/evidence_linking_view.py +284 -179
- souleyez/ui/evidence_vault.py +393 -285
- souleyez/ui/exploit_suggestions_view.py +555 -349
- souleyez/ui/export_view.py +100 -66
- souleyez/ui/gap_analysis_view.py +315 -171
- souleyez/ui/help_system.py +105 -97
- souleyez/ui/intelligence_view.py +436 -293
- souleyez/ui/interactive.py +22827 -10678
- souleyez/ui/interactive_selector.py +75 -68
- souleyez/ui/log_formatter.py +47 -39
- souleyez/ui/menu_components.py +22 -13
- souleyez/ui/msf_auxiliary_menu.py +184 -133
- souleyez/ui/pending_chains_view.py +336 -172
- souleyez/ui/progress_indicators.py +5 -3
- souleyez/ui/recommendations_view.py +195 -137
- souleyez/ui/rule_builder.py +343 -225
- souleyez/ui/setup_wizard.py +678 -284
- souleyez/ui/shortcuts.py +217 -165
- souleyez/ui/splunk_gap_analysis_view.py +452 -270
- souleyez/ui/splunk_vulns_view.py +139 -86
- souleyez/ui/team_dashboard.py +498 -335
- souleyez/ui/template_selector.py +196 -105
- souleyez/ui/terminal.py +6 -6
- souleyez/ui/timeline_view.py +198 -127
- souleyez/ui/tool_setup.py +264 -164
- souleyez/ui/tutorial.py +202 -72
- souleyez/ui/tutorial_state.py +40 -40
- souleyez/ui/wazuh_vulns_view.py +235 -141
- souleyez/ui/wordlist_browser.py +260 -107
- souleyez/ui.py +464 -312
- souleyez/utils/tool_checker.py +427 -367
- souleyez/utils.py +33 -29
- souleyez/wordlists.py +134 -167
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/METADATA +1 -1
- souleyez-2.43.34.dist-info/RECORD +443 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
- souleyez-2.43.29.dist-info/RECORD +0 -379
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
|
@@ -16,6 +16,7 @@ import re
|
|
|
16
16
|
@dataclass
|
|
17
17
|
class CorrelatedFinding:
|
|
18
18
|
"""Represents a group of related findings from different tools."""
|
|
19
|
+
|
|
19
20
|
cve_id: Optional[str] = None
|
|
20
21
|
service: str = ""
|
|
21
22
|
port: int = 0
|
|
@@ -29,8 +30,8 @@ class CorrelatedFinding:
|
|
|
29
30
|
|
|
30
31
|
def add_finding(self, finding: Dict[str, Any]):
|
|
31
32
|
"""Add a finding to this correlation group."""
|
|
32
|
-
finding_id = finding.get(
|
|
33
|
-
tool = finding.get(
|
|
33
|
+
finding_id = finding.get("id")
|
|
34
|
+
tool = finding.get("tool", "")
|
|
34
35
|
|
|
35
36
|
if finding_id and finding_id not in self.finding_ids:
|
|
36
37
|
self.finding_ids.append(finding_id)
|
|
@@ -39,9 +40,15 @@ class CorrelatedFinding:
|
|
|
39
40
|
self.tools.append(tool)
|
|
40
41
|
|
|
41
42
|
# Update severity to highest
|
|
42
|
-
severities = [
|
|
43
|
-
current_idx =
|
|
44
|
-
|
|
43
|
+
severities = ["critical", "high", "medium", "low", "info"]
|
|
44
|
+
current_idx = (
|
|
45
|
+
severities.index(self.severity) if self.severity in severities else 4
|
|
46
|
+
)
|
|
47
|
+
new_idx = (
|
|
48
|
+
severities.index(finding.get("severity", "info"))
|
|
49
|
+
if finding.get("severity") in severities
|
|
50
|
+
else 4
|
|
51
|
+
)
|
|
45
52
|
|
|
46
53
|
if new_idx < current_idx:
|
|
47
54
|
self.severity = severities[new_idx]
|
|
@@ -49,22 +56,23 @@ class CorrelatedFinding:
|
|
|
49
56
|
def to_dict(self) -> Dict[str, Any]:
|
|
50
57
|
"""Convert to dictionary."""
|
|
51
58
|
return {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
"cve_id": self.cve_id,
|
|
60
|
+
"service": self.service,
|
|
61
|
+
"port": self.port,
|
|
62
|
+
"host_ip": self.host_ip,
|
|
63
|
+
"severity": self.severity,
|
|
64
|
+
"finding_ids": self.finding_ids,
|
|
65
|
+
"tools": self.tools,
|
|
66
|
+
"confidence": self.confidence,
|
|
67
|
+
"description": self.description,
|
|
68
|
+
"exploit_available": self.exploit_available,
|
|
62
69
|
}
|
|
63
70
|
|
|
64
71
|
|
|
65
72
|
@dataclass
|
|
66
73
|
class AttackPath:
|
|
67
74
|
"""Represents a potential attack path using multiple findings."""
|
|
75
|
+
|
|
68
76
|
name: str
|
|
69
77
|
findings: List[Dict[str, Any]] = field(default_factory=list)
|
|
70
78
|
success_probability: float = 0.0
|
|
@@ -73,11 +81,11 @@ class AttackPath:
|
|
|
73
81
|
|
|
74
82
|
def to_dict(self) -> Dict[str, Any]:
|
|
75
83
|
return {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
"name": self.name,
|
|
85
|
+
"finding_ids": [f.get("id") for f in self.findings],
|
|
86
|
+
"success_probability": self.success_probability,
|
|
87
|
+
"impact": self.impact,
|
|
88
|
+
"steps": self.steps,
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
|
|
@@ -87,7 +95,9 @@ class VulnerabilityCorrelator:
|
|
|
87
95
|
def __init__(self):
|
|
88
96
|
"""Initialize correlator."""
|
|
89
97
|
|
|
90
|
-
def correlate_by_cve(
|
|
98
|
+
def correlate_by_cve(
|
|
99
|
+
self, findings: List[Dict[str, Any]]
|
|
100
|
+
) -> List[CorrelatedFinding]:
|
|
91
101
|
"""
|
|
92
102
|
Group findings by CVE ID.
|
|
93
103
|
|
|
@@ -97,14 +107,14 @@ class VulnerabilityCorrelator:
|
|
|
97
107
|
|
|
98
108
|
for finding in findings:
|
|
99
109
|
# Extract CVE from various fields
|
|
100
|
-
cve_id = finding.get(
|
|
110
|
+
cve_id = finding.get("cve_id")
|
|
101
111
|
if not cve_id:
|
|
102
112
|
# Try to extract from refs or description
|
|
103
|
-
refs = finding.get(
|
|
104
|
-
desc = finding.get(
|
|
113
|
+
refs = finding.get("refs", "")
|
|
114
|
+
desc = finding.get("description", "")
|
|
105
115
|
text = f"{refs} {desc}"
|
|
106
116
|
|
|
107
|
-
cve_matches = re.findall(r
|
|
117
|
+
cve_matches = re.findall(r"CVE-\d{4}-\d{4,7}", text, re.IGNORECASE)
|
|
108
118
|
if cve_matches:
|
|
109
119
|
cve_id = cve_matches[0].upper()
|
|
110
120
|
|
|
@@ -112,17 +122,19 @@ class VulnerabilityCorrelator:
|
|
|
112
122
|
if cve_id not in cve_groups:
|
|
113
123
|
cve_groups[cve_id] = CorrelatedFinding(
|
|
114
124
|
cve_id=cve_id,
|
|
115
|
-
service=finding.get(
|
|
116
|
-
port=finding.get(
|
|
125
|
+
service=finding.get("service", ""),
|
|
126
|
+
port=finding.get("port", 0),
|
|
117
127
|
host_ip=self._extract_host_ip(finding),
|
|
118
|
-
confidence=0.95 # High confidence for CVE matching
|
|
128
|
+
confidence=0.95, # High confidence for CVE matching
|
|
119
129
|
)
|
|
120
130
|
|
|
121
131
|
cve_groups[cve_id].add_finding(finding)
|
|
122
132
|
|
|
123
133
|
return list(cve_groups.values())
|
|
124
134
|
|
|
125
|
-
def correlate_by_service(
|
|
135
|
+
def correlate_by_service(
|
|
136
|
+
self, findings: List[Dict[str, Any]]
|
|
137
|
+
) -> List[CorrelatedFinding]:
|
|
126
138
|
"""
|
|
127
139
|
Group findings by service/port combination.
|
|
128
140
|
|
|
@@ -132,7 +144,7 @@ class VulnerabilityCorrelator:
|
|
|
132
144
|
|
|
133
145
|
for finding in findings:
|
|
134
146
|
host_ip = self._extract_host_ip(finding)
|
|
135
|
-
port = finding.get(
|
|
147
|
+
port = finding.get("port", 0)
|
|
136
148
|
|
|
137
149
|
# Skip findings without port/host
|
|
138
150
|
if not host_ip or not port:
|
|
@@ -145,7 +157,7 @@ class VulnerabilityCorrelator:
|
|
|
145
157
|
service=self._extract_service_name(finding),
|
|
146
158
|
port=port,
|
|
147
159
|
host_ip=host_ip,
|
|
148
|
-
confidence=0.7 # Medium-high confidence
|
|
160
|
+
confidence=0.7, # Medium-high confidence
|
|
149
161
|
)
|
|
150
162
|
|
|
151
163
|
service_groups[key].add_finding(finding)
|
|
@@ -153,24 +165,39 @@ class VulnerabilityCorrelator:
|
|
|
153
165
|
# Only return groups with multiple findings
|
|
154
166
|
return [g for g in service_groups.values() if len(g.finding_ids) > 1]
|
|
155
167
|
|
|
156
|
-
def correlate_by_vulnerability_type(
|
|
168
|
+
def correlate_by_vulnerability_type(
|
|
169
|
+
self, findings: List[Dict[str, Any]]
|
|
170
|
+
) -> List[CorrelatedFinding]:
|
|
157
171
|
"""
|
|
158
172
|
Group findings by vulnerability type (SQL injection, XSS, RCE, etc.).
|
|
159
173
|
"""
|
|
160
174
|
vuln_types = {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
175
|
+
"sqli": ["sql injection", "sqlmap", "blind sql"],
|
|
176
|
+
"xss": ["cross-site scripting", "xss", "reflected xss", "stored xss"],
|
|
177
|
+
"rce": [
|
|
178
|
+
"remote code execution",
|
|
179
|
+
"command injection",
|
|
180
|
+
"shell upload",
|
|
181
|
+
"arbitrary code",
|
|
182
|
+
],
|
|
183
|
+
"lfi": ["local file inclusion", "directory traversal", "path traversal"],
|
|
184
|
+
"auth_bypass": [
|
|
185
|
+
"authentication bypass",
|
|
186
|
+
"broken authentication",
|
|
187
|
+
"default credentials",
|
|
188
|
+
],
|
|
189
|
+
"info_disclosure": [
|
|
190
|
+
"information disclosure",
|
|
191
|
+
"sensitive data",
|
|
192
|
+
"directory listing",
|
|
193
|
+
],
|
|
167
194
|
}
|
|
168
195
|
|
|
169
196
|
type_groups = {}
|
|
170
197
|
|
|
171
198
|
for finding in findings:
|
|
172
|
-
title = finding.get(
|
|
173
|
-
desc = finding.get(
|
|
199
|
+
title = finding.get("title", "").lower()
|
|
200
|
+
desc = finding.get("description", "").lower()
|
|
174
201
|
text = f"{title} {desc}"
|
|
175
202
|
|
|
176
203
|
for vuln_type, keywords in vuln_types.items():
|
|
@@ -182,7 +209,7 @@ class VulnerabilityCorrelator:
|
|
|
182
209
|
type_groups[key] = CorrelatedFinding(
|
|
183
210
|
host_ip=host_ip,
|
|
184
211
|
description=f"Multiple {vuln_type.upper()} vulnerabilities",
|
|
185
|
-
confidence=0.6
|
|
212
|
+
confidence=0.6,
|
|
186
213
|
)
|
|
187
214
|
|
|
188
215
|
type_groups[key].add_finding(finding)
|
|
@@ -194,7 +221,7 @@ class VulnerabilityCorrelator:
|
|
|
194
221
|
self,
|
|
195
222
|
findings: List[Dict[str, Any]],
|
|
196
223
|
credentials: List[Dict[str, Any]] = None,
|
|
197
|
-
smb_shares: List[Dict[str, Any]] = None
|
|
224
|
+
smb_shares: List[Dict[str, Any]] = None,
|
|
198
225
|
) -> List[AttackPath]:
|
|
199
226
|
"""
|
|
200
227
|
Identify potential attack paths by chaining vulnerabilities and access.
|
|
@@ -221,7 +248,11 @@ class VulnerabilityCorrelator:
|
|
|
221
248
|
for host_ip, host_findings in by_host.items():
|
|
222
249
|
# Path 1: RCE + Valid Credentials
|
|
223
250
|
rce_findings = [f for f in host_findings if self._is_rce(f)]
|
|
224
|
-
host_creds = [
|
|
251
|
+
host_creds = [
|
|
252
|
+
c
|
|
253
|
+
for c in credentials
|
|
254
|
+
if c.get("ip_address") == host_ip and c.get("status") == "valid"
|
|
255
|
+
]
|
|
225
256
|
|
|
226
257
|
if rce_findings and host_creds:
|
|
227
258
|
path = AttackPath(
|
|
@@ -233,13 +264,15 @@ class VulnerabilityCorrelator:
|
|
|
233
264
|
f"1. Exploit {rce_findings[0].get('title')} for code execution",
|
|
234
265
|
f"2. Use valid credentials: {host_creds[0].get('username')} / {host_creds[0].get('password')}",
|
|
235
266
|
"3. Establish persistent access",
|
|
236
|
-
"4. Escalate privileges if needed"
|
|
237
|
-
]
|
|
267
|
+
"4. Escalate privileges if needed",
|
|
268
|
+
],
|
|
238
269
|
)
|
|
239
270
|
paths.append(path)
|
|
240
271
|
|
|
241
272
|
# Path 2: SQL Injection + Database
|
|
242
|
-
sqli_findings = [
|
|
273
|
+
sqli_findings = [
|
|
274
|
+
f for f in host_findings if "sql" in f.get("title", "").lower()
|
|
275
|
+
]
|
|
243
276
|
if sqli_findings:
|
|
244
277
|
path = AttackPath(
|
|
245
278
|
name=f"SQL Injection on {host_ip}",
|
|
@@ -250,13 +283,17 @@ class VulnerabilityCorrelator:
|
|
|
250
283
|
f"1. Exploit SQL injection: {sqli_findings[0].get('path', '')}",
|
|
251
284
|
"2. Enumerate database schema",
|
|
252
285
|
"3. Extract sensitive data (users, passwords, etc.)",
|
|
253
|
-
"4. Attempt to read files or execute commands (if possible)"
|
|
254
|
-
]
|
|
286
|
+
"4. Attempt to read files or execute commands (if possible)",
|
|
287
|
+
],
|
|
255
288
|
)
|
|
256
289
|
paths.append(path)
|
|
257
290
|
|
|
258
291
|
# Path 3: Writable SMB + Any Access
|
|
259
|
-
host_shares = [
|
|
292
|
+
host_shares = [
|
|
293
|
+
s
|
|
294
|
+
for s in smb_shares
|
|
295
|
+
if s.get("ip_address") == host_ip and s.get("writable")
|
|
296
|
+
]
|
|
260
297
|
if host_shares:
|
|
261
298
|
path = AttackPath(
|
|
262
299
|
name=f"Writable SMB Share on {host_ip}",
|
|
@@ -267,13 +304,18 @@ class VulnerabilityCorrelator:
|
|
|
267
304
|
f"1. Access writable share: \\\\{host_ip}\\{host_shares[0].get('share_name')}",
|
|
268
305
|
"2. Upload malicious files (exe, dll, script)",
|
|
269
306
|
"3. Wait for execution or trigger manually",
|
|
270
|
-
"4. Gain code execution on the system"
|
|
271
|
-
]
|
|
307
|
+
"4. Gain code execution on the system",
|
|
308
|
+
],
|
|
272
309
|
)
|
|
273
310
|
paths.append(path)
|
|
274
311
|
|
|
275
312
|
# Path 4: Authentication Bypass + Service Access
|
|
276
|
-
auth_bypass = [
|
|
313
|
+
auth_bypass = [
|
|
314
|
+
f
|
|
315
|
+
for f in host_findings
|
|
316
|
+
if "auth" in f.get("title", "").lower()
|
|
317
|
+
and "bypass" in f.get("title", "").lower()
|
|
318
|
+
]
|
|
277
319
|
if auth_bypass:
|
|
278
320
|
path = AttackPath(
|
|
279
321
|
name=f"Authentication Bypass on {host_ip}",
|
|
@@ -284,28 +326,31 @@ class VulnerabilityCorrelator:
|
|
|
284
326
|
f"1. Exploit authentication bypass: {auth_bypass[0].get('title')}",
|
|
285
327
|
"2. Gain unauthorized access to application",
|
|
286
328
|
"3. Enumerate accessible functions",
|
|
287
|
-
"4. Look for privilege escalation opportunities"
|
|
288
|
-
]
|
|
329
|
+
"4. Look for privilege escalation opportunities",
|
|
330
|
+
],
|
|
289
331
|
)
|
|
290
332
|
paths.append(path)
|
|
291
333
|
|
|
292
334
|
# Sort by impact and probability
|
|
293
|
-
impact_order = {
|
|
294
|
-
paths.sort(
|
|
335
|
+
impact_order = {"critical": 0, "high": 1, "medium": 2, "low": 3}
|
|
336
|
+
paths.sort(
|
|
337
|
+
key=lambda p: (impact_order.get(p.impact, 3), -p.success_probability)
|
|
338
|
+
)
|
|
295
339
|
|
|
296
340
|
return paths
|
|
297
341
|
|
|
298
342
|
def _extract_host_ip(self, finding: Dict[str, Any]) -> str:
|
|
299
343
|
"""Extract host IP from finding."""
|
|
300
344
|
# Direct field
|
|
301
|
-
if
|
|
302
|
-
return finding[
|
|
345
|
+
if "ip_address" in finding:
|
|
346
|
+
return finding["ip_address"]
|
|
303
347
|
|
|
304
348
|
# From target field
|
|
305
|
-
target = finding.get(
|
|
349
|
+
target = finding.get("target", "")
|
|
306
350
|
# Extract IP from URL or plain IP
|
|
307
351
|
import re
|
|
308
|
-
|
|
352
|
+
|
|
353
|
+
ip_match = re.search(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", target)
|
|
309
354
|
if ip_match:
|
|
310
355
|
return ip_match.group(0)
|
|
311
356
|
|
|
@@ -313,30 +358,30 @@ class VulnerabilityCorrelator:
|
|
|
313
358
|
|
|
314
359
|
def _extract_service_name(self, finding: Dict[str, Any]) -> str:
|
|
315
360
|
"""Extract service name from finding."""
|
|
316
|
-
if
|
|
317
|
-
return finding[
|
|
361
|
+
if "service" in finding:
|
|
362
|
+
return finding["service"]
|
|
318
363
|
|
|
319
364
|
# Try to infer from tool
|
|
320
|
-
tool = finding.get(
|
|
321
|
-
if tool ==
|
|
322
|
-
return
|
|
323
|
-
elif tool ==
|
|
324
|
-
return
|
|
325
|
-
elif tool ==
|
|
326
|
-
return
|
|
365
|
+
tool = finding.get("tool", "").lower()
|
|
366
|
+
if tool == "nuclei":
|
|
367
|
+
return "http"
|
|
368
|
+
elif tool == "smbmap":
|
|
369
|
+
return "smb"
|
|
370
|
+
elif tool == "sqlmap":
|
|
371
|
+
return "database"
|
|
327
372
|
|
|
328
|
-
return finding.get(
|
|
373
|
+
return finding.get("finding_type", "unknown")
|
|
329
374
|
|
|
330
375
|
def _is_rce(self, finding: Dict[str, Any]) -> bool:
|
|
331
376
|
"""Check if finding is related to RCE."""
|
|
332
377
|
text = f"{finding.get('title', '')} {finding.get('description', '')}".lower()
|
|
333
378
|
rce_keywords = [
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
379
|
+
"remote code execution",
|
|
380
|
+
"command injection",
|
|
381
|
+
"arbitrary code",
|
|
382
|
+
"shell upload",
|
|
383
|
+
"code exec",
|
|
384
|
+
"rce",
|
|
340
385
|
]
|
|
341
386
|
return any(kw in text for kw in rce_keywords)
|
|
342
387
|
|
|
@@ -344,7 +389,7 @@ class VulnerabilityCorrelator:
|
|
|
344
389
|
self,
|
|
345
390
|
findings: List[Dict[str, Any]],
|
|
346
391
|
credentials: List[Dict[str, Any]] = None,
|
|
347
|
-
smb_shares: List[Dict[str, Any]] = None
|
|
392
|
+
smb_shares: List[Dict[str, Any]] = None,
|
|
348
393
|
) -> Dict[str, Any]:
|
|
349
394
|
"""
|
|
350
395
|
Generate a comprehensive correlation report.
|
|
@@ -365,18 +410,20 @@ class VulnerabilityCorrelator:
|
|
|
365
410
|
attack_paths = self.find_attack_paths(findings, credentials, smb_shares)
|
|
366
411
|
|
|
367
412
|
return {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
413
|
+
"cve_correlations": [c.to_dict() for c in cve_corr],
|
|
414
|
+
"service_correlations": [c.to_dict() for c in service_corr],
|
|
415
|
+
"type_correlations": [c.to_dict() for c in type_corr],
|
|
416
|
+
"attack_paths": [p.to_dict() for p in attack_paths],
|
|
417
|
+
"summary": {
|
|
418
|
+
"total_findings": len(findings),
|
|
419
|
+
"cve_groups": len(cve_corr),
|
|
420
|
+
"service_groups": len(service_corr),
|
|
421
|
+
"type_groups": len(type_corr),
|
|
422
|
+
"attack_paths": len(attack_paths),
|
|
423
|
+
"high_confidence_correlations": len(
|
|
424
|
+
[c for c in cve_corr if c.confidence > 0.8]
|
|
425
|
+
),
|
|
426
|
+
},
|
|
380
427
|
}
|
|
381
428
|
|
|
382
429
|
|
souleyez/core/web_utils.py
CHANGED
|
@@ -38,11 +38,11 @@ def check_http_redirect(ip: str, port: int = 80, timeout: int = 3) -> Dict[str,
|
|
|
38
38
|
'final_url': 'https://example.com/', 'status_code': 200, 'error': None}
|
|
39
39
|
"""
|
|
40
40
|
result = {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
"redirects_to_https": False,
|
|
42
|
+
"final_scheme": "http",
|
|
43
|
+
"final_url": None,
|
|
44
|
+
"status_code": None,
|
|
45
|
+
"error": None,
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
url = f"http://{ip}:{port}/"
|
|
@@ -56,32 +56,32 @@ def check_http_redirect(ip: str, port: int = 80, timeout: int = 3) -> Dict[str,
|
|
|
56
56
|
timeout=timeout,
|
|
57
57
|
verify=False, # nosec B501 - pentesting tool needs to handle self-signed certs
|
|
58
58
|
allow_redirects=True,
|
|
59
|
-
headers={
|
|
59
|
+
headers={"User-Agent": "SoulEyez/1.0"},
|
|
60
60
|
)
|
|
61
61
|
|
|
62
62
|
# Get final URL after all redirects
|
|
63
63
|
final_url = response.url
|
|
64
|
-
result[
|
|
65
|
-
result[
|
|
64
|
+
result["final_url"] = final_url
|
|
65
|
+
result["status_code"] = response.status_code
|
|
66
66
|
|
|
67
67
|
# Parse final URL to get scheme
|
|
68
68
|
parsed = urlparse(final_url)
|
|
69
|
-
result[
|
|
69
|
+
result["final_scheme"] = parsed.scheme
|
|
70
70
|
|
|
71
71
|
# Check if we ended up on HTTPS
|
|
72
|
-
if parsed.scheme ==
|
|
73
|
-
result[
|
|
72
|
+
if parsed.scheme == "https":
|
|
73
|
+
result["redirects_to_https"] = True
|
|
74
74
|
|
|
75
75
|
except requests.exceptions.Timeout:
|
|
76
|
-
result[
|
|
76
|
+
result["error"] = f"Timeout after {timeout}s"
|
|
77
77
|
except requests.exceptions.SSLError as e:
|
|
78
|
-
result[
|
|
78
|
+
result["error"] = f"SSL error: {str(e)[:100]}"
|
|
79
79
|
except requests.exceptions.ConnectionError as e:
|
|
80
|
-
result[
|
|
80
|
+
result["error"] = f"Connection error: {str(e)[:100]}"
|
|
81
81
|
except requests.exceptions.RequestException as e:
|
|
82
|
-
result[
|
|
82
|
+
result["error"] = f"Request error: {str(e)[:100]}"
|
|
83
83
|
except Exception as e:
|
|
84
|
-
result[
|
|
84
|
+
result["error"] = f"Unexpected error: {str(e)[:100]}"
|
|
85
85
|
|
|
86
86
|
return result
|
|
87
87
|
|
|
@@ -101,11 +101,11 @@ def check_https_redirect(ip: str, port: int = 443, timeout: int = 3) -> Dict[str
|
|
|
101
101
|
Dictionary with redirect information (same format as check_http_redirect)
|
|
102
102
|
"""
|
|
103
103
|
result = {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
"redirects_to_http": False,
|
|
105
|
+
"final_scheme": "https",
|
|
106
|
+
"final_url": None,
|
|
107
|
+
"status_code": None,
|
|
108
|
+
"error": None,
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
url = f"https://{ip}:{port}/"
|
|
@@ -116,33 +116,34 @@ def check_https_redirect(ip: str, port: int = 443, timeout: int = 3) -> Dict[str
|
|
|
116
116
|
timeout=timeout,
|
|
117
117
|
verify=False, # nosec B501 - pentesting tool needs to handle self-signed certs
|
|
118
118
|
allow_redirects=True,
|
|
119
|
-
headers={
|
|
119
|
+
headers={"User-Agent": "SoulEyez/1.0"},
|
|
120
120
|
)
|
|
121
121
|
|
|
122
122
|
final_url = response.url
|
|
123
|
-
result[
|
|
124
|
-
result[
|
|
123
|
+
result["final_url"] = final_url
|
|
124
|
+
result["status_code"] = response.status_code
|
|
125
125
|
|
|
126
126
|
parsed = urlparse(final_url)
|
|
127
|
-
result[
|
|
127
|
+
result["final_scheme"] = parsed.scheme
|
|
128
128
|
|
|
129
|
-
if parsed.scheme ==
|
|
130
|
-
result[
|
|
129
|
+
if parsed.scheme == "http":
|
|
130
|
+
result["redirects_to_http"] = True
|
|
131
131
|
|
|
132
132
|
except requests.exceptions.Timeout:
|
|
133
|
-
result[
|
|
133
|
+
result["error"] = f"Timeout after {timeout}s"
|
|
134
134
|
except requests.exceptions.SSLError as e:
|
|
135
|
-
result[
|
|
135
|
+
result["error"] = f"SSL error: {str(e)[:100]}"
|
|
136
136
|
except requests.exceptions.ConnectionError as e:
|
|
137
|
-
result[
|
|
137
|
+
result["error"] = f"Connection error: {str(e)[:100]}"
|
|
138
138
|
except requests.exceptions.RequestException as e:
|
|
139
|
-
result[
|
|
139
|
+
result["error"] = f"Request error: {str(e)[:100]}"
|
|
140
140
|
except Exception as e:
|
|
141
|
-
result[
|
|
141
|
+
result["error"] = f"Unexpected error: {str(e)[:100]}"
|
|
142
142
|
|
|
143
143
|
return result
|
|
144
144
|
|
|
145
145
|
|
|
146
146
|
# Suppress SSL warnings for pentesting context
|
|
147
147
|
import urllib3
|
|
148
|
+
|
|
148
149
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|