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
|
@@ -49,8 +49,8 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
49
49
|
verify_ssl: Verify SSL certificates
|
|
50
50
|
space: Kibana space (default: "default")
|
|
51
51
|
"""
|
|
52
|
-
self.elasticsearch_url = elasticsearch_url.rstrip(
|
|
53
|
-
self.kibana_url = (kibana_url or elasticsearch_url).rstrip(
|
|
52
|
+
self.elasticsearch_url = elasticsearch_url.rstrip("/")
|
|
53
|
+
self.kibana_url = (kibana_url or elasticsearch_url).rstrip("/")
|
|
54
54
|
self.api_key = api_key
|
|
55
55
|
self.username = username
|
|
56
56
|
self.password = password
|
|
@@ -58,7 +58,7 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
58
58
|
self.space = space
|
|
59
59
|
|
|
60
60
|
@classmethod
|
|
61
|
-
def from_config(cls, config: Dict[str, Any]) ->
|
|
61
|
+
def from_config(cls, config: Dict[str, Any]) -> "ElasticSIEMClient":
|
|
62
62
|
"""Create client from configuration dictionary.
|
|
63
63
|
|
|
64
64
|
Args:
|
|
@@ -68,19 +68,19 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
68
68
|
ElasticSIEMClient instance
|
|
69
69
|
"""
|
|
70
70
|
return cls(
|
|
71
|
-
elasticsearch_url=config.get(
|
|
72
|
-
kibana_url=config.get(
|
|
73
|
-
api_key=config.get(
|
|
74
|
-
username=config.get(
|
|
75
|
-
password=config.get(
|
|
76
|
-
verify_ssl=config.get(
|
|
77
|
-
space=config.get(
|
|
71
|
+
elasticsearch_url=config.get("elasticsearch_url", ""),
|
|
72
|
+
kibana_url=config.get("kibana_url"),
|
|
73
|
+
api_key=config.get("api_key"),
|
|
74
|
+
username=config.get("username"),
|
|
75
|
+
password=config.get("password"),
|
|
76
|
+
verify_ssl=config.get("verify_ssl", False),
|
|
77
|
+
space=config.get("space", "default"),
|
|
78
78
|
)
|
|
79
79
|
|
|
80
80
|
@property
|
|
81
81
|
def siem_type(self) -> str:
|
|
82
82
|
"""Return the SIEM type identifier."""
|
|
83
|
-
return
|
|
83
|
+
return "elastic"
|
|
84
84
|
|
|
85
85
|
def _get_auth(self):
|
|
86
86
|
"""Get authentication for requests."""
|
|
@@ -93,11 +93,11 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
93
93
|
def _get_headers(self) -> Dict[str, str]:
|
|
94
94
|
"""Get headers for requests."""
|
|
95
95
|
headers = {
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
"Content-Type": "application/json",
|
|
97
|
+
"kbn-xsrf": "true", # Required for Kibana API
|
|
98
98
|
}
|
|
99
99
|
if self.api_key:
|
|
100
|
-
headers[
|
|
100
|
+
headers["Authorization"] = f"ApiKey {self.api_key}"
|
|
101
101
|
return headers
|
|
102
102
|
|
|
103
103
|
def _es_request(
|
|
@@ -124,7 +124,7 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
124
124
|
auth=self._get_auth(),
|
|
125
125
|
json=json_data,
|
|
126
126
|
verify=self.verify_ssl,
|
|
127
|
-
timeout=60
|
|
127
|
+
timeout=60,
|
|
128
128
|
)
|
|
129
129
|
|
|
130
130
|
def _kibana_request(
|
|
@@ -144,7 +144,7 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
144
144
|
Response object
|
|
145
145
|
"""
|
|
146
146
|
# Handle space in URL
|
|
147
|
-
if self.space !=
|
|
147
|
+
if self.space != "default":
|
|
148
148
|
url = f"{self.kibana_url}/s/{self.space}{endpoint}"
|
|
149
149
|
else:
|
|
150
150
|
url = f"{self.kibana_url}{endpoint}"
|
|
@@ -156,7 +156,7 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
156
156
|
auth=self._get_auth(),
|
|
157
157
|
json=json_data,
|
|
158
158
|
verify=self.verify_ssl,
|
|
159
|
-
timeout=60
|
|
159
|
+
timeout=60,
|
|
160
160
|
)
|
|
161
161
|
|
|
162
162
|
def test_connection(self) -> SIEMConnectionStatus:
|
|
@@ -171,30 +171,28 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
171
171
|
response.raise_for_status()
|
|
172
172
|
data = response.json()
|
|
173
173
|
|
|
174
|
-
version = data.get(
|
|
175
|
-
cluster_name = data.get(
|
|
174
|
+
version = data.get("version", {}).get("number", "unknown")
|
|
175
|
+
cluster_name = data.get("cluster_name", "unknown")
|
|
176
176
|
|
|
177
177
|
return SIEMConnectionStatus(
|
|
178
178
|
connected=True,
|
|
179
179
|
version=version,
|
|
180
|
-
siem_type=
|
|
180
|
+
siem_type="elastic",
|
|
181
181
|
details={
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
182
|
+
"cluster_name": cluster_name,
|
|
183
|
+
"cluster_uuid": data.get("cluster_uuid", ""),
|
|
184
|
+
"tagline": data.get("tagline", ""),
|
|
185
|
+
},
|
|
186
186
|
)
|
|
187
187
|
except requests.exceptions.ConnectionError as e:
|
|
188
188
|
return SIEMConnectionStatus(
|
|
189
189
|
connected=False,
|
|
190
190
|
error=f"Connection failed: {str(e)}",
|
|
191
|
-
siem_type=
|
|
191
|
+
siem_type="elastic",
|
|
192
192
|
)
|
|
193
193
|
except Exception as e:
|
|
194
194
|
return SIEMConnectionStatus(
|
|
195
|
-
connected=False,
|
|
196
|
-
error=str(e),
|
|
197
|
-
siem_type='elastic'
|
|
195
|
+
connected=False, error=str(e), siem_type="elastic"
|
|
198
196
|
)
|
|
199
197
|
|
|
200
198
|
def get_alerts(
|
|
@@ -205,7 +203,7 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
205
203
|
dest_ip: Optional[str] = None,
|
|
206
204
|
rule_ids: Optional[List[str]] = None,
|
|
207
205
|
search_text: Optional[str] = None,
|
|
208
|
-
limit: int = 100
|
|
206
|
+
limit: int = 100,
|
|
209
207
|
) -> List[SIEMAlert]:
|
|
210
208
|
"""Query alerts from Elastic Security.
|
|
211
209
|
|
|
@@ -227,7 +225,7 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
227
225
|
"range": {
|
|
228
226
|
"@timestamp": {
|
|
229
227
|
"gte": start_time.isoformat(),
|
|
230
|
-
"lte": end_time.isoformat()
|
|
228
|
+
"lte": end_time.isoformat(),
|
|
231
229
|
}
|
|
232
230
|
}
|
|
233
231
|
}
|
|
@@ -235,49 +233,43 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
235
233
|
|
|
236
234
|
# IP filters
|
|
237
235
|
if source_ip:
|
|
238
|
-
must_clauses.append(
|
|
239
|
-
|
|
240
|
-
"
|
|
241
|
-
|
|
236
|
+
must_clauses.append(
|
|
237
|
+
{
|
|
238
|
+
"multi_match": {
|
|
239
|
+
"query": source_ip,
|
|
240
|
+
"fields": ["source.ip", "client.ip", "host.ip"],
|
|
241
|
+
}
|
|
242
242
|
}
|
|
243
|
-
|
|
243
|
+
)
|
|
244
244
|
if dest_ip:
|
|
245
|
-
must_clauses.append(
|
|
246
|
-
|
|
247
|
-
"
|
|
248
|
-
|
|
245
|
+
must_clauses.append(
|
|
246
|
+
{
|
|
247
|
+
"multi_match": {
|
|
248
|
+
"query": dest_ip,
|
|
249
|
+
"fields": ["destination.ip", "server.ip"],
|
|
250
|
+
}
|
|
249
251
|
}
|
|
250
|
-
|
|
252
|
+
)
|
|
251
253
|
|
|
252
254
|
# Rule ID filter
|
|
253
255
|
if rule_ids:
|
|
254
|
-
must_clauses.append({
|
|
255
|
-
"terms": {"signal.rule.id": rule_ids}
|
|
256
|
-
})
|
|
256
|
+
must_clauses.append({"terms": {"signal.rule.id": rule_ids}})
|
|
257
257
|
|
|
258
258
|
# Search text
|
|
259
259
|
if search_text:
|
|
260
|
-
must_clauses.append({
|
|
261
|
-
"query_string": {"query": f"*{search_text}*"}
|
|
262
|
-
})
|
|
260
|
+
must_clauses.append({"query_string": {"query": f"*{search_text}*"}})
|
|
263
261
|
|
|
264
262
|
query = {
|
|
265
263
|
"size": limit,
|
|
266
264
|
"sort": [{"@timestamp": {"order": "desc"}}],
|
|
267
|
-
"query": {
|
|
268
|
-
"bool": {
|
|
269
|
-
"must": must_clauses
|
|
270
|
-
}
|
|
271
|
-
}
|
|
265
|
+
"query": {"bool": {"must": must_clauses}},
|
|
272
266
|
}
|
|
273
267
|
|
|
274
268
|
# Query the signals index
|
|
275
269
|
index_pattern = f".siem-signals-{self.space}"
|
|
276
270
|
try:
|
|
277
271
|
response = self._es_request(
|
|
278
|
-
"POST",
|
|
279
|
-
f"/{index_pattern}/_search",
|
|
280
|
-
json_data=query
|
|
272
|
+
"POST", f"/{index_pattern}/_search", json_data=query
|
|
281
273
|
)
|
|
282
274
|
|
|
283
275
|
if response.status_code == 404:
|
|
@@ -286,7 +278,7 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
286
278
|
|
|
287
279
|
response.raise_for_status()
|
|
288
280
|
data = response.json()
|
|
289
|
-
hits = data.get(
|
|
281
|
+
hits = data.get("hits", {}).get("hits", [])
|
|
290
282
|
return [self._normalize_alert(hit) for hit in hits]
|
|
291
283
|
|
|
292
284
|
except requests.exceptions.HTTPError:
|
|
@@ -301,61 +293,57 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
301
293
|
Returns:
|
|
302
294
|
Normalized SIEMAlert
|
|
303
295
|
"""
|
|
304
|
-
source = hit.get(
|
|
305
|
-
signal = source.get(
|
|
306
|
-
rule = signal.get(
|
|
296
|
+
source = hit.get("_source", {})
|
|
297
|
+
signal = source.get("signal", {})
|
|
298
|
+
rule = signal.get("rule", {})
|
|
307
299
|
|
|
308
300
|
# Parse timestamp
|
|
309
|
-
timestamp_str = source.get(
|
|
301
|
+
timestamp_str = source.get("@timestamp", "")
|
|
310
302
|
try:
|
|
311
|
-
timestamp = datetime.fromisoformat(
|
|
312
|
-
timestamp_str.replace('Z', '+00:00')
|
|
313
|
-
)
|
|
303
|
+
timestamp = datetime.fromisoformat(timestamp_str.replace("Z", "+00:00"))
|
|
314
304
|
except (ValueError, AttributeError):
|
|
315
305
|
timestamp = datetime.now()
|
|
316
306
|
|
|
317
307
|
# Extract rule info
|
|
318
|
-
rule_id = rule.get(
|
|
319
|
-
rule_name = rule.get(
|
|
320
|
-
severity = rule.get(
|
|
308
|
+
rule_id = rule.get("id", "")
|
|
309
|
+
rule_name = rule.get("name", "")
|
|
310
|
+
severity = rule.get("severity", "low")
|
|
321
311
|
|
|
322
312
|
# Extract IPs
|
|
323
|
-
source_data = source.get(
|
|
324
|
-
dest_data = source.get(
|
|
325
|
-
source_ip = source_data.get(
|
|
326
|
-
dest_ip = dest_data.get(
|
|
313
|
+
source_data = source.get("source", {})
|
|
314
|
+
dest_data = source.get("destination", {})
|
|
315
|
+
source_ip = source_data.get("ip")
|
|
316
|
+
dest_ip = dest_data.get("ip")
|
|
327
317
|
|
|
328
318
|
# Extract MITRE info
|
|
329
|
-
threats = rule.get(
|
|
319
|
+
threats = rule.get("threat", [])
|
|
330
320
|
mitre_tactics = []
|
|
331
321
|
mitre_techniques = []
|
|
332
322
|
for threat in threats:
|
|
333
|
-
if threat.get(
|
|
334
|
-
tactic = threat.get(
|
|
335
|
-
if tactic.get(
|
|
336
|
-
mitre_tactics.append(tactic.get(
|
|
337
|
-
for technique in threat.get(
|
|
338
|
-
if technique.get(
|
|
339
|
-
mitre_techniques.append(technique.get(
|
|
323
|
+
if threat.get("framework") == "MITRE ATT&CK":
|
|
324
|
+
tactic = threat.get("tactic", {})
|
|
325
|
+
if tactic.get("name"):
|
|
326
|
+
mitre_tactics.append(tactic.get("name"))
|
|
327
|
+
for technique in threat.get("technique", []):
|
|
328
|
+
if technique.get("id"):
|
|
329
|
+
mitre_techniques.append(technique.get("id"))
|
|
340
330
|
|
|
341
331
|
return SIEMAlert(
|
|
342
|
-
id=hit.get(
|
|
332
|
+
id=hit.get("_id", ""),
|
|
343
333
|
timestamp=timestamp,
|
|
344
334
|
rule_id=rule_id,
|
|
345
335
|
rule_name=rule_name,
|
|
346
336
|
severity=severity,
|
|
347
337
|
source_ip=source_ip,
|
|
348
338
|
dest_ip=dest_ip,
|
|
349
|
-
description=rule.get(
|
|
339
|
+
description=rule.get("description", ""),
|
|
350
340
|
raw_data=source,
|
|
351
341
|
mitre_tactics=mitre_tactics,
|
|
352
342
|
mitre_techniques=mitre_techniques,
|
|
353
343
|
)
|
|
354
344
|
|
|
355
345
|
def get_rules(
|
|
356
|
-
self,
|
|
357
|
-
rule_ids: Optional[List[str]] = None,
|
|
358
|
-
enabled_only: bool = True
|
|
346
|
+
self, rule_ids: Optional[List[str]] = None, enabled_only: bool = True
|
|
359
347
|
) -> List[SIEMRule]:
|
|
360
348
|
"""Get detection rules from Elastic Security.
|
|
361
349
|
|
|
@@ -368,52 +356,50 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
368
356
|
"""
|
|
369
357
|
# Use Kibana Detection Engine API
|
|
370
358
|
params = {
|
|
371
|
-
|
|
372
|
-
|
|
359
|
+
"page": 1,
|
|
360
|
+
"per_page": 500,
|
|
373
361
|
}
|
|
374
362
|
|
|
375
363
|
try:
|
|
376
364
|
response = self._kibana_request(
|
|
377
|
-
"GET",
|
|
378
|
-
"/api/detection_engine/rules/_find",
|
|
379
|
-
json_data=params
|
|
365
|
+
"GET", "/api/detection_engine/rules/_find", json_data=params
|
|
380
366
|
)
|
|
381
367
|
|
|
382
368
|
if response.status_code != 200:
|
|
383
369
|
return []
|
|
384
370
|
|
|
385
371
|
data = response.json()
|
|
386
|
-
raw_rules = data.get(
|
|
372
|
+
raw_rules = data.get("data", [])
|
|
387
373
|
|
|
388
374
|
rules = []
|
|
389
375
|
for raw_rule in raw_rules:
|
|
390
376
|
# Filter by rule_ids if provided
|
|
391
|
-
if rule_ids and raw_rule.get(
|
|
377
|
+
if rule_ids and raw_rule.get("id") not in rule_ids:
|
|
392
378
|
continue
|
|
393
379
|
|
|
394
380
|
# Filter disabled if requested
|
|
395
|
-
if enabled_only and not raw_rule.get(
|
|
381
|
+
if enabled_only and not raw_rule.get("enabled", True):
|
|
396
382
|
continue
|
|
397
383
|
|
|
398
384
|
# Extract MITRE info
|
|
399
|
-
threats = raw_rule.get(
|
|
385
|
+
threats = raw_rule.get("threat", [])
|
|
400
386
|
mitre_tactics = []
|
|
401
387
|
mitre_techniques = []
|
|
402
388
|
for threat in threats:
|
|
403
|
-
if threat.get(
|
|
404
|
-
tactic = threat.get(
|
|
405
|
-
if tactic.get(
|
|
406
|
-
mitre_tactics.append(tactic.get(
|
|
407
|
-
for technique in threat.get(
|
|
408
|
-
if technique.get(
|
|
409
|
-
mitre_techniques.append(technique.get(
|
|
389
|
+
if threat.get("framework") == "MITRE ATT&CK":
|
|
390
|
+
tactic = threat.get("tactic", {})
|
|
391
|
+
if tactic.get("name"):
|
|
392
|
+
mitre_tactics.append(tactic.get("name"))
|
|
393
|
+
for technique in threat.get("technique", []):
|
|
394
|
+
if technique.get("id"):
|
|
395
|
+
mitre_techniques.append(technique.get("id"))
|
|
410
396
|
|
|
411
397
|
rule = SIEMRule(
|
|
412
|
-
id=raw_rule.get(
|
|
413
|
-
name=raw_rule.get(
|
|
414
|
-
description=raw_rule.get(
|
|
415
|
-
severity=raw_rule.get(
|
|
416
|
-
enabled=raw_rule.get(
|
|
398
|
+
id=raw_rule.get("id", ""),
|
|
399
|
+
name=raw_rule.get("name", ""),
|
|
400
|
+
description=raw_rule.get("description", ""),
|
|
401
|
+
severity=raw_rule.get("severity", "low"),
|
|
402
|
+
enabled=raw_rule.get("enabled", True),
|
|
417
403
|
mitre_tactics=mitre_tactics,
|
|
418
404
|
mitre_techniques=mitre_techniques,
|
|
419
405
|
raw_data=raw_rule,
|
|
@@ -436,25 +422,25 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
436
422
|
"""
|
|
437
423
|
# Elastic Security prebuilt rule recommendations
|
|
438
424
|
recommendations_map = {
|
|
439
|
-
|
|
425
|
+
"nmap": [
|
|
440
426
|
{
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
427
|
+
"rule_id": "port-scan-activity",
|
|
428
|
+
"rule_name": "Network Port Scan Activity",
|
|
429
|
+
"index": "filebeat-*,packetbeat-*",
|
|
444
430
|
},
|
|
445
431
|
],
|
|
446
|
-
|
|
432
|
+
"hydra": [
|
|
447
433
|
{
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
434
|
+
"rule_id": "brute-force-ssh",
|
|
435
|
+
"rule_name": "SSH Brute Force Attempt",
|
|
436
|
+
"index": "auditbeat-*,filebeat-*",
|
|
451
437
|
},
|
|
452
438
|
],
|
|
453
|
-
|
|
439
|
+
"sqlmap": [
|
|
454
440
|
{
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
441
|
+
"rule_id": "sql-injection-attack",
|
|
442
|
+
"rule_name": "SQL Injection Attempt",
|
|
443
|
+
"index": "filebeat-*",
|
|
458
444
|
},
|
|
459
445
|
],
|
|
460
446
|
}
|
|
@@ -464,13 +450,13 @@ class ElasticSIEMClient(SIEMClient):
|
|
|
464
450
|
|
|
465
451
|
return [
|
|
466
452
|
{
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
453
|
+
"rule_id": r["rule_id"],
|
|
454
|
+
"rule_name": r["rule_name"],
|
|
455
|
+
"description": f"Elastic detection rule for {attack_type}",
|
|
456
|
+
"severity": "high",
|
|
457
|
+
"enabled": True,
|
|
458
|
+
"siem_type": "elastic",
|
|
459
|
+
"index_pattern": r.get("index", ""),
|
|
474
460
|
}
|
|
475
461
|
for r in recommendations
|
|
476
462
|
]
|