souleyez 2.43.26__py3-none-any.whl → 2.43.34__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of souleyez might be problematic. Click here for more details.
- souleyez/__init__.py +1 -2
- souleyez/ai/__init__.py +21 -15
- souleyez/ai/action_mapper.py +249 -150
- souleyez/ai/chain_advisor.py +116 -100
- souleyez/ai/claude_provider.py +29 -28
- souleyez/ai/context_builder.py +80 -62
- souleyez/ai/executor.py +158 -117
- souleyez/ai/feedback_handler.py +136 -121
- souleyez/ai/llm_factory.py +27 -20
- souleyez/ai/llm_provider.py +4 -2
- souleyez/ai/ollama_provider.py +6 -9
- souleyez/ai/ollama_service.py +44 -37
- souleyez/ai/path_scorer.py +91 -76
- souleyez/ai/recommender.py +176 -144
- souleyez/ai/report_context.py +74 -73
- souleyez/ai/report_service.py +84 -66
- souleyez/ai/result_parser.py +222 -229
- souleyez/ai/safety.py +67 -44
- souleyez/auth/__init__.py +23 -22
- souleyez/auth/audit.py +36 -26
- souleyez/auth/engagement_access.py +65 -48
- souleyez/auth/permissions.py +14 -3
- souleyez/auth/session_manager.py +54 -37
- souleyez/auth/user_manager.py +109 -64
- souleyez/commands/audit.py +40 -43
- souleyez/commands/auth.py +35 -15
- souleyez/commands/deliverables.py +55 -50
- souleyez/commands/engagement.py +47 -28
- souleyez/commands/license.py +32 -23
- souleyez/commands/screenshots.py +36 -32
- souleyez/commands/user.py +82 -36
- souleyez/config.py +52 -44
- souleyez/core/credential_tester.py +87 -81
- souleyez/core/cve_mappings.py +179 -192
- souleyez/core/cve_matcher.py +162 -148
- souleyez/core/msf_auto_mapper.py +100 -83
- souleyez/core/msf_chain_engine.py +294 -256
- souleyez/core/msf_database.py +153 -70
- souleyez/core/msf_integration.py +679 -673
- souleyez/core/msf_rpc_client.py +40 -42
- souleyez/core/msf_rpc_manager.py +77 -79
- souleyez/core/msf_sync_manager.py +241 -181
- souleyez/core/network_utils.py +22 -15
- souleyez/core/parser_handler.py +34 -25
- souleyez/core/pending_chains.py +114 -63
- souleyez/core/templates.py +158 -107
- souleyez/core/tool_chaining.py +9526 -2879
- souleyez/core/version_utils.py +79 -94
- souleyez/core/vuln_correlation.py +136 -89
- souleyez/core/web_utils.py +33 -32
- souleyez/data/wordlists/ad_users.txt +378 -0
- souleyez/data/wordlists/api_endpoints_large.txt +769 -0
- souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
- souleyez/data/wordlists/lfi_payloads.txt +82 -0
- souleyez/data/wordlists/passwords_brute.txt +1548 -0
- souleyez/data/wordlists/passwords_crack.txt +2479 -0
- souleyez/data/wordlists/passwords_spray.txt +386 -0
- souleyez/data/wordlists/subdomains_large.txt +5057 -0
- souleyez/data/wordlists/usernames_common.txt +694 -0
- souleyez/data/wordlists/web_dirs_large.txt +4769 -0
- souleyez/detection/__init__.py +1 -1
- souleyez/detection/attack_signatures.py +12 -17
- souleyez/detection/mitre_mappings.py +61 -55
- souleyez/detection/validator.py +97 -86
- souleyez/devtools.py +23 -10
- souleyez/docs/README.md +4 -4
- souleyez/docs/api-reference/cli-commands.md +2 -2
- souleyez/docs/developer-guide/adding-new-tools.md +562 -0
- souleyez/docs/user-guide/auto-chaining.md +30 -8
- souleyez/docs/user-guide/getting-started.md +1 -1
- souleyez/docs/user-guide/installation.md +26 -3
- souleyez/docs/user-guide/metasploit-integration.md +2 -2
- souleyez/docs/user-guide/rbac.md +1 -1
- souleyez/docs/user-guide/scope-management.md +1 -1
- souleyez/docs/user-guide/siem-integration.md +1 -1
- souleyez/docs/user-guide/tools-reference.md +1 -8
- souleyez/docs/user-guide/worker-management.md +1 -1
- souleyez/engine/background.py +1239 -535
- souleyez/engine/base.py +4 -1
- souleyez/engine/job_status.py +17 -49
- souleyez/engine/log_sanitizer.py +103 -77
- souleyez/engine/manager.py +38 -7
- souleyez/engine/result_handler.py +2200 -1550
- souleyez/engine/worker_manager.py +50 -41
- souleyez/export/evidence_bundle.py +72 -62
- souleyez/feature_flags/features.py +16 -20
- souleyez/feature_flags.py +5 -9
- souleyez/handlers/__init__.py +11 -0
- souleyez/handlers/base.py +188 -0
- souleyez/handlers/bash_handler.py +277 -0
- souleyez/handlers/bloodhound_handler.py +243 -0
- souleyez/handlers/certipy_handler.py +311 -0
- souleyez/handlers/crackmapexec_handler.py +486 -0
- souleyez/handlers/dnsrecon_handler.py +344 -0
- souleyez/handlers/enum4linux_handler.py +400 -0
- souleyez/handlers/evil_winrm_handler.py +493 -0
- souleyez/handlers/ffuf_handler.py +815 -0
- souleyez/handlers/gobuster_handler.py +1114 -0
- souleyez/handlers/gpp_extract_handler.py +334 -0
- souleyez/handlers/hashcat_handler.py +444 -0
- souleyez/handlers/hydra_handler.py +563 -0
- souleyez/handlers/impacket_getuserspns_handler.py +343 -0
- souleyez/handlers/impacket_psexec_handler.py +222 -0
- souleyez/handlers/impacket_secretsdump_handler.py +426 -0
- souleyez/handlers/john_handler.py +286 -0
- souleyez/handlers/katana_handler.py +425 -0
- souleyez/handlers/kerbrute_handler.py +298 -0
- souleyez/handlers/ldapsearch_handler.py +636 -0
- souleyez/handlers/lfi_extract_handler.py +464 -0
- souleyez/handlers/msf_auxiliary_handler.py +408 -0
- souleyez/handlers/msf_exploit_handler.py +380 -0
- souleyez/handlers/nikto_handler.py +413 -0
- souleyez/handlers/nmap_handler.py +821 -0
- souleyez/handlers/nuclei_handler.py +359 -0
- souleyez/handlers/nxc_handler.py +371 -0
- souleyez/handlers/rdp_sec_check_handler.py +353 -0
- souleyez/handlers/registry.py +292 -0
- souleyez/handlers/responder_handler.py +232 -0
- souleyez/handlers/service_explorer_handler.py +434 -0
- souleyez/handlers/smbclient_handler.py +344 -0
- souleyez/handlers/smbmap_handler.py +510 -0
- souleyez/handlers/smbpasswd_handler.py +296 -0
- souleyez/handlers/sqlmap_handler.py +1116 -0
- souleyez/handlers/theharvester_handler.py +601 -0
- souleyez/handlers/web_login_test_handler.py +327 -0
- souleyez/handlers/whois_handler.py +277 -0
- souleyez/handlers/wpscan_handler.py +554 -0
- souleyez/history.py +32 -16
- souleyez/importers/msf_importer.py +106 -75
- souleyez/importers/smart_importer.py +208 -147
- souleyez/integrations/siem/__init__.py +10 -10
- souleyez/integrations/siem/base.py +17 -18
- souleyez/integrations/siem/elastic.py +108 -122
- souleyez/integrations/siem/factory.py +207 -80
- souleyez/integrations/siem/googlesecops.py +146 -154
- souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
- souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
- souleyez/integrations/siem/sentinel.py +107 -109
- souleyez/integrations/siem/splunk.py +246 -212
- souleyez/integrations/siem/wazuh.py +65 -71
- souleyez/integrations/wazuh/__init__.py +5 -5
- souleyez/integrations/wazuh/client.py +70 -93
- souleyez/integrations/wazuh/config.py +85 -57
- souleyez/integrations/wazuh/host_mapper.py +28 -36
- souleyez/integrations/wazuh/sync.py +78 -68
- souleyez/intelligence/__init__.py +4 -5
- souleyez/intelligence/correlation_analyzer.py +309 -295
- souleyez/intelligence/exploit_knowledge.py +661 -623
- souleyez/intelligence/exploit_suggestions.py +159 -139
- souleyez/intelligence/gap_analyzer.py +132 -97
- souleyez/intelligence/gap_detector.py +251 -214
- souleyez/intelligence/sensitive_tables.py +266 -129
- souleyez/intelligence/service_parser.py +137 -123
- souleyez/intelligence/surface_analyzer.py +407 -268
- souleyez/intelligence/target_parser.py +159 -162
- souleyez/licensing/__init__.py +6 -6
- souleyez/licensing/validator.py +17 -19
- souleyez/log_config.py +79 -54
- souleyez/main.py +1505 -687
- souleyez/migrations/fix_job_counter.py +16 -14
- souleyez/parsers/bloodhound_parser.py +41 -39
- souleyez/parsers/crackmapexec_parser.py +178 -111
- souleyez/parsers/dalfox_parser.py +72 -77
- souleyez/parsers/dnsrecon_parser.py +103 -91
- souleyez/parsers/enum4linux_parser.py +183 -153
- souleyez/parsers/ffuf_parser.py +29 -25
- souleyez/parsers/gobuster_parser.py +301 -41
- souleyez/parsers/hashcat_parser.py +324 -79
- souleyez/parsers/http_fingerprint_parser.py +350 -103
- souleyez/parsers/hydra_parser.py +131 -111
- souleyez/parsers/impacket_parser.py +231 -178
- souleyez/parsers/john_parser.py +98 -86
- souleyez/parsers/katana_parser.py +316 -0
- souleyez/parsers/msf_parser.py +943 -498
- souleyez/parsers/nikto_parser.py +346 -65
- souleyez/parsers/nmap_parser.py +262 -174
- souleyez/parsers/nuclei_parser.py +40 -44
- souleyez/parsers/responder_parser.py +26 -26
- souleyez/parsers/searchsploit_parser.py +74 -74
- souleyez/parsers/service_explorer_parser.py +279 -0
- souleyez/parsers/smbmap_parser.py +180 -124
- souleyez/parsers/sqlmap_parser.py +434 -308
- souleyez/parsers/theharvester_parser.py +75 -57
- souleyez/parsers/whois_parser.py +135 -94
- souleyez/parsers/wpscan_parser.py +278 -190
- souleyez/plugins/afp.py +44 -36
- souleyez/plugins/afp_brute.py +114 -46
- souleyez/plugins/ard.py +48 -37
- souleyez/plugins/bloodhound.py +95 -61
- souleyez/plugins/certipy.py +303 -0
- souleyez/plugins/crackmapexec.py +186 -85
- souleyez/plugins/dalfox.py +120 -59
- souleyez/plugins/dns_hijack.py +146 -41
- souleyez/plugins/dnsrecon.py +97 -61
- souleyez/plugins/enum4linux.py +91 -66
- souleyez/plugins/evil_winrm.py +291 -0
- souleyez/plugins/ffuf.py +166 -90
- souleyez/plugins/firmware_extract.py +133 -29
- souleyez/plugins/gobuster.py +387 -190
- souleyez/plugins/gpp_extract.py +393 -0
- souleyez/plugins/hashcat.py +100 -73
- souleyez/plugins/http_fingerprint.py +854 -267
- souleyez/plugins/hydra.py +566 -200
- souleyez/plugins/impacket_getnpusers.py +117 -69
- souleyez/plugins/impacket_psexec.py +84 -64
- souleyez/plugins/impacket_secretsdump.py +103 -69
- souleyez/plugins/impacket_smbclient.py +89 -75
- souleyez/plugins/john.py +86 -69
- souleyez/plugins/katana.py +313 -0
- souleyez/plugins/kerbrute.py +237 -0
- souleyez/plugins/lfi_extract.py +541 -0
- souleyez/plugins/macos_ssh.py +117 -48
- souleyez/plugins/mdns.py +35 -30
- souleyez/plugins/msf_auxiliary.py +253 -130
- souleyez/plugins/msf_exploit.py +239 -161
- souleyez/plugins/nikto.py +134 -78
- souleyez/plugins/nmap.py +275 -91
- souleyez/plugins/nuclei.py +180 -89
- souleyez/plugins/nxc.py +285 -0
- souleyez/plugins/plugin_base.py +35 -36
- souleyez/plugins/plugin_template.py +13 -5
- souleyez/plugins/rdp_sec_check.py +130 -0
- souleyez/plugins/responder.py +112 -71
- souleyez/plugins/router_http_brute.py +76 -65
- souleyez/plugins/router_ssh_brute.py +118 -41
- souleyez/plugins/router_telnet_brute.py +124 -42
- souleyez/plugins/routersploit.py +91 -59
- souleyez/plugins/routersploit_exploit.py +77 -55
- souleyez/plugins/searchsploit.py +91 -77
- souleyez/plugins/service_explorer.py +1160 -0
- souleyez/plugins/smbmap.py +122 -72
- souleyez/plugins/smbpasswd.py +215 -0
- souleyez/plugins/sqlmap.py +301 -113
- souleyez/plugins/theharvester.py +127 -75
- souleyez/plugins/tr069.py +79 -57
- souleyez/plugins/upnp.py +65 -47
- souleyez/plugins/upnp_abuse.py +73 -55
- souleyez/plugins/vnc_access.py +129 -42
- souleyez/plugins/vnc_brute.py +109 -38
- souleyez/plugins/web_login_test.py +417 -0
- souleyez/plugins/whois.py +77 -58
- souleyez/plugins/wpscan.py +173 -69
- souleyez/reporting/__init__.py +2 -1
- souleyez/reporting/attack_chain.py +411 -346
- souleyez/reporting/charts.py +436 -501
- souleyez/reporting/compliance_mappings.py +334 -201
- souleyez/reporting/detection_report.py +126 -125
- souleyez/reporting/formatters.py +828 -591
- souleyez/reporting/generator.py +386 -302
- souleyez/reporting/metrics.py +72 -75
- souleyez/scanner.py +35 -29
- souleyez/security/__init__.py +37 -11
- souleyez/security/scope_validator.py +175 -106
- souleyez/security/validation.py +223 -149
- souleyez/security.py +22 -6
- souleyez/storage/credentials.py +247 -186
- souleyez/storage/crypto.py +296 -129
- souleyez/storage/database.py +73 -50
- souleyez/storage/db.py +58 -36
- souleyez/storage/deliverable_evidence.py +177 -128
- souleyez/storage/deliverable_exporter.py +282 -246
- souleyez/storage/deliverable_templates.py +134 -116
- souleyez/storage/deliverables.py +135 -130
- souleyez/storage/engagements.py +109 -56
- souleyez/storage/evidence.py +181 -152
- souleyez/storage/execution_log.py +31 -17
- souleyez/storage/exploit_attempts.py +93 -57
- souleyez/storage/exploits.py +67 -36
- souleyez/storage/findings.py +48 -61
- souleyez/storage/hosts.py +176 -144
- souleyez/storage/migrate_to_engagements.py +43 -19
- souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
- souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
- souleyez/storage/migrations/_003_add_execution_log.py +14 -8
- souleyez/storage/migrations/_005_screenshots.py +13 -5
- souleyez/storage/migrations/_006_deliverables.py +13 -5
- souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
- souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
- souleyez/storage/migrations/_010_evidence_linking.py +17 -10
- souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
- souleyez/storage/migrations/_012_team_collaboration.py +34 -21
- souleyez/storage/migrations/_013_add_host_tags.py +12 -6
- souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
- souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
- souleyez/storage/migrations/_016_add_domain_field.py +10 -4
- souleyez/storage/migrations/_017_msf_sessions.py +16 -8
- souleyez/storage/migrations/_018_add_osint_target.py +10 -6
- souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
- souleyez/storage/migrations/_020_add_rbac.py +36 -15
- souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
- souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
- souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
- souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
- souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
- souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
- souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
- souleyez/storage/migrations/__init__.py +26 -26
- souleyez/storage/migrations/migration_manager.py +19 -19
- souleyez/storage/msf_sessions.py +100 -65
- souleyez/storage/osint.py +17 -24
- souleyez/storage/recommendation_engine.py +269 -235
- souleyez/storage/screenshots.py +33 -32
- souleyez/storage/smb_shares.py +136 -92
- souleyez/storage/sqlmap_data.py +183 -128
- souleyez/storage/team_collaboration.py +135 -141
- souleyez/storage/timeline_tracker.py +122 -94
- souleyez/storage/wazuh_vulns.py +64 -66
- souleyez/storage/web_paths.py +33 -37
- souleyez/testing/credential_tester.py +221 -205
- souleyez/ui/__init__.py +1 -1
- souleyez/ui/ai_quotes.py +12 -12
- souleyez/ui/attack_surface.py +2439 -1516
- souleyez/ui/chain_rules_view.py +914 -382
- souleyez/ui/correlation_view.py +312 -230
- souleyez/ui/dashboard.py +2382 -1130
- souleyez/ui/deliverables_view.py +148 -62
- souleyez/ui/design_system.py +13 -13
- souleyez/ui/errors.py +49 -49
- souleyez/ui/evidence_linking_view.py +284 -179
- souleyez/ui/evidence_vault.py +393 -285
- souleyez/ui/exploit_suggestions_view.py +555 -349
- souleyez/ui/export_view.py +100 -66
- souleyez/ui/gap_analysis_view.py +315 -171
- souleyez/ui/help_system.py +105 -97
- souleyez/ui/intelligence_view.py +436 -293
- souleyez/ui/interactive.py +23434 -10286
- souleyez/ui/interactive_selector.py +75 -68
- souleyez/ui/log_formatter.py +47 -39
- souleyez/ui/menu_components.py +22 -13
- souleyez/ui/msf_auxiliary_menu.py +184 -133
- souleyez/ui/pending_chains_view.py +336 -172
- souleyez/ui/progress_indicators.py +5 -3
- souleyez/ui/recommendations_view.py +195 -137
- souleyez/ui/rule_builder.py +343 -225
- souleyez/ui/setup_wizard.py +678 -284
- souleyez/ui/shortcuts.py +217 -165
- souleyez/ui/splunk_gap_analysis_view.py +452 -270
- souleyez/ui/splunk_vulns_view.py +139 -86
- souleyez/ui/team_dashboard.py +498 -335
- souleyez/ui/template_selector.py +196 -105
- souleyez/ui/terminal.py +6 -6
- souleyez/ui/timeline_view.py +198 -127
- souleyez/ui/tool_setup.py +264 -164
- souleyez/ui/tutorial.py +202 -72
- souleyez/ui/tutorial_state.py +40 -40
- souleyez/ui/wazuh_vulns_view.py +235 -141
- souleyez/ui/wordlist_browser.py +260 -107
- souleyez/ui.py +464 -312
- souleyez/utils/tool_checker.py +427 -367
- souleyez/utils.py +33 -29
- souleyez/wordlists.py +134 -167
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/METADATA +1 -1
- souleyez-2.43.34.dist-info/RECORD +443 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
- souleyez-2.43.26.dist-info/RECORD +0 -379
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
- {souleyez-2.43.26.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
|
@@ -33,16 +33,16 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
33
33
|
|
|
34
34
|
# Chronicle API regions
|
|
35
35
|
REGIONS = {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
"us": "https://backstory.googleapis.com",
|
|
37
|
+
"europe": "https://europe-backstory.googleapis.com",
|
|
38
|
+
"asia-southeast1": "https://asia-southeast1-backstory.googleapis.com",
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
def __init__(
|
|
42
42
|
self,
|
|
43
43
|
credentials_json: str,
|
|
44
44
|
customer_id: str,
|
|
45
|
-
region: str =
|
|
45
|
+
region: str = "us",
|
|
46
46
|
project_id: Optional[str] = None,
|
|
47
47
|
verify_ssl: bool = True,
|
|
48
48
|
):
|
|
@@ -70,13 +70,13 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
70
70
|
except json.JSONDecodeError as e:
|
|
71
71
|
raise ValueError(f"Invalid service account JSON: {e}")
|
|
72
72
|
|
|
73
|
-
self.project_id = project_id or self._credentials.get(
|
|
73
|
+
self.project_id = project_id or self._credentials.get("project_id", "")
|
|
74
74
|
|
|
75
75
|
# Set API base URL
|
|
76
|
-
self.api_base = self.REGIONS.get(self.region, self.REGIONS[
|
|
76
|
+
self.api_base = self.REGIONS.get(self.region, self.REGIONS["us"])
|
|
77
77
|
|
|
78
78
|
@classmethod
|
|
79
|
-
def from_config(cls, config: Dict[str, Any]) ->
|
|
79
|
+
def from_config(cls, config: Dict[str, Any]) -> "GoogleSecOpsSIEMClient":
|
|
80
80
|
"""Create client from configuration dictionary.
|
|
81
81
|
|
|
82
82
|
Args:
|
|
@@ -86,17 +86,17 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
86
86
|
GoogleSecOpsSIEMClient instance
|
|
87
87
|
"""
|
|
88
88
|
return cls(
|
|
89
|
-
credentials_json=config.get(
|
|
90
|
-
customer_id=config.get(
|
|
91
|
-
region=config.get(
|
|
92
|
-
project_id=config.get(
|
|
93
|
-
verify_ssl=config.get(
|
|
89
|
+
credentials_json=config.get("credentials_json", "{}"),
|
|
90
|
+
customer_id=config.get("customer_id", ""),
|
|
91
|
+
region=config.get("region", "us"),
|
|
92
|
+
project_id=config.get("project_id"),
|
|
93
|
+
verify_ssl=config.get("verify_ssl", True),
|
|
94
94
|
)
|
|
95
95
|
|
|
96
96
|
@property
|
|
97
97
|
def siem_type(self) -> str:
|
|
98
98
|
"""Return the SIEM type identifier."""
|
|
99
|
-
return
|
|
99
|
+
return "google_secops"
|
|
100
100
|
|
|
101
101
|
def _create_jwt(self) -> str:
|
|
102
102
|
"""Create a signed JWT for service account authentication.
|
|
@@ -113,45 +113,43 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
113
113
|
|
|
114
114
|
# JWT header
|
|
115
115
|
header = {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
"alg": "RS256",
|
|
117
|
+
"typ": "JWT",
|
|
118
|
+
"kid": self._credentials.get("private_key_id", ""),
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
# JWT claims
|
|
122
122
|
claims = {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
123
|
+
"iss": self._credentials.get("client_email", ""),
|
|
124
|
+
"sub": self._credentials.get("client_email", ""),
|
|
125
|
+
"aud": "https://oauth2.googleapis.com/token",
|
|
126
|
+
"iat": now,
|
|
127
|
+
"exp": expiry,
|
|
128
|
+
"scope": "https://www.googleapis.com/auth/chronicle-backstory",
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
# Encode header and claims
|
|
132
132
|
def b64_encode(data: dict) -> str:
|
|
133
|
-
return
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
return (
|
|
134
|
+
base64.urlsafe_b64encode(
|
|
135
|
+
json.dumps(data, separators=(",", ":")).encode()
|
|
136
|
+
)
|
|
137
|
+
.rstrip(b"=")
|
|
138
|
+
.decode()
|
|
139
|
+
)
|
|
136
140
|
|
|
137
141
|
header_b64 = b64_encode(header)
|
|
138
142
|
claims_b64 = b64_encode(claims)
|
|
139
143
|
message = f"{header_b64}.{claims_b64}".encode()
|
|
140
144
|
|
|
141
145
|
# Sign with private key
|
|
142
|
-
private_key_pem = self._credentials.get(
|
|
146
|
+
private_key_pem = self._credentials.get("private_key", "")
|
|
143
147
|
private_key = serialization.load_pem_private_key(
|
|
144
|
-
private_key_pem.encode(),
|
|
145
|
-
password=None,
|
|
146
|
-
backend=default_backend()
|
|
148
|
+
private_key_pem.encode(), password=None, backend=default_backend()
|
|
147
149
|
)
|
|
148
150
|
|
|
149
|
-
signature = private_key.sign(
|
|
150
|
-
|
|
151
|
-
padding.PKCS1v15(),
|
|
152
|
-
hashes.SHA256()
|
|
153
|
-
)
|
|
154
|
-
signature_b64 = base64.urlsafe_b64encode(signature).rstrip(b'=').decode()
|
|
151
|
+
signature = private_key.sign(message, padding.PKCS1v15(), hashes.SHA256())
|
|
152
|
+
signature_b64 = base64.urlsafe_b64encode(signature).rstrip(b"=").decode()
|
|
155
153
|
|
|
156
154
|
return f"{header_b64}.{claims_b64}.{signature_b64}"
|
|
157
155
|
|
|
@@ -171,19 +169,19 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
171
169
|
|
|
172
170
|
# Exchange JWT for access token
|
|
173
171
|
response = requests.post(
|
|
174
|
-
|
|
172
|
+
"https://oauth2.googleapis.com/token",
|
|
175
173
|
data={
|
|
176
|
-
|
|
177
|
-
|
|
174
|
+
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
175
|
+
"assertion": jwt,
|
|
178
176
|
},
|
|
179
177
|
timeout=30,
|
|
180
|
-
verify=self.verify_ssl
|
|
178
|
+
verify=self.verify_ssl,
|
|
181
179
|
)
|
|
182
180
|
response.raise_for_status()
|
|
183
181
|
|
|
184
182
|
token_data = response.json()
|
|
185
|
-
self._access_token = token_data[
|
|
186
|
-
expires_in = token_data.get(
|
|
183
|
+
self._access_token = token_data["access_token"]
|
|
184
|
+
expires_in = token_data.get("expires_in", 3600)
|
|
187
185
|
self._token_expiry = datetime.now() + timedelta(seconds=expires_in - 60)
|
|
188
186
|
|
|
189
187
|
return self._access_token
|
|
@@ -210,8 +208,8 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
210
208
|
url = f"{self.api_base}{endpoint}"
|
|
211
209
|
|
|
212
210
|
headers = {
|
|
213
|
-
|
|
214
|
-
|
|
211
|
+
"Authorization": f"Bearer {token}",
|
|
212
|
+
"Content-Type": "application/json",
|
|
215
213
|
}
|
|
216
214
|
|
|
217
215
|
response = requests.request(
|
|
@@ -221,7 +219,7 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
221
219
|
params=params,
|
|
222
220
|
json=json_data,
|
|
223
221
|
verify=self.verify_ssl,
|
|
224
|
-
timeout=60
|
|
222
|
+
timeout=60,
|
|
225
223
|
)
|
|
226
224
|
return response
|
|
227
225
|
|
|
@@ -237,52 +235,48 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
237
235
|
|
|
238
236
|
# Query for a small time window to verify API access
|
|
239
237
|
response = self._request(
|
|
240
|
-
|
|
241
|
-
'/v1alpha/detect/rules',
|
|
242
|
-
params={'page_size': 1}
|
|
238
|
+
"GET", "/v1alpha/detect/rules", params={"page_size": 1}
|
|
243
239
|
)
|
|
244
240
|
|
|
245
241
|
if response.status_code == 200:
|
|
246
242
|
return SIEMConnectionStatus(
|
|
247
243
|
connected=True,
|
|
248
|
-
version=
|
|
249
|
-
siem_type=
|
|
244
|
+
version="Chronicle API v1alpha",
|
|
245
|
+
siem_type="google_secops",
|
|
250
246
|
details={
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
247
|
+
"region": self.region,
|
|
248
|
+
"customer_id": self.customer_id,
|
|
249
|
+
"project_id": self.project_id,
|
|
250
|
+
},
|
|
255
251
|
)
|
|
256
252
|
elif response.status_code == 403:
|
|
257
253
|
return SIEMConnectionStatus(
|
|
258
254
|
connected=False,
|
|
259
|
-
error=
|
|
260
|
-
siem_type=
|
|
255
|
+
error="Permission denied. Check service account permissions.",
|
|
256
|
+
siem_type="google_secops",
|
|
261
257
|
)
|
|
262
258
|
else:
|
|
263
259
|
return SIEMConnectionStatus(
|
|
264
260
|
connected=False,
|
|
265
|
-
error=f
|
|
266
|
-
siem_type=
|
|
261
|
+
error=f"API error: {response.status_code} - {response.text[:200]}",
|
|
262
|
+
siem_type="google_secops",
|
|
267
263
|
)
|
|
268
264
|
|
|
269
265
|
except requests.exceptions.ConnectionError as e:
|
|
270
266
|
return SIEMConnectionStatus(
|
|
271
267
|
connected=False,
|
|
272
|
-
error=f
|
|
273
|
-
siem_type=
|
|
268
|
+
error=f"Connection failed: {str(e)}",
|
|
269
|
+
siem_type="google_secops",
|
|
274
270
|
)
|
|
275
271
|
except ValueError as e:
|
|
276
272
|
return SIEMConnectionStatus(
|
|
277
273
|
connected=False,
|
|
278
|
-
error=f
|
|
279
|
-
siem_type=
|
|
274
|
+
error=f"Configuration error: {str(e)}",
|
|
275
|
+
siem_type="google_secops",
|
|
280
276
|
)
|
|
281
277
|
except Exception as e:
|
|
282
278
|
return SIEMConnectionStatus(
|
|
283
|
-
connected=False,
|
|
284
|
-
error=str(e),
|
|
285
|
-
siem_type='google_secops'
|
|
279
|
+
connected=False, error=str(e), siem_type="google_secops"
|
|
286
280
|
)
|
|
287
281
|
|
|
288
282
|
def get_alerts(
|
|
@@ -293,7 +287,7 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
293
287
|
dest_ip: Optional[str] = None,
|
|
294
288
|
rule_ids: Optional[List[str]] = None,
|
|
295
289
|
search_text: Optional[str] = None,
|
|
296
|
-
limit: int = 100
|
|
290
|
+
limit: int = 100,
|
|
297
291
|
) -> List[SIEMAlert]:
|
|
298
292
|
"""Query detections/alerts from Google SecOps.
|
|
299
293
|
|
|
@@ -310,27 +304,23 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
310
304
|
List of normalized SIEMAlert objects
|
|
311
305
|
"""
|
|
312
306
|
# Format times for Chronicle API (RFC 3339)
|
|
313
|
-
start_str = start_time.strftime(
|
|
314
|
-
end_str = end_time.strftime(
|
|
307
|
+
start_str = start_time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
308
|
+
end_str = end_time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
315
309
|
|
|
316
310
|
# Query detections endpoint
|
|
317
311
|
params = {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
312
|
+
"start_time": start_str,
|
|
313
|
+
"end_time": end_str,
|
|
314
|
+
"page_size": min(limit, 1000),
|
|
321
315
|
}
|
|
322
316
|
|
|
323
|
-
response = self._request(
|
|
324
|
-
'GET',
|
|
325
|
-
'/v1alpha/detect/detections',
|
|
326
|
-
params=params
|
|
327
|
-
)
|
|
317
|
+
response = self._request("GET", "/v1alpha/detect/detections", params=params)
|
|
328
318
|
|
|
329
319
|
if response.status_code != 200:
|
|
330
320
|
return []
|
|
331
321
|
|
|
332
322
|
data = response.json()
|
|
333
|
-
detections = data.get(
|
|
323
|
+
detections = data.get("detections", [])
|
|
334
324
|
|
|
335
325
|
# Filter and normalize results
|
|
336
326
|
alerts = []
|
|
@@ -346,8 +336,10 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
346
336
|
continue
|
|
347
337
|
if search_text:
|
|
348
338
|
search_lower = search_text.lower()
|
|
349
|
-
if (
|
|
350
|
-
|
|
339
|
+
if (
|
|
340
|
+
search_lower not in alert.rule_name.lower()
|
|
341
|
+
and search_lower not in alert.description.lower()
|
|
342
|
+
):
|
|
351
343
|
continue
|
|
352
344
|
|
|
353
345
|
alerts.append(alert)
|
|
@@ -367,47 +359,51 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
367
359
|
Normalized SIEMAlert
|
|
368
360
|
"""
|
|
369
361
|
# Parse timestamp
|
|
370
|
-
timestamp_str = detection.get(
|
|
362
|
+
timestamp_str = detection.get("detectionTime", "")
|
|
371
363
|
try:
|
|
372
|
-
timestamp = datetime.fromisoformat(timestamp_str.replace(
|
|
364
|
+
timestamp = datetime.fromisoformat(timestamp_str.replace("Z", "+00:00"))
|
|
373
365
|
except (ValueError, AttributeError):
|
|
374
366
|
timestamp = datetime.now()
|
|
375
367
|
|
|
376
368
|
# Extract rule info
|
|
377
|
-
rule_info =
|
|
378
|
-
|
|
379
|
-
|
|
369
|
+
rule_info = (
|
|
370
|
+
detection.get("detection", [{}])[0] if detection.get("detection") else {}
|
|
371
|
+
)
|
|
372
|
+
rule_id = rule_info.get("ruleId", detection.get("ruleId", ""))
|
|
373
|
+
rule_name = rule_info.get("ruleName", detection.get("ruleName", rule_id))
|
|
380
374
|
|
|
381
375
|
# Map severity
|
|
382
|
-
severity_raw = detection.get(
|
|
376
|
+
severity_raw = detection.get(
|
|
377
|
+
"severity", rule_info.get("severity", "INFORMATIONAL")
|
|
378
|
+
)
|
|
383
379
|
severity = self._map_severity(severity_raw)
|
|
384
380
|
|
|
385
381
|
# Extract IPs from UDM events
|
|
386
382
|
source_ip = None
|
|
387
383
|
dest_ip = None
|
|
388
|
-
events = detection.get(
|
|
384
|
+
events = detection.get("collectionElements", [])
|
|
389
385
|
for element in events:
|
|
390
|
-
references = element.get(
|
|
386
|
+
references = element.get("references", [])
|
|
391
387
|
for ref in references:
|
|
392
|
-
event = ref.get(
|
|
393
|
-
principal = event.get(
|
|
394
|
-
target = event.get(
|
|
388
|
+
event = ref.get("event", {})
|
|
389
|
+
principal = event.get("principal", {})
|
|
390
|
+
target = event.get("target", {})
|
|
395
391
|
|
|
396
|
-
if not source_ip and principal.get(
|
|
397
|
-
ips = principal.get(
|
|
392
|
+
if not source_ip and principal.get("ip"):
|
|
393
|
+
ips = principal.get("ip", [])
|
|
398
394
|
source_ip = ips[0] if ips else None
|
|
399
395
|
|
|
400
|
-
if not dest_ip and target.get(
|
|
401
|
-
ips = target.get(
|
|
396
|
+
if not dest_ip and target.get("ip"):
|
|
397
|
+
ips = target.get("ip", [])
|
|
402
398
|
dest_ip = ips[0] if ips else None
|
|
403
399
|
|
|
404
400
|
# Extract description
|
|
405
|
-
description = detection.get(
|
|
401
|
+
description = detection.get("description", rule_info.get("ruleText", ""))
|
|
406
402
|
if not description:
|
|
407
403
|
description = f"Chronicle detection: {rule_name}"
|
|
408
404
|
|
|
409
405
|
return SIEMAlert(
|
|
410
|
-
id=detection.get(
|
|
406
|
+
id=detection.get("id", str(hash(str(detection)))[:12]),
|
|
411
407
|
timestamp=timestamp,
|
|
412
408
|
rule_id=str(rule_id),
|
|
413
409
|
rule_name=str(rule_name),
|
|
@@ -424,19 +420,17 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
424
420
|
"""Map Chronicle severity to normalized severity."""
|
|
425
421
|
severity_upper = str(severity).upper()
|
|
426
422
|
severity_map = {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
423
|
+
"CRITICAL": "critical",
|
|
424
|
+
"HIGH": "high",
|
|
425
|
+
"MEDIUM": "medium",
|
|
426
|
+
"LOW": "low",
|
|
427
|
+
"INFORMATIONAL": "info",
|
|
428
|
+
"INFO": "info",
|
|
433
429
|
}
|
|
434
|
-
return severity_map.get(severity_upper,
|
|
430
|
+
return severity_map.get(severity_upper, "info")
|
|
435
431
|
|
|
436
432
|
def get_rules(
|
|
437
|
-
self,
|
|
438
|
-
rule_ids: Optional[List[str]] = None,
|
|
439
|
-
enabled_only: bool = True
|
|
433
|
+
self, rule_ids: Optional[List[str]] = None, enabled_only: bool = True
|
|
440
434
|
) -> List[SIEMRule]:
|
|
441
435
|
"""Get YARA-L detection rules from Google SecOps.
|
|
442
436
|
|
|
@@ -448,38 +442,40 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
448
442
|
List of normalized SIEMRule objects
|
|
449
443
|
"""
|
|
450
444
|
response = self._request(
|
|
451
|
-
|
|
452
|
-
'/v1alpha/detect/rules',
|
|
453
|
-
params={'page_size': 1000}
|
|
445
|
+
"GET", "/v1alpha/detect/rules", params={"page_size": 1000}
|
|
454
446
|
)
|
|
455
447
|
|
|
456
448
|
if response.status_code != 200:
|
|
457
449
|
return []
|
|
458
450
|
|
|
459
451
|
data = response.json()
|
|
460
|
-
raw_rules = data.get(
|
|
452
|
+
raw_rules = data.get("rules", [])
|
|
461
453
|
|
|
462
454
|
rules = []
|
|
463
455
|
for raw_rule in raw_rules:
|
|
464
|
-
rule_id = raw_rule.get(
|
|
456
|
+
rule_id = raw_rule.get("ruleId", "")
|
|
465
457
|
|
|
466
458
|
# Filter by rule_ids if provided
|
|
467
459
|
if rule_ids and rule_id not in rule_ids:
|
|
468
460
|
continue
|
|
469
461
|
|
|
470
462
|
# Check if enabled
|
|
471
|
-
is_enabled = raw_rule.get(
|
|
463
|
+
is_enabled = raw_rule.get("liveRuleEnabled", True)
|
|
472
464
|
if enabled_only and not is_enabled:
|
|
473
465
|
continue
|
|
474
466
|
|
|
475
467
|
rule = SIEMRule(
|
|
476
468
|
id=rule_id,
|
|
477
|
-
name=raw_rule.get(
|
|
478
|
-
description=raw_rule.get(
|
|
479
|
-
severity=self._map_severity(
|
|
469
|
+
name=raw_rule.get("ruleName", rule_id),
|
|
470
|
+
description=raw_rule.get("metadata", {}).get("description", ""),
|
|
471
|
+
severity=self._map_severity(
|
|
472
|
+
raw_rule.get("metadata", {}).get("severity", "")
|
|
473
|
+
),
|
|
480
474
|
enabled=is_enabled,
|
|
481
|
-
mitre_tactics=raw_rule.get(
|
|
482
|
-
mitre_techniques=raw_rule.get(
|
|
475
|
+
mitre_tactics=raw_rule.get("metadata", {}).get("mitreTactics", []),
|
|
476
|
+
mitre_techniques=raw_rule.get("metadata", {}).get(
|
|
477
|
+
"mitreTechniques", []
|
|
478
|
+
),
|
|
483
479
|
raw_data=raw_rule,
|
|
484
480
|
)
|
|
485
481
|
rules.append(rule)
|
|
@@ -497,11 +493,11 @@ class GoogleSecOpsSIEMClient(SIEMClient):
|
|
|
497
493
|
"""
|
|
498
494
|
# Chronicle/Google SecOps rule recommendations
|
|
499
495
|
recommendations_map = {
|
|
500
|
-
|
|
496
|
+
"nmap": [
|
|
501
497
|
{
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
498
|
+
"rule_id": "network_port_scan",
|
|
499
|
+
"rule_name": "Network Port Scan Detection",
|
|
500
|
+
"yaral": """
|
|
505
501
|
rule network_port_scan {
|
|
506
502
|
meta:
|
|
507
503
|
description = "Detects potential port scanning activity"
|
|
@@ -513,14 +509,14 @@ rule network_port_scan {
|
|
|
513
509
|
$src_ip over 5m
|
|
514
510
|
condition:
|
|
515
511
|
#e > 100
|
|
516
|
-
}
|
|
512
|
+
}""",
|
|
517
513
|
},
|
|
518
514
|
],
|
|
519
|
-
|
|
515
|
+
"hydra": [
|
|
520
516
|
{
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
517
|
+
"rule_id": "brute_force_auth",
|
|
518
|
+
"rule_name": "Brute Force Authentication",
|
|
519
|
+
"yaral": """
|
|
524
520
|
rule brute_force_authentication {
|
|
525
521
|
meta:
|
|
526
522
|
description = "Detects brute force login attempts"
|
|
@@ -533,14 +529,14 @@ rule brute_force_authentication {
|
|
|
533
529
|
$src_ip over 5m
|
|
534
530
|
condition:
|
|
535
531
|
#e > 10
|
|
536
|
-
}
|
|
532
|
+
}""",
|
|
537
533
|
},
|
|
538
534
|
],
|
|
539
|
-
|
|
535
|
+
"sqlmap": [
|
|
540
536
|
{
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
537
|
+
"rule_id": "sql_injection",
|
|
538
|
+
"rule_name": "SQL Injection Attempt",
|
|
539
|
+
"yaral": """
|
|
544
540
|
rule sql_injection_attempt {
|
|
545
541
|
meta:
|
|
546
542
|
description = "Detects SQL injection patterns in requests"
|
|
@@ -550,7 +546,7 @@ rule sql_injection_attempt {
|
|
|
550
546
|
re.regex($e.target.url, `(?i)(union|select|insert|update|delete|drop).*`)
|
|
551
547
|
condition:
|
|
552
548
|
$e
|
|
553
|
-
}
|
|
549
|
+
}""",
|
|
554
550
|
},
|
|
555
551
|
],
|
|
556
552
|
}
|
|
@@ -560,23 +556,19 @@ rule sql_injection_attempt {
|
|
|
560
556
|
|
|
561
557
|
return [
|
|
562
558
|
{
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
559
|
+
"rule_id": r["rule_id"],
|
|
560
|
+
"rule_name": r["rule_name"],
|
|
561
|
+
"description": f"YARA-L rule for detecting {attack_type}",
|
|
562
|
+
"severity": "high",
|
|
563
|
+
"enabled": False, # These are recommendations, not deployed
|
|
564
|
+
"siem_type": "google_secops",
|
|
565
|
+
"yaral_rule": r.get("yaral", ""),
|
|
570
566
|
}
|
|
571
567
|
for r in recommendations
|
|
572
568
|
]
|
|
573
569
|
|
|
574
570
|
def search_udm_events(
|
|
575
|
-
self,
|
|
576
|
-
query: str,
|
|
577
|
-
start_time: datetime,
|
|
578
|
-
end_time: datetime,
|
|
579
|
-
limit: int = 100
|
|
571
|
+
self, query: str, start_time: datetime, end_time: datetime, limit: int = 100
|
|
580
572
|
) -> List[Dict[str, Any]]:
|
|
581
573
|
"""Search UDM events with a custom query.
|
|
582
574
|
|
|
@@ -591,24 +583,24 @@ rule sql_injection_attempt {
|
|
|
591
583
|
Returns:
|
|
592
584
|
List of UDM events
|
|
593
585
|
"""
|
|
594
|
-
start_str = start_time.strftime(
|
|
595
|
-
end_str = end_time.strftime(
|
|
586
|
+
start_str = start_time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
587
|
+
end_str = end_time.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
596
588
|
|
|
597
589
|
response = self._request(
|
|
598
|
-
|
|
599
|
-
|
|
590
|
+
"POST",
|
|
591
|
+
"/v1alpha/events:udmSearch",
|
|
600
592
|
json_data={
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
593
|
+
"query": query,
|
|
594
|
+
"time_range": {
|
|
595
|
+
"start_time": start_str,
|
|
596
|
+
"end_time": end_str,
|
|
605
597
|
},
|
|
606
|
-
|
|
607
|
-
}
|
|
598
|
+
"limit": limit,
|
|
599
|
+
},
|
|
608
600
|
)
|
|
609
601
|
|
|
610
602
|
if response.status_code != 200:
|
|
611
603
|
return []
|
|
612
604
|
|
|
613
605
|
data = response.json()
|
|
614
|
-
return data.get(
|
|
606
|
+
return data.get("events", {}).get("events", [])
|
|
@@ -202,11 +202,14 @@ def get_wazuh_rules_for_attack(attack_type: str) -> Dict[str, Any]:
|
|
|
202
202
|
Dict with rule_ids, rule_names, detection_guidance
|
|
203
203
|
"""
|
|
204
204
|
attack_lower = attack_type.lower()
|
|
205
|
-
return WAZUH_ATTACK_RULES.get(
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
205
|
+
return WAZUH_ATTACK_RULES.get(
|
|
206
|
+
attack_lower,
|
|
207
|
+
{
|
|
208
|
+
"rule_ids": [],
|
|
209
|
+
"rule_names": {},
|
|
210
|
+
"detection_guidance": "Review SIEM rule configuration for this attack category.",
|
|
211
|
+
},
|
|
212
|
+
)
|
|
210
213
|
|
|
211
214
|
|
|
212
215
|
def get_all_wazuh_rule_ids() -> List[int]:
|