souleyez 2.43.29__py3-none-any.whl → 3.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. souleyez/__init__.py +1 -2
  2. souleyez/ai/__init__.py +21 -15
  3. souleyez/ai/action_mapper.py +249 -150
  4. souleyez/ai/chain_advisor.py +116 -100
  5. souleyez/ai/claude_provider.py +29 -28
  6. souleyez/ai/context_builder.py +80 -62
  7. souleyez/ai/executor.py +158 -117
  8. souleyez/ai/feedback_handler.py +136 -121
  9. souleyez/ai/llm_factory.py +27 -20
  10. souleyez/ai/llm_provider.py +4 -2
  11. souleyez/ai/ollama_provider.py +6 -9
  12. souleyez/ai/ollama_service.py +44 -37
  13. souleyez/ai/path_scorer.py +91 -76
  14. souleyez/ai/recommender.py +176 -144
  15. souleyez/ai/report_context.py +74 -73
  16. souleyez/ai/report_service.py +84 -66
  17. souleyez/ai/result_parser.py +222 -229
  18. souleyez/ai/safety.py +67 -44
  19. souleyez/auth/__init__.py +23 -22
  20. souleyez/auth/audit.py +36 -26
  21. souleyez/auth/engagement_access.py +65 -48
  22. souleyez/auth/permissions.py +14 -3
  23. souleyez/auth/session_manager.py +54 -37
  24. souleyez/auth/user_manager.py +109 -64
  25. souleyez/commands/audit.py +40 -43
  26. souleyez/commands/auth.py +35 -15
  27. souleyez/commands/deliverables.py +55 -50
  28. souleyez/commands/engagement.py +47 -28
  29. souleyez/commands/license.py +32 -23
  30. souleyez/commands/screenshots.py +36 -32
  31. souleyez/commands/user.py +82 -36
  32. souleyez/config.py +52 -44
  33. souleyez/core/credential_tester.py +87 -81
  34. souleyez/core/cve_mappings.py +179 -192
  35. souleyez/core/cve_matcher.py +162 -148
  36. souleyez/core/msf_auto_mapper.py +100 -83
  37. souleyez/core/msf_chain_engine.py +294 -256
  38. souleyez/core/msf_database.py +153 -70
  39. souleyez/core/msf_integration.py +679 -673
  40. souleyez/core/msf_rpc_client.py +40 -42
  41. souleyez/core/msf_rpc_manager.py +77 -79
  42. souleyez/core/msf_sync_manager.py +241 -181
  43. souleyez/core/network_utils.py +22 -15
  44. souleyez/core/parser_handler.py +34 -25
  45. souleyez/core/pending_chains.py +114 -63
  46. souleyez/core/templates.py +158 -107
  47. souleyez/core/tool_chaining.py +9564 -2881
  48. souleyez/core/version_utils.py +79 -94
  49. souleyez/core/vuln_correlation.py +136 -89
  50. souleyez/core/web_utils.py +33 -32
  51. souleyez/data/wordlists/ad_users.txt +378 -0
  52. souleyez/data/wordlists/api_endpoints_large.txt +769 -0
  53. souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
  54. souleyez/data/wordlists/lfi_payloads.txt +82 -0
  55. souleyez/data/wordlists/passwords_brute.txt +1548 -0
  56. souleyez/data/wordlists/passwords_crack.txt +2479 -0
  57. souleyez/data/wordlists/passwords_spray.txt +386 -0
  58. souleyez/data/wordlists/subdomains_large.txt +5057 -0
  59. souleyez/data/wordlists/usernames_common.txt +694 -0
  60. souleyez/data/wordlists/web_dirs_large.txt +4769 -0
  61. souleyez/detection/__init__.py +1 -1
  62. souleyez/detection/attack_signatures.py +12 -17
  63. souleyez/detection/mitre_mappings.py +61 -55
  64. souleyez/detection/validator.py +97 -86
  65. souleyez/devtools.py +23 -10
  66. souleyez/docs/README.md +4 -4
  67. souleyez/docs/api-reference/cli-commands.md +2 -2
  68. souleyez/docs/developer-guide/adding-new-tools.md +562 -0
  69. souleyez/docs/user-guide/auto-chaining.md +30 -8
  70. souleyez/docs/user-guide/getting-started.md +1 -1
  71. souleyez/docs/user-guide/installation.md +26 -3
  72. souleyez/docs/user-guide/metasploit-integration.md +2 -2
  73. souleyez/docs/user-guide/rbac.md +1 -1
  74. souleyez/docs/user-guide/scope-management.md +1 -1
  75. souleyez/docs/user-guide/siem-integration.md +1 -1
  76. souleyez/docs/user-guide/tools-reference.md +1 -8
  77. souleyez/docs/user-guide/worker-management.md +1 -1
  78. souleyez/engine/background.py +1239 -535
  79. souleyez/engine/base.py +4 -1
  80. souleyez/engine/job_status.py +17 -49
  81. souleyez/engine/log_sanitizer.py +103 -77
  82. souleyez/engine/manager.py +38 -7
  83. souleyez/engine/result_handler.py +2200 -1550
  84. souleyez/engine/worker_manager.py +50 -41
  85. souleyez/export/evidence_bundle.py +72 -62
  86. souleyez/feature_flags/features.py +16 -20
  87. souleyez/feature_flags.py +5 -9
  88. souleyez/handlers/__init__.py +11 -0
  89. souleyez/handlers/base.py +188 -0
  90. souleyez/handlers/bash_handler.py +277 -0
  91. souleyez/handlers/bloodhound_handler.py +243 -0
  92. souleyez/handlers/certipy_handler.py +311 -0
  93. souleyez/handlers/crackmapexec_handler.py +486 -0
  94. souleyez/handlers/dnsrecon_handler.py +344 -0
  95. souleyez/handlers/enum4linux_handler.py +400 -0
  96. souleyez/handlers/evil_winrm_handler.py +493 -0
  97. souleyez/handlers/ffuf_handler.py +815 -0
  98. souleyez/handlers/gobuster_handler.py +1114 -0
  99. souleyez/handlers/gpp_extract_handler.py +334 -0
  100. souleyez/handlers/hashcat_handler.py +444 -0
  101. souleyez/handlers/hydra_handler.py +564 -0
  102. souleyez/handlers/impacket_getuserspns_handler.py +343 -0
  103. souleyez/handlers/impacket_psexec_handler.py +222 -0
  104. souleyez/handlers/impacket_secretsdump_handler.py +426 -0
  105. souleyez/handlers/john_handler.py +286 -0
  106. souleyez/handlers/katana_handler.py +425 -0
  107. souleyez/handlers/kerbrute_handler.py +298 -0
  108. souleyez/handlers/ldapsearch_handler.py +636 -0
  109. souleyez/handlers/lfi_extract_handler.py +464 -0
  110. souleyez/handlers/msf_auxiliary_handler.py +409 -0
  111. souleyez/handlers/msf_exploit_handler.py +380 -0
  112. souleyez/handlers/nikto_handler.py +413 -0
  113. souleyez/handlers/nmap_handler.py +821 -0
  114. souleyez/handlers/nuclei_handler.py +359 -0
  115. souleyez/handlers/nxc_handler.py +417 -0
  116. souleyez/handlers/rdp_sec_check_handler.py +353 -0
  117. souleyez/handlers/registry.py +292 -0
  118. souleyez/handlers/responder_handler.py +232 -0
  119. souleyez/handlers/service_explorer_handler.py +434 -0
  120. souleyez/handlers/smbclient_handler.py +344 -0
  121. souleyez/handlers/smbmap_handler.py +510 -0
  122. souleyez/handlers/smbpasswd_handler.py +296 -0
  123. souleyez/handlers/sqlmap_handler.py +1116 -0
  124. souleyez/handlers/theharvester_handler.py +601 -0
  125. souleyez/handlers/web_login_test_handler.py +327 -0
  126. souleyez/handlers/whois_handler.py +277 -0
  127. souleyez/handlers/wpscan_handler.py +554 -0
  128. souleyez/history.py +32 -16
  129. souleyez/importers/msf_importer.py +106 -75
  130. souleyez/importers/smart_importer.py +208 -147
  131. souleyez/integrations/siem/__init__.py +10 -10
  132. souleyez/integrations/siem/base.py +17 -18
  133. souleyez/integrations/siem/elastic.py +108 -122
  134. souleyez/integrations/siem/factory.py +207 -80
  135. souleyez/integrations/siem/googlesecops.py +146 -154
  136. souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
  137. souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
  138. souleyez/integrations/siem/sentinel.py +107 -109
  139. souleyez/integrations/siem/splunk.py +246 -212
  140. souleyez/integrations/siem/wazuh.py +65 -71
  141. souleyez/integrations/wazuh/__init__.py +5 -5
  142. souleyez/integrations/wazuh/client.py +70 -93
  143. souleyez/integrations/wazuh/config.py +85 -57
  144. souleyez/integrations/wazuh/host_mapper.py +28 -36
  145. souleyez/integrations/wazuh/sync.py +78 -68
  146. souleyez/intelligence/__init__.py +4 -5
  147. souleyez/intelligence/correlation_analyzer.py +309 -295
  148. souleyez/intelligence/exploit_knowledge.py +661 -623
  149. souleyez/intelligence/exploit_suggestions.py +159 -139
  150. souleyez/intelligence/gap_analyzer.py +132 -97
  151. souleyez/intelligence/gap_detector.py +251 -214
  152. souleyez/intelligence/sensitive_tables.py +266 -129
  153. souleyez/intelligence/service_parser.py +137 -123
  154. souleyez/intelligence/surface_analyzer.py +407 -268
  155. souleyez/intelligence/target_parser.py +159 -162
  156. souleyez/licensing/__init__.py +6 -6
  157. souleyez/licensing/validator.py +17 -19
  158. souleyez/log_config.py +79 -54
  159. souleyez/main.py +1505 -687
  160. souleyez/migrations/fix_job_counter.py +16 -14
  161. souleyez/parsers/bloodhound_parser.py +41 -39
  162. souleyez/parsers/crackmapexec_parser.py +178 -111
  163. souleyez/parsers/dalfox_parser.py +72 -77
  164. souleyez/parsers/dnsrecon_parser.py +103 -91
  165. souleyez/parsers/enum4linux_parser.py +183 -153
  166. souleyez/parsers/ffuf_parser.py +29 -25
  167. souleyez/parsers/gobuster_parser.py +301 -41
  168. souleyez/parsers/hashcat_parser.py +324 -79
  169. souleyez/parsers/http_fingerprint_parser.py +350 -103
  170. souleyez/parsers/hydra_parser.py +131 -111
  171. souleyez/parsers/impacket_parser.py +231 -178
  172. souleyez/parsers/john_parser.py +98 -86
  173. souleyez/parsers/katana_parser.py +316 -0
  174. souleyez/parsers/msf_parser.py +943 -498
  175. souleyez/parsers/nikto_parser.py +346 -65
  176. souleyez/parsers/nmap_parser.py +262 -174
  177. souleyez/parsers/nuclei_parser.py +40 -44
  178. souleyez/parsers/responder_parser.py +26 -26
  179. souleyez/parsers/searchsploit_parser.py +74 -74
  180. souleyez/parsers/service_explorer_parser.py +279 -0
  181. souleyez/parsers/smbmap_parser.py +180 -124
  182. souleyez/parsers/sqlmap_parser.py +434 -308
  183. souleyez/parsers/theharvester_parser.py +75 -57
  184. souleyez/parsers/whois_parser.py +135 -94
  185. souleyez/parsers/wpscan_parser.py +278 -190
  186. souleyez/plugins/afp.py +44 -36
  187. souleyez/plugins/afp_brute.py +114 -46
  188. souleyez/plugins/ard.py +48 -37
  189. souleyez/plugins/bloodhound.py +95 -61
  190. souleyez/plugins/certipy.py +303 -0
  191. souleyez/plugins/crackmapexec.py +186 -85
  192. souleyez/plugins/dalfox.py +120 -59
  193. souleyez/plugins/dns_hijack.py +146 -41
  194. souleyez/plugins/dnsrecon.py +97 -61
  195. souleyez/plugins/enum4linux.py +91 -66
  196. souleyez/plugins/evil_winrm.py +291 -0
  197. souleyez/plugins/ffuf.py +166 -90
  198. souleyez/plugins/firmware_extract.py +133 -29
  199. souleyez/plugins/gobuster.py +387 -190
  200. souleyez/plugins/gpp_extract.py +393 -0
  201. souleyez/plugins/hashcat.py +100 -73
  202. souleyez/plugins/http_fingerprint.py +913 -267
  203. souleyez/plugins/hydra.py +566 -200
  204. souleyez/plugins/impacket_getnpusers.py +117 -69
  205. souleyez/plugins/impacket_psexec.py +84 -64
  206. souleyez/plugins/impacket_secretsdump.py +103 -69
  207. souleyez/plugins/impacket_smbclient.py +89 -75
  208. souleyez/plugins/john.py +86 -69
  209. souleyez/plugins/katana.py +313 -0
  210. souleyez/plugins/kerbrute.py +237 -0
  211. souleyez/plugins/lfi_extract.py +541 -0
  212. souleyez/plugins/macos_ssh.py +117 -48
  213. souleyez/plugins/mdns.py +35 -30
  214. souleyez/plugins/msf_auxiliary.py +253 -130
  215. souleyez/plugins/msf_exploit.py +239 -161
  216. souleyez/plugins/nikto.py +134 -78
  217. souleyez/plugins/nmap.py +275 -91
  218. souleyez/plugins/nuclei.py +180 -89
  219. souleyez/plugins/nxc.py +285 -0
  220. souleyez/plugins/plugin_base.py +35 -36
  221. souleyez/plugins/plugin_template.py +13 -5
  222. souleyez/plugins/rdp_sec_check.py +130 -0
  223. souleyez/plugins/responder.py +112 -71
  224. souleyez/plugins/router_http_brute.py +76 -65
  225. souleyez/plugins/router_ssh_brute.py +118 -41
  226. souleyez/plugins/router_telnet_brute.py +124 -42
  227. souleyez/plugins/routersploit.py +91 -59
  228. souleyez/plugins/routersploit_exploit.py +77 -55
  229. souleyez/plugins/searchsploit.py +91 -77
  230. souleyez/plugins/service_explorer.py +1160 -0
  231. souleyez/plugins/smbmap.py +122 -72
  232. souleyez/plugins/smbpasswd.py +215 -0
  233. souleyez/plugins/sqlmap.py +301 -113
  234. souleyez/plugins/theharvester.py +127 -75
  235. souleyez/plugins/tr069.py +79 -57
  236. souleyez/plugins/upnp.py +65 -47
  237. souleyez/plugins/upnp_abuse.py +73 -55
  238. souleyez/plugins/vnc_access.py +129 -42
  239. souleyez/plugins/vnc_brute.py +109 -38
  240. souleyez/plugins/web_login_test.py +417 -0
  241. souleyez/plugins/whois.py +77 -58
  242. souleyez/plugins/wpscan.py +219 -69
  243. souleyez/reporting/__init__.py +2 -1
  244. souleyez/reporting/attack_chain.py +411 -346
  245. souleyez/reporting/charts.py +436 -501
  246. souleyez/reporting/compliance_mappings.py +334 -201
  247. souleyez/reporting/detection_report.py +126 -125
  248. souleyez/reporting/formatters.py +828 -591
  249. souleyez/reporting/generator.py +386 -302
  250. souleyez/reporting/metrics.py +72 -75
  251. souleyez/scanner.py +35 -29
  252. souleyez/security/__init__.py +37 -11
  253. souleyez/security/scope_validator.py +175 -106
  254. souleyez/security/validation.py +237 -149
  255. souleyez/security.py +22 -6
  256. souleyez/storage/credentials.py +247 -186
  257. souleyez/storage/crypto.py +296 -129
  258. souleyez/storage/database.py +73 -50
  259. souleyez/storage/db.py +58 -36
  260. souleyez/storage/deliverable_evidence.py +177 -128
  261. souleyez/storage/deliverable_exporter.py +282 -246
  262. souleyez/storage/deliverable_templates.py +134 -116
  263. souleyez/storage/deliverables.py +135 -130
  264. souleyez/storage/engagements.py +109 -56
  265. souleyez/storage/evidence.py +181 -152
  266. souleyez/storage/execution_log.py +31 -17
  267. souleyez/storage/exploit_attempts.py +93 -57
  268. souleyez/storage/exploits.py +67 -36
  269. souleyez/storage/findings.py +48 -61
  270. souleyez/storage/hosts.py +176 -144
  271. souleyez/storage/migrate_to_engagements.py +43 -19
  272. souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
  273. souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
  274. souleyez/storage/migrations/_003_add_execution_log.py +14 -8
  275. souleyez/storage/migrations/_005_screenshots.py +13 -5
  276. souleyez/storage/migrations/_006_deliverables.py +13 -5
  277. souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
  278. souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
  279. souleyez/storage/migrations/_010_evidence_linking.py +17 -10
  280. souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
  281. souleyez/storage/migrations/_012_team_collaboration.py +34 -21
  282. souleyez/storage/migrations/_013_add_host_tags.py +12 -6
  283. souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
  284. souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
  285. souleyez/storage/migrations/_016_add_domain_field.py +10 -4
  286. souleyez/storage/migrations/_017_msf_sessions.py +16 -8
  287. souleyez/storage/migrations/_018_add_osint_target.py +10 -6
  288. souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
  289. souleyez/storage/migrations/_020_add_rbac.py +36 -15
  290. souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
  291. souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
  292. souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
  293. souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
  294. souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
  295. souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
  296. souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
  297. souleyez/storage/migrations/__init__.py +26 -26
  298. souleyez/storage/migrations/migration_manager.py +19 -19
  299. souleyez/storage/msf_sessions.py +100 -65
  300. souleyez/storage/osint.py +17 -24
  301. souleyez/storage/recommendation_engine.py +269 -235
  302. souleyez/storage/screenshots.py +33 -32
  303. souleyez/storage/smb_shares.py +136 -92
  304. souleyez/storage/sqlmap_data.py +183 -128
  305. souleyez/storage/team_collaboration.py +135 -141
  306. souleyez/storage/timeline_tracker.py +122 -94
  307. souleyez/storage/wazuh_vulns.py +64 -66
  308. souleyez/storage/web_paths.py +33 -37
  309. souleyez/testing/credential_tester.py +221 -205
  310. souleyez/ui/__init__.py +1 -1
  311. souleyez/ui/ai_quotes.py +12 -12
  312. souleyez/ui/attack_surface.py +2439 -1516
  313. souleyez/ui/chain_rules_view.py +914 -382
  314. souleyez/ui/correlation_view.py +312 -230
  315. souleyez/ui/dashboard.py +2382 -1130
  316. souleyez/ui/deliverables_view.py +148 -62
  317. souleyez/ui/design_system.py +13 -13
  318. souleyez/ui/errors.py +49 -49
  319. souleyez/ui/evidence_linking_view.py +284 -179
  320. souleyez/ui/evidence_vault.py +393 -285
  321. souleyez/ui/exploit_suggestions_view.py +555 -349
  322. souleyez/ui/export_view.py +100 -66
  323. souleyez/ui/gap_analysis_view.py +315 -171
  324. souleyez/ui/help_system.py +105 -97
  325. souleyez/ui/intelligence_view.py +436 -293
  326. souleyez/ui/interactive.py +23034 -10679
  327. souleyez/ui/interactive_selector.py +75 -68
  328. souleyez/ui/log_formatter.py +47 -39
  329. souleyez/ui/menu_components.py +22 -13
  330. souleyez/ui/msf_auxiliary_menu.py +184 -133
  331. souleyez/ui/pending_chains_view.py +336 -172
  332. souleyez/ui/progress_indicators.py +5 -3
  333. souleyez/ui/recommendations_view.py +195 -137
  334. souleyez/ui/rule_builder.py +343 -225
  335. souleyez/ui/setup_wizard.py +678 -284
  336. souleyez/ui/shortcuts.py +217 -165
  337. souleyez/ui/splunk_gap_analysis_view.py +452 -270
  338. souleyez/ui/splunk_vulns_view.py +139 -86
  339. souleyez/ui/team_dashboard.py +498 -335
  340. souleyez/ui/template_selector.py +196 -105
  341. souleyez/ui/terminal.py +6 -6
  342. souleyez/ui/timeline_view.py +198 -127
  343. souleyez/ui/tool_setup.py +264 -164
  344. souleyez/ui/tutorial.py +202 -72
  345. souleyez/ui/tutorial_state.py +40 -40
  346. souleyez/ui/wazuh_vulns_view.py +235 -141
  347. souleyez/ui/wordlist_browser.py +260 -107
  348. souleyez/ui.py +464 -312
  349. souleyez/utils/tool_checker.py +427 -367
  350. souleyez/utils.py +33 -29
  351. souleyez/wordlists.py +134 -167
  352. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/METADATA +2 -2
  353. souleyez-3.0.0.dist-info/RECORD +443 -0
  354. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/WHEEL +1 -1
  355. souleyez-2.43.29.dist-info/RECORD +0 -379
  356. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/entry_points.txt +0 -0
  357. {souleyez-2.43.29.dist-info → souleyez-3.0.0.dist-info}/licenses/LICENSE +0 -0
  358. {souleyez-2.43.29.dist-info → souleyez-3.0.0.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
- 'us': 'https://backstory.googleapis.com',
37
- 'europe': 'https://europe-backstory.googleapis.com',
38
- 'asia-southeast1': 'https://asia-southeast1-backstory.googleapis.com',
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 = 'us',
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('project_id', '')
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['us'])
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]) -> 'GoogleSecOpsSIEMClient':
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('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),
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 'google_secops'
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
- 'alg': 'RS256',
117
- 'typ': 'JWT',
118
- 'kid': self._credentials.get('private_key_id', '')
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
- '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'
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 base64.urlsafe_b64encode(
134
- json.dumps(data, separators=(',', ':')).encode()
135
- ).rstrip(b'=').decode()
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('private_key', '')
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
- message,
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
- 'https://oauth2.googleapis.com/token',
172
+ "https://oauth2.googleapis.com/token",
175
173
  data={
176
- 'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
177
- 'assertion': jwt,
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['access_token']
186
- expires_in = token_data.get('expires_in', 3600)
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
- 'Authorization': f'Bearer {token}',
214
- 'Content-Type': 'application/json',
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
- 'GET',
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='Chronicle API v1alpha',
249
- siem_type='google_secops',
244
+ version="Chronicle API v1alpha",
245
+ siem_type="google_secops",
250
246
  details={
251
- 'region': self.region,
252
- 'customer_id': self.customer_id,
253
- 'project_id': self.project_id,
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='Permission denied. Check service account permissions.',
260
- siem_type='google_secops'
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'API error: {response.status_code} - {response.text[:200]}',
266
- siem_type='google_secops'
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'Connection failed: {str(e)}',
273
- siem_type='google_secops'
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'Configuration error: {str(e)}',
279
- siem_type='google_secops'
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('%Y-%m-%dT%H:%M:%SZ')
314
- end_str = end_time.strftime('%Y-%m-%dT%H:%M:%SZ')
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
- 'start_time': start_str,
319
- 'end_time': end_str,
320
- 'page_size': min(limit, 1000),
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('detections', [])
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 (search_lower not in alert.rule_name.lower() and
350
- search_lower not in alert.description.lower()):
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('detectionTime', '')
362
+ timestamp_str = detection.get("detectionTime", "")
371
363
  try:
372
- timestamp = datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
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 = detection.get('detection', [{}])[0] if detection.get('detection') else {}
378
- rule_id = rule_info.get('ruleId', detection.get('ruleId', ''))
379
- rule_name = rule_info.get('ruleName', detection.get('ruleName', rule_id))
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('severity', rule_info.get('severity', 'INFORMATIONAL'))
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('collectionElements', [])
384
+ events = detection.get("collectionElements", [])
389
385
  for element in events:
390
- references = element.get('references', [])
386
+ references = element.get("references", [])
391
387
  for ref in references:
392
- event = ref.get('event', {})
393
- principal = event.get('principal', {})
394
- target = event.get('target', {})
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('ip'):
397
- ips = principal.get('ip', [])
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('ip'):
401
- ips = target.get('ip', [])
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('description', rule_info.get('ruleText', ''))
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('id', str(hash(str(detection)))[:12]),
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
- 'CRITICAL': 'critical',
428
- 'HIGH': 'high',
429
- 'MEDIUM': 'medium',
430
- 'LOW': 'low',
431
- 'INFORMATIONAL': 'info',
432
- 'INFO': 'info',
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, 'info')
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
- 'GET',
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('rules', [])
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('ruleId', '')
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('liveRuleEnabled', True)
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('ruleName', rule_id),
478
- description=raw_rule.get('metadata', {}).get('description', ''),
479
- severity=self._map_severity(raw_rule.get('metadata', {}).get('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('metadata', {}).get('mitreTactics', []),
482
- mitre_techniques=raw_rule.get('metadata', {}).get('mitreTechniques', []),
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
- 'nmap': [
496
+ "nmap": [
501
497
  {
502
- 'rule_id': 'network_port_scan',
503
- 'rule_name': 'Network Port Scan Detection',
504
- 'yaral': '''
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
- 'hydra': [
515
+ "hydra": [
520
516
  {
521
- 'rule_id': 'brute_force_auth',
522
- 'rule_name': 'Brute Force Authentication',
523
- 'yaral': '''
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
- 'sqlmap': [
535
+ "sqlmap": [
540
536
  {
541
- 'rule_id': 'sql_injection',
542
- 'rule_name': 'SQL Injection Attempt',
543
- 'yaral': '''
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
- 'rule_id': r['rule_id'],
564
- 'rule_name': r['rule_name'],
565
- 'description': f"YARA-L rule for detecting {attack_type}",
566
- 'severity': 'high',
567
- 'enabled': False, # These are recommendations, not deployed
568
- 'siem_type': 'google_secops',
569
- 'yaral_rule': r.get('yaral', ''),
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('%Y-%m-%dT%H:%M:%SZ')
595
- end_str = end_time.strftime('%Y-%m-%dT%H:%M:%SZ')
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
- 'POST',
599
- '/v1alpha/events:udmSearch',
590
+ "POST",
591
+ "/v1alpha/events:udmSearch",
600
592
  json_data={
601
- 'query': query,
602
- 'time_range': {
603
- 'start_time': start_str,
604
- 'end_time': end_str,
593
+ "query": query,
594
+ "time_range": {
595
+ "start_time": start_str,
596
+ "end_time": end_str,
605
597
  },
606
- 'limit': limit,
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('events', {}).get('events', [])
606
+ return data.get("events", {}).get("events", [])
@@ -7,5 +7,5 @@ Maps attack types to SIEM-specific detection rules.
7
7
  from souleyez.integrations.siem.rule_mappings.wazuh_rules import WAZUH_ATTACK_RULES
8
8
 
9
9
  __all__ = [
10
- 'WAZUH_ATTACK_RULES',
10
+ "WAZUH_ATTACK_RULES",
11
11
  ]
@@ -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(attack_lower, {
206
- "rule_ids": [],
207
- "rule_names": {},
208
- "detection_guidance": "Review SIEM rule configuration for this attack category.",
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]: