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
|
@@ -18,6 +18,7 @@ logger = get_logger(__name__)
|
|
|
18
18
|
@dataclass
|
|
19
19
|
class VulnGap:
|
|
20
20
|
"""Represents a vulnerability gap between detection sources."""
|
|
21
|
+
|
|
21
22
|
cve_id: str
|
|
22
23
|
severity: str
|
|
23
24
|
host_ip: str
|
|
@@ -31,6 +32,7 @@ class VulnGap:
|
|
|
31
32
|
@dataclass
|
|
32
33
|
class GapAnalysisResult:
|
|
33
34
|
"""Result of gap analysis."""
|
|
35
|
+
|
|
34
36
|
wazuh_total: int = 0
|
|
35
37
|
scan_total: int = 0
|
|
36
38
|
wazuh_only: List[VulnGap] = field(default_factory=list)
|
|
@@ -71,24 +73,30 @@ class GapAnalyzer:
|
|
|
71
73
|
result.scan_total = len(scan_findings)
|
|
72
74
|
|
|
73
75
|
# Build lookup sets
|
|
74
|
-
wazuh_cve_hosts = {
|
|
75
|
-
|
|
76
|
+
wazuh_cve_hosts = {
|
|
77
|
+
(v["cve_id"], v["host_ip"]): v for v in wazuh_vulns if v.get("cve_id")
|
|
78
|
+
}
|
|
79
|
+
scan_cve_hosts = {
|
|
80
|
+
(f["cve_id"], f["host_ip"]): f for f in scan_findings if f.get("cve_id")
|
|
81
|
+
}
|
|
76
82
|
|
|
77
83
|
# Find confirmed (both sources)
|
|
78
84
|
for key, wazuh_v in wazuh_cve_hosts.items():
|
|
79
85
|
cve_id, host_ip = key
|
|
80
86
|
if key in scan_cve_hosts:
|
|
81
87
|
scan_f = scan_cve_hosts[key]
|
|
82
|
-
result.confirmed.append(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
result.confirmed.append(
|
|
89
|
+
VulnGap(
|
|
90
|
+
cve_id=cve_id,
|
|
91
|
+
severity=wazuh_v.get("severity", "Medium"),
|
|
92
|
+
host_ip=host_ip,
|
|
93
|
+
source="both",
|
|
94
|
+
wazuh_details=wazuh_v,
|
|
95
|
+
scan_details=scan_f,
|
|
96
|
+
recommendation="High confidence - confirmed by both sources",
|
|
97
|
+
confidence="high",
|
|
98
|
+
)
|
|
99
|
+
)
|
|
92
100
|
|
|
93
101
|
# Find Wazuh-only (scan missed)
|
|
94
102
|
for key, wazuh_v in wazuh_cve_hosts.items():
|
|
@@ -97,29 +105,33 @@ class GapAnalyzer:
|
|
|
97
105
|
# Check if any scan found this CVE on any host
|
|
98
106
|
cve_found_elsewhere = any(c == cve_id for c, _ in scan_cve_hosts.keys())
|
|
99
107
|
|
|
100
|
-
result.wazuh_only.append(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
result.wazuh_only.append(
|
|
109
|
+
VulnGap(
|
|
110
|
+
cve_id=cve_id,
|
|
111
|
+
severity=wazuh_v.get("severity", "Medium"),
|
|
112
|
+
host_ip=host_ip,
|
|
113
|
+
source="wazuh",
|
|
114
|
+
wazuh_details=wazuh_v,
|
|
115
|
+
recommendation=self._get_scan_recommendation(cve_id, wazuh_v),
|
|
116
|
+
confidence="medium" if cve_found_elsewhere else "high",
|
|
117
|
+
)
|
|
118
|
+
)
|
|
109
119
|
|
|
110
120
|
# Find scan-only (Wazuh missed)
|
|
111
121
|
for key, scan_f in scan_cve_hosts.items():
|
|
112
122
|
cve_id, host_ip = key
|
|
113
123
|
if key not in wazuh_cve_hosts:
|
|
114
|
-
result.scan_only.append(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
result.scan_only.append(
|
|
125
|
+
VulnGap(
|
|
126
|
+
cve_id=cve_id,
|
|
127
|
+
severity=scan_f.get("severity", "medium"),
|
|
128
|
+
host_ip=host_ip,
|
|
129
|
+
source="scan",
|
|
130
|
+
scan_details=scan_f,
|
|
131
|
+
recommendation="Wazuh agent may not have detection rule for this CVE",
|
|
132
|
+
confidence="medium",
|
|
133
|
+
)
|
|
134
|
+
)
|
|
123
135
|
|
|
124
136
|
# Calculate coverage percentage
|
|
125
137
|
if result.wazuh_total > 0:
|
|
@@ -136,12 +148,18 @@ class GapAnalyzer:
|
|
|
136
148
|
result = self.analyze()
|
|
137
149
|
return [
|
|
138
150
|
{
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
151
|
+
"cve_id": gap.cve_id,
|
|
152
|
+
"severity": gap.severity,
|
|
153
|
+
"host_ip": gap.host_ip,
|
|
154
|
+
"package_name": (
|
|
155
|
+
gap.wazuh_details.get("package_name") if gap.wazuh_details else None
|
|
156
|
+
),
|
|
157
|
+
"package_version": (
|
|
158
|
+
gap.wazuh_details.get("package_version")
|
|
159
|
+
if gap.wazuh_details
|
|
160
|
+
else None
|
|
161
|
+
),
|
|
162
|
+
"recommendation": gap.recommendation,
|
|
145
163
|
}
|
|
146
164
|
for gap in result.wazuh_only
|
|
147
165
|
]
|
|
@@ -158,11 +176,11 @@ class GapAnalyzer:
|
|
|
158
176
|
result = self.analyze()
|
|
159
177
|
return [
|
|
160
178
|
{
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
179
|
+
"cve_id": gap.cve_id,
|
|
180
|
+
"severity": gap.severity,
|
|
181
|
+
"host_ip": gap.host_ip,
|
|
182
|
+
"tool": gap.scan_details.get("tool") if gap.scan_details else None,
|
|
183
|
+
"recommendation": gap.recommendation,
|
|
166
184
|
}
|
|
167
185
|
for gap in result.scan_only
|
|
168
186
|
]
|
|
@@ -174,12 +192,14 @@ class GapAnalyzer:
|
|
|
174
192
|
result = self.analyze()
|
|
175
193
|
return [
|
|
176
194
|
{
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
195
|
+
"cve_id": gap.cve_id,
|
|
196
|
+
"severity": gap.severity,
|
|
197
|
+
"host_ip": gap.host_ip,
|
|
198
|
+
"package_name": (
|
|
199
|
+
gap.wazuh_details.get("package_name") if gap.wazuh_details else None
|
|
200
|
+
),
|
|
201
|
+
"scan_tool": gap.scan_details.get("tool") if gap.scan_details else None,
|
|
202
|
+
"confidence": "high",
|
|
183
203
|
}
|
|
184
204
|
for gap in result.confirmed
|
|
185
205
|
]
|
|
@@ -194,13 +214,13 @@ class GapAnalyzer:
|
|
|
194
214
|
result = self.analyze()
|
|
195
215
|
|
|
196
216
|
return {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
217
|
+
"wazuh_total": result.wazuh_total,
|
|
218
|
+
"scan_total": result.scan_total,
|
|
219
|
+
"wazuh_only_count": len(result.wazuh_only),
|
|
220
|
+
"scan_only_count": len(result.scan_only),
|
|
221
|
+
"confirmed_count": len(result.confirmed),
|
|
222
|
+
"coverage_pct": round(result.coverage_pct, 1),
|
|
223
|
+
"by_severity": self._get_severity_breakdown(result),
|
|
204
224
|
}
|
|
205
225
|
|
|
206
226
|
def get_actionable_gaps(self, limit: int = 20) -> List[Dict[str, Any]]:
|
|
@@ -212,22 +232,29 @@ class GapAnalyzer:
|
|
|
212
232
|
result = self.analyze()
|
|
213
233
|
|
|
214
234
|
# Sort by severity
|
|
215
|
-
severity_order = {
|
|
235
|
+
severity_order = {"Critical": 0, "High": 1, "Medium": 2, "Low": 3}
|
|
216
236
|
|
|
217
237
|
sorted_gaps = sorted(
|
|
218
|
-
result.wazuh_only,
|
|
219
|
-
key=lambda g: severity_order.get(g.severity, 4)
|
|
238
|
+
result.wazuh_only, key=lambda g: severity_order.get(g.severity, 4)
|
|
220
239
|
)
|
|
221
240
|
|
|
222
241
|
return [
|
|
223
242
|
{
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
243
|
+
"cve_id": gap.cve_id,
|
|
244
|
+
"severity": gap.severity,
|
|
245
|
+
"host_ip": gap.host_ip,
|
|
246
|
+
"package": (
|
|
247
|
+
gap.wazuh_details.get("package_name") if gap.wazuh_details else None
|
|
248
|
+
),
|
|
249
|
+
"version": (
|
|
250
|
+
gap.wazuh_details.get("package_version")
|
|
251
|
+
if gap.wazuh_details
|
|
252
|
+
else None
|
|
253
|
+
),
|
|
254
|
+
"recommendation": gap.recommendation,
|
|
255
|
+
"priority": (
|
|
256
|
+
"high" if gap.severity in ["Critical", "High"] else "medium"
|
|
257
|
+
),
|
|
231
258
|
}
|
|
232
259
|
for gap in sorted_gaps[:limit]
|
|
233
260
|
]
|
|
@@ -254,7 +281,7 @@ class GapAnalyzer:
|
|
|
254
281
|
vulns = []
|
|
255
282
|
for r in results:
|
|
256
283
|
vuln = dict(r)
|
|
257
|
-
vuln[
|
|
284
|
+
vuln["host_ip"] = r.get("mapped_host_ip") or r.get("host_ip")
|
|
258
285
|
vulns.append(vuln)
|
|
259
286
|
|
|
260
287
|
return vulns
|
|
@@ -278,14 +305,16 @@ class GapAnalyzer:
|
|
|
278
305
|
|
|
279
306
|
for r in nuclei_results:
|
|
280
307
|
# Extract IP from matched_at URL
|
|
281
|
-
host_ip = self._extract_ip(r.get(
|
|
308
|
+
host_ip = self._extract_ip(r.get("matched_at", ""))
|
|
282
309
|
if host_ip:
|
|
283
|
-
findings.append(
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
310
|
+
findings.append(
|
|
311
|
+
{
|
|
312
|
+
"cve_id": r["cve_id"],
|
|
313
|
+
"severity": r.get("severity", "medium"),
|
|
314
|
+
"host_ip": host_ip,
|
|
315
|
+
"tool": "nuclei",
|
|
316
|
+
}
|
|
317
|
+
)
|
|
289
318
|
|
|
290
319
|
# Get from findings table (check refs/title for CVE)
|
|
291
320
|
findings_query = """
|
|
@@ -303,14 +332,18 @@ class GapAnalyzer:
|
|
|
303
332
|
|
|
304
333
|
for r in findings_results:
|
|
305
334
|
# Extract CVE from title or refs
|
|
306
|
-
cve_id = self._extract_cve(r.get(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
335
|
+
cve_id = self._extract_cve(r.get("title", "")) or self._extract_cve(
|
|
336
|
+
r.get("refs", "")
|
|
337
|
+
)
|
|
338
|
+
if cve_id and r.get("host_ip"):
|
|
339
|
+
findings.append(
|
|
340
|
+
{
|
|
341
|
+
"cve_id": cve_id,
|
|
342
|
+
"severity": r.get("severity", "medium"),
|
|
343
|
+
"host_ip": r["host_ip"],
|
|
344
|
+
"tool": r.get("tool", "unknown"),
|
|
345
|
+
}
|
|
346
|
+
)
|
|
314
347
|
|
|
315
348
|
return findings
|
|
316
349
|
|
|
@@ -319,7 +352,7 @@ class GapAnalyzer:
|
|
|
319
352
|
if not text:
|
|
320
353
|
return None
|
|
321
354
|
|
|
322
|
-
match = re.search(r
|
|
355
|
+
match = re.search(r"CVE-\d{4}-\d{4,}", text, re.IGNORECASE)
|
|
323
356
|
if match:
|
|
324
357
|
return match.group(0).upper()
|
|
325
358
|
|
|
@@ -331,7 +364,7 @@ class GapAnalyzer:
|
|
|
331
364
|
return None
|
|
332
365
|
|
|
333
366
|
# Try to extract IP from URL like https://10.0.0.1:443/path
|
|
334
|
-
ip_pattern = r
|
|
367
|
+
ip_pattern = r"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
|
|
335
368
|
match = re.search(ip_pattern, url)
|
|
336
369
|
if match:
|
|
337
370
|
return match.group(1)
|
|
@@ -340,35 +373,37 @@ class GapAnalyzer:
|
|
|
340
373
|
|
|
341
374
|
def _get_scan_recommendation(self, cve_id: str, wazuh_details: Dict) -> str:
|
|
342
375
|
"""Generate scan recommendation for a Wazuh-only CVE."""
|
|
343
|
-
package = wazuh_details.get(
|
|
344
|
-
severity = wazuh_details.get(
|
|
376
|
+
package = wazuh_details.get("package_name", "unknown")
|
|
377
|
+
severity = wazuh_details.get("severity", "Medium")
|
|
345
378
|
|
|
346
|
-
if severity in [
|
|
379
|
+
if severity in ["Critical", "High"]:
|
|
347
380
|
return f"Run targeted nuclei scan: nuclei -t cves/{cve_id.lower()}.yaml"
|
|
348
381
|
|
|
349
382
|
return f"Verify {cve_id} in {package} - may not be network exploitable"
|
|
350
383
|
|
|
351
|
-
def _get_severity_breakdown(
|
|
384
|
+
def _get_severity_breakdown(
|
|
385
|
+
self, result: GapAnalysisResult
|
|
386
|
+
) -> Dict[str, Dict[str, int]]:
|
|
352
387
|
"""Get counts by severity for each category."""
|
|
353
388
|
breakdown = {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
389
|
+
"wazuh_only": {"Critical": 0, "High": 0, "Medium": 0, "Low": 0},
|
|
390
|
+
"scan_only": {"Critical": 0, "High": 0, "Medium": 0, "Low": 0},
|
|
391
|
+
"confirmed": {"Critical": 0, "High": 0, "Medium": 0, "Low": 0},
|
|
357
392
|
}
|
|
358
393
|
|
|
359
394
|
for gap in result.wazuh_only:
|
|
360
|
-
sev = gap.severity if gap.severity in breakdown[
|
|
361
|
-
breakdown[
|
|
395
|
+
sev = gap.severity if gap.severity in breakdown["wazuh_only"] else "Medium"
|
|
396
|
+
breakdown["wazuh_only"][sev] += 1
|
|
362
397
|
|
|
363
398
|
for gap in result.scan_only:
|
|
364
399
|
# Normalize severity (scan findings use lowercase)
|
|
365
|
-
sev = gap.severity.capitalize() if gap.severity else
|
|
366
|
-
if sev not in breakdown[
|
|
367
|
-
sev =
|
|
368
|
-
breakdown[
|
|
400
|
+
sev = gap.severity.capitalize() if gap.severity else "Medium"
|
|
401
|
+
if sev not in breakdown["scan_only"]:
|
|
402
|
+
sev = "Medium"
|
|
403
|
+
breakdown["scan_only"][sev] += 1
|
|
369
404
|
|
|
370
405
|
for gap in result.confirmed:
|
|
371
|
-
sev = gap.severity if gap.severity in breakdown[
|
|
372
|
-
breakdown[
|
|
406
|
+
sev = gap.severity if gap.severity in breakdown["confirmed"] else "Medium"
|
|
407
|
+
breakdown["confirmed"][sev] += 1
|
|
373
408
|
|
|
374
409
|
return breakdown
|