souleyez 2.43.28__py3-none-any.whl → 2.43.32__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 (356) 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 +9592 -2879
  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 +1238 -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 +2198 -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 +563 -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 +408 -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 +371 -0
  116. souleyez/handlers/rdp_sec_check_handler.py +353 -0
  117. souleyez/handlers/registry.py +288 -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/whois_handler.py +277 -0
  126. souleyez/handlers/wpscan_handler.py +554 -0
  127. souleyez/history.py +32 -16
  128. souleyez/importers/msf_importer.py +106 -75
  129. souleyez/importers/smart_importer.py +208 -147
  130. souleyez/integrations/siem/__init__.py +10 -10
  131. souleyez/integrations/siem/base.py +17 -18
  132. souleyez/integrations/siem/elastic.py +108 -122
  133. souleyez/integrations/siem/factory.py +207 -80
  134. souleyez/integrations/siem/googlesecops.py +146 -154
  135. souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
  136. souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
  137. souleyez/integrations/siem/sentinel.py +107 -109
  138. souleyez/integrations/siem/splunk.py +246 -212
  139. souleyez/integrations/siem/wazuh.py +65 -71
  140. souleyez/integrations/wazuh/__init__.py +5 -5
  141. souleyez/integrations/wazuh/client.py +70 -93
  142. souleyez/integrations/wazuh/config.py +85 -57
  143. souleyez/integrations/wazuh/host_mapper.py +28 -36
  144. souleyez/integrations/wazuh/sync.py +78 -68
  145. souleyez/intelligence/__init__.py +4 -5
  146. souleyez/intelligence/correlation_analyzer.py +309 -295
  147. souleyez/intelligence/exploit_knowledge.py +661 -623
  148. souleyez/intelligence/exploit_suggestions.py +159 -139
  149. souleyez/intelligence/gap_analyzer.py +132 -97
  150. souleyez/intelligence/gap_detector.py +251 -214
  151. souleyez/intelligence/sensitive_tables.py +266 -129
  152. souleyez/intelligence/service_parser.py +137 -123
  153. souleyez/intelligence/surface_analyzer.py +407 -268
  154. souleyez/intelligence/target_parser.py +159 -162
  155. souleyez/licensing/__init__.py +6 -6
  156. souleyez/licensing/validator.py +17 -19
  157. souleyez/log_config.py +79 -54
  158. souleyez/main.py +1505 -687
  159. souleyez/migrations/fix_job_counter.py +16 -14
  160. souleyez/parsers/bloodhound_parser.py +41 -39
  161. souleyez/parsers/crackmapexec_parser.py +178 -111
  162. souleyez/parsers/dalfox_parser.py +72 -77
  163. souleyez/parsers/dnsrecon_parser.py +103 -91
  164. souleyez/parsers/enum4linux_parser.py +183 -153
  165. souleyez/parsers/ffuf_parser.py +29 -25
  166. souleyez/parsers/gobuster_parser.py +301 -41
  167. souleyez/parsers/hashcat_parser.py +324 -79
  168. souleyez/parsers/http_fingerprint_parser.py +350 -103
  169. souleyez/parsers/hydra_parser.py +131 -111
  170. souleyez/parsers/impacket_parser.py +231 -178
  171. souleyez/parsers/john_parser.py +98 -86
  172. souleyez/parsers/katana_parser.py +316 -0
  173. souleyez/parsers/msf_parser.py +943 -498
  174. souleyez/parsers/nikto_parser.py +346 -65
  175. souleyez/parsers/nmap_parser.py +262 -174
  176. souleyez/parsers/nuclei_parser.py +40 -44
  177. souleyez/parsers/responder_parser.py +26 -26
  178. souleyez/parsers/searchsploit_parser.py +74 -74
  179. souleyez/parsers/service_explorer_parser.py +279 -0
  180. souleyez/parsers/smbmap_parser.py +180 -124
  181. souleyez/parsers/sqlmap_parser.py +434 -308
  182. souleyez/parsers/theharvester_parser.py +75 -57
  183. souleyez/parsers/whois_parser.py +135 -94
  184. souleyez/parsers/wpscan_parser.py +278 -190
  185. souleyez/plugins/afp.py +44 -36
  186. souleyez/plugins/afp_brute.py +114 -46
  187. souleyez/plugins/ard.py +48 -37
  188. souleyez/plugins/bloodhound.py +95 -61
  189. souleyez/plugins/certipy.py +303 -0
  190. souleyez/plugins/crackmapexec.py +186 -85
  191. souleyez/plugins/dalfox.py +120 -59
  192. souleyez/plugins/dns_hijack.py +146 -41
  193. souleyez/plugins/dnsrecon.py +97 -61
  194. souleyez/plugins/enum4linux.py +91 -66
  195. souleyez/plugins/evil_winrm.py +291 -0
  196. souleyez/plugins/ffuf.py +166 -90
  197. souleyez/plugins/firmware_extract.py +133 -29
  198. souleyez/plugins/gobuster.py +387 -190
  199. souleyez/plugins/gpp_extract.py +393 -0
  200. souleyez/plugins/hashcat.py +100 -73
  201. souleyez/plugins/http_fingerprint.py +854 -267
  202. souleyez/plugins/hydra.py +566 -200
  203. souleyez/plugins/impacket_getnpusers.py +117 -69
  204. souleyez/plugins/impacket_psexec.py +84 -64
  205. souleyez/plugins/impacket_secretsdump.py +103 -69
  206. souleyez/plugins/impacket_smbclient.py +89 -75
  207. souleyez/plugins/john.py +86 -69
  208. souleyez/plugins/katana.py +313 -0
  209. souleyez/plugins/kerbrute.py +237 -0
  210. souleyez/plugins/lfi_extract.py +541 -0
  211. souleyez/plugins/macos_ssh.py +117 -48
  212. souleyez/plugins/mdns.py +35 -30
  213. souleyez/plugins/msf_auxiliary.py +253 -130
  214. souleyez/plugins/msf_exploit.py +239 -161
  215. souleyez/plugins/nikto.py +134 -78
  216. souleyez/plugins/nmap.py +275 -91
  217. souleyez/plugins/nuclei.py +180 -89
  218. souleyez/plugins/nxc.py +285 -0
  219. souleyez/plugins/plugin_base.py +35 -36
  220. souleyez/plugins/plugin_template.py +13 -5
  221. souleyez/plugins/rdp_sec_check.py +130 -0
  222. souleyez/plugins/responder.py +112 -71
  223. souleyez/plugins/router_http_brute.py +76 -65
  224. souleyez/plugins/router_ssh_brute.py +118 -41
  225. souleyez/plugins/router_telnet_brute.py +124 -42
  226. souleyez/plugins/routersploit.py +91 -59
  227. souleyez/plugins/routersploit_exploit.py +77 -55
  228. souleyez/plugins/searchsploit.py +91 -77
  229. souleyez/plugins/service_explorer.py +1160 -0
  230. souleyez/plugins/smbmap.py +122 -72
  231. souleyez/plugins/smbpasswd.py +215 -0
  232. souleyez/plugins/sqlmap.py +301 -113
  233. souleyez/plugins/theharvester.py +127 -75
  234. souleyez/plugins/tr069.py +79 -57
  235. souleyez/plugins/upnp.py +65 -47
  236. souleyez/plugins/upnp_abuse.py +73 -55
  237. souleyez/plugins/vnc_access.py +129 -42
  238. souleyez/plugins/vnc_brute.py +109 -38
  239. souleyez/plugins/whois.py +77 -58
  240. souleyez/plugins/wpscan.py +173 -69
  241. souleyez/reporting/__init__.py +2 -1
  242. souleyez/reporting/attack_chain.py +411 -346
  243. souleyez/reporting/charts.py +436 -501
  244. souleyez/reporting/compliance_mappings.py +334 -201
  245. souleyez/reporting/detection_report.py +126 -125
  246. souleyez/reporting/formatters.py +828 -591
  247. souleyez/reporting/generator.py +386 -302
  248. souleyez/reporting/metrics.py +72 -75
  249. souleyez/scanner.py +35 -29
  250. souleyez/security/__init__.py +37 -11
  251. souleyez/security/scope_validator.py +175 -106
  252. souleyez/security/validation.py +223 -149
  253. souleyez/security.py +22 -6
  254. souleyez/storage/credentials.py +247 -186
  255. souleyez/storage/crypto.py +296 -129
  256. souleyez/storage/database.py +73 -50
  257. souleyez/storage/db.py +58 -36
  258. souleyez/storage/deliverable_evidence.py +177 -128
  259. souleyez/storage/deliverable_exporter.py +282 -246
  260. souleyez/storage/deliverable_templates.py +134 -116
  261. souleyez/storage/deliverables.py +135 -130
  262. souleyez/storage/engagements.py +109 -56
  263. souleyez/storage/evidence.py +181 -152
  264. souleyez/storage/execution_log.py +31 -17
  265. souleyez/storage/exploit_attempts.py +93 -57
  266. souleyez/storage/exploits.py +67 -36
  267. souleyez/storage/findings.py +48 -61
  268. souleyez/storage/hosts.py +176 -144
  269. souleyez/storage/migrate_to_engagements.py +43 -19
  270. souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
  271. souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
  272. souleyez/storage/migrations/_003_add_execution_log.py +14 -8
  273. souleyez/storage/migrations/_005_screenshots.py +13 -5
  274. souleyez/storage/migrations/_006_deliverables.py +13 -5
  275. souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
  276. souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
  277. souleyez/storage/migrations/_010_evidence_linking.py +17 -10
  278. souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
  279. souleyez/storage/migrations/_012_team_collaboration.py +34 -21
  280. souleyez/storage/migrations/_013_add_host_tags.py +12 -6
  281. souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
  282. souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
  283. souleyez/storage/migrations/_016_add_domain_field.py +10 -4
  284. souleyez/storage/migrations/_017_msf_sessions.py +16 -8
  285. souleyez/storage/migrations/_018_add_osint_target.py +10 -6
  286. souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
  287. souleyez/storage/migrations/_020_add_rbac.py +36 -15
  288. souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
  289. souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
  290. souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
  291. souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
  292. souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
  293. souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
  294. souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
  295. souleyez/storage/migrations/__init__.py +26 -26
  296. souleyez/storage/migrations/migration_manager.py +19 -19
  297. souleyez/storage/msf_sessions.py +100 -65
  298. souleyez/storage/osint.py +17 -24
  299. souleyez/storage/recommendation_engine.py +269 -235
  300. souleyez/storage/screenshots.py +33 -32
  301. souleyez/storage/smb_shares.py +136 -92
  302. souleyez/storage/sqlmap_data.py +183 -128
  303. souleyez/storage/team_collaboration.py +135 -141
  304. souleyez/storage/timeline_tracker.py +122 -94
  305. souleyez/storage/wazuh_vulns.py +64 -66
  306. souleyez/storage/web_paths.py +33 -37
  307. souleyez/testing/credential_tester.py +221 -205
  308. souleyez/ui/__init__.py +1 -1
  309. souleyez/ui/ai_quotes.py +12 -12
  310. souleyez/ui/attack_surface.py +2439 -1516
  311. souleyez/ui/chain_rules_view.py +914 -382
  312. souleyez/ui/correlation_view.py +312 -230
  313. souleyez/ui/dashboard.py +2382 -1130
  314. souleyez/ui/deliverables_view.py +148 -62
  315. souleyez/ui/design_system.py +13 -13
  316. souleyez/ui/errors.py +49 -49
  317. souleyez/ui/evidence_linking_view.py +284 -179
  318. souleyez/ui/evidence_vault.py +393 -285
  319. souleyez/ui/exploit_suggestions_view.py +555 -349
  320. souleyez/ui/export_view.py +100 -66
  321. souleyez/ui/gap_analysis_view.py +315 -171
  322. souleyez/ui/help_system.py +105 -97
  323. souleyez/ui/intelligence_view.py +436 -293
  324. souleyez/ui/interactive.py +23142 -10430
  325. souleyez/ui/interactive_selector.py +75 -68
  326. souleyez/ui/log_formatter.py +47 -39
  327. souleyez/ui/menu_components.py +22 -13
  328. souleyez/ui/msf_auxiliary_menu.py +184 -133
  329. souleyez/ui/pending_chains_view.py +336 -172
  330. souleyez/ui/progress_indicators.py +5 -3
  331. souleyez/ui/recommendations_view.py +195 -137
  332. souleyez/ui/rule_builder.py +343 -225
  333. souleyez/ui/setup_wizard.py +678 -284
  334. souleyez/ui/shortcuts.py +217 -165
  335. souleyez/ui/splunk_gap_analysis_view.py +452 -270
  336. souleyez/ui/splunk_vulns_view.py +139 -86
  337. souleyez/ui/team_dashboard.py +498 -335
  338. souleyez/ui/template_selector.py +196 -105
  339. souleyez/ui/terminal.py +6 -6
  340. souleyez/ui/timeline_view.py +198 -127
  341. souleyez/ui/tool_setup.py +264 -164
  342. souleyez/ui/tutorial.py +202 -72
  343. souleyez/ui/tutorial_state.py +40 -40
  344. souleyez/ui/wazuh_vulns_view.py +235 -141
  345. souleyez/ui/wordlist_browser.py +260 -107
  346. souleyez/ui.py +464 -312
  347. souleyez/utils/tool_checker.py +427 -367
  348. souleyez/utils.py +33 -29
  349. souleyez/wordlists.py +134 -167
  350. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/METADATA +1 -1
  351. souleyez-2.43.32.dist-info/RECORD +441 -0
  352. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/WHEEL +1 -1
  353. souleyez-2.43.28.dist-info/RECORD +0 -379
  354. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/entry_points.txt +0 -0
  355. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/licenses/LICENSE +0 -0
  356. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/top_level.txt +0 -0
@@ -4,6 +4,7 @@ SIEM Configuration Management.
4
4
  Stores SIEM connection settings with encrypted credentials.
5
5
  Supports multiple SIEM platforms: Wazuh, Splunk, Elastic, Sentinel.
6
6
  """
7
+
7
8
  import json
8
9
  from typing import Optional, Dict, Any, List
9
10
  from pathlib import Path
@@ -11,7 +12,7 @@ from souleyez.storage.database import get_db
11
12
  from souleyez.storage.crypto import get_crypto_manager
12
13
 
13
14
  # Supported SIEM types (Open Source first, then Commercial)
14
- SIEM_TYPES = ['wazuh', 'elastic', 'splunk', 'sentinel', 'google_secops']
15
+ SIEM_TYPES = ["wazuh", "elastic", "splunk", "sentinel", "google_secops"]
15
16
 
16
17
 
17
18
  class WazuhConfig:
@@ -22,7 +23,9 @@ class WazuhConfig:
22
23
  """
23
24
 
24
25
  @staticmethod
25
- def get_config(engagement_id: int, siem_type: str = None) -> Optional[Dict[str, Any]]:
26
+ def get_config(
27
+ engagement_id: int, siem_type: str = None
28
+ ) -> Optional[Dict[str, Any]]:
26
29
  """
27
30
  Get SIEM config for an engagement.
28
31
 
@@ -40,35 +43,44 @@ class WazuhConfig:
40
43
  # Check if new columns exist (migration 025+)
41
44
  cursor.execute("PRAGMA table_info(wazuh_config)")
42
45
  columns = [col[1] for col in cursor.fetchall()]
43
- has_new_columns = 'siem_type' in columns
46
+ has_new_columns = "siem_type" in columns
44
47
 
45
48
  # Query with or without new columns
46
49
  if has_new_columns:
47
50
  if siem_type:
48
- cursor.execute("""
51
+ cursor.execute(
52
+ """
49
53
  SELECT api_url, api_user, api_password, indexer_url, indexer_user,
50
54
  indexer_password, verify_ssl, enabled, siem_type, config_json
51
55
  FROM wazuh_config
52
56
  WHERE engagement_id = ? AND siem_type = ?
53
- """, (engagement_id, siem_type))
57
+ """,
58
+ (engagement_id, siem_type),
59
+ )
54
60
  else:
55
61
  # Get most recently updated config (the "current" selected SIEM)
56
62
  # Not filtering by enabled - user may have selected but not configured yet
57
- cursor.execute("""
63
+ cursor.execute(
64
+ """
58
65
  SELECT api_url, api_user, api_password, indexer_url, indexer_user,
59
66
  indexer_password, verify_ssl, enabled, siem_type, config_json
60
67
  FROM wazuh_config
61
68
  WHERE engagement_id = ?
62
69
  ORDER BY updated_at DESC
63
70
  LIMIT 1
64
- """, (engagement_id,))
71
+ """,
72
+ (engagement_id,),
73
+ )
65
74
  else:
66
- cursor.execute("""
75
+ cursor.execute(
76
+ """
67
77
  SELECT api_url, api_user, api_password, indexer_url, indexer_user,
68
78
  indexer_password, verify_ssl, enabled
69
79
  FROM wazuh_config
70
80
  WHERE engagement_id = ?
71
- """, (engagement_id,))
81
+ """,
82
+ (engagement_id,),
83
+ )
72
84
 
73
85
  row = cursor.fetchone()
74
86
  if not row:
@@ -107,7 +119,7 @@ class WazuhConfig:
107
119
  # Decrypt any encrypted fields in extra config
108
120
  crypto = get_crypto_manager()
109
121
  if crypto and extra_config:
110
- for key in ['password', 'client_secret', 'api_key', 'token']:
122
+ for key in ["password", "client_secret", "api_key", "token"]:
111
123
  if key in extra_config and extra_config[key]:
112
124
  try:
113
125
  extra_config[key] = crypto.decrypt(extra_config[key])
@@ -118,9 +130,9 @@ class WazuhConfig:
118
130
  pass
119
131
 
120
132
  # Map Wazuh fields to generic names for SIEMFactory compatibility
121
- if config['siem_type'] == 'wazuh':
122
- config['username'] = config.get('api_user')
123
- config['password'] = config.get('api_password')
133
+ if config["siem_type"] == "wazuh":
134
+ config["username"] = config.get("api_user")
135
+ config["password"] = config.get("api_password")
124
136
 
125
137
  return config
126
138
 
@@ -130,14 +142,12 @@ class WazuhConfig:
130
142
  cursor.execute("PRAGMA table_info(wazuh_config)")
131
143
  columns = [col[1] for col in cursor.fetchall()]
132
144
 
133
- if 'siem_type' not in columns:
145
+ if "siem_type" not in columns:
134
146
  cursor.execute(
135
147
  "ALTER TABLE wazuh_config ADD COLUMN siem_type TEXT DEFAULT 'wazuh'"
136
148
  )
137
- if 'config_json' not in columns:
138
- cursor.execute(
139
- "ALTER TABLE wazuh_config ADD COLUMN config_json TEXT"
140
- )
149
+ if "config_json" not in columns:
150
+ cursor.execute("ALTER TABLE wazuh_config ADD COLUMN config_json TEXT")
141
151
  conn.commit()
142
152
 
143
153
  @staticmethod
@@ -152,7 +162,7 @@ class WazuhConfig:
152
162
  verify_ssl: bool = False,
153
163
  enabled: bool = True,
154
164
  siem_type: str = "wazuh",
155
- config_json: Optional[Dict[str, Any]] = None
165
+ config_json: Optional[Dict[str, Any]] = None,
156
166
  ) -> bool:
157
167
  """
158
168
  Save SIEM config for an engagement.
@@ -199,15 +209,18 @@ class WazuhConfig:
199
209
  try:
200
210
  crypto = get_crypto_manager()
201
211
  if crypto:
202
- for key in ['password', 'client_secret', 'api_key', 'token']:
212
+ for key in ["password", "client_secret", "api_key", "token"]:
203
213
  if key in encrypted_config and encrypted_config[key]:
204
- encrypted_config[key] = crypto.encrypt(encrypted_config[key])
214
+ encrypted_config[key] = crypto.encrypt(
215
+ encrypted_config[key]
216
+ )
205
217
  except Exception:
206
218
  pass
207
219
  config_json_str = json.dumps(encrypted_config)
208
220
 
209
221
  # Upsert config - keyed by (engagement_id, siem_type) for multi-SIEM support
210
- cursor.execute("""
222
+ cursor.execute(
223
+ """
211
224
  INSERT INTO wazuh_config (
212
225
  engagement_id, api_url, api_user, api_password, indexer_url,
213
226
  indexer_user, indexer_password, verify_ssl, enabled,
@@ -225,21 +238,28 @@ class WazuhConfig:
225
238
  enabled = excluded.enabled,
226
239
  config_json = excluded.config_json,
227
240
  updated_at = CURRENT_TIMESTAMP
228
- """, (
229
- engagement_id, api_url, api_user, encrypted_api_password,
230
- indexer_url, indexer_user or 'admin', encrypted_indexer_password,
231
- verify_ssl, enabled, siem_type, config_json_str
232
- ))
241
+ """,
242
+ (
243
+ engagement_id,
244
+ api_url,
245
+ api_user,
246
+ encrypted_api_password,
247
+ indexer_url,
248
+ indexer_user or "admin",
249
+ encrypted_indexer_password,
250
+ verify_ssl,
251
+ enabled,
252
+ siem_type,
253
+ config_json_str,
254
+ ),
255
+ )
233
256
 
234
257
  conn.commit()
235
258
  return True
236
259
 
237
260
  @staticmethod
238
261
  def save_siem_config(
239
- engagement_id: int,
240
- siem_type: str,
241
- config: Dict[str, Any],
242
- enabled: bool = True
262
+ engagement_id: int, siem_type: str, config: Dict[str, Any], enabled: bool = True
243
263
  ) -> bool:
244
264
  """
245
265
  Save configuration for any SIEM type.
@@ -252,29 +272,29 @@ class WazuhConfig:
252
272
  config: SIEM-specific configuration dict
253
273
  enabled: Whether integration is enabled
254
274
  """
255
- if siem_type == 'wazuh':
275
+ if siem_type == "wazuh":
256
276
  # Use existing Wazuh fields for backwards compatibility
257
277
  return WazuhConfig.save_config(
258
278
  engagement_id=engagement_id,
259
- api_url=config.get('api_url', ''),
260
- api_user=config.get('username', config.get('api_user', '')),
261
- api_password=config.get('password', config.get('api_password', '')),
262
- indexer_url=config.get('indexer_url'),
263
- indexer_user=config.get('indexer_user'),
264
- indexer_password=config.get('indexer_password'),
265
- verify_ssl=config.get('verify_ssl', False),
279
+ api_url=config.get("api_url", ""),
280
+ api_user=config.get("username", config.get("api_user", "")),
281
+ api_password=config.get("password", config.get("api_password", "")),
282
+ indexer_url=config.get("indexer_url"),
283
+ indexer_user=config.get("indexer_user"),
284
+ indexer_password=config.get("indexer_password"),
285
+ verify_ssl=config.get("verify_ssl", False),
266
286
  enabled=enabled,
267
- siem_type='wazuh'
287
+ siem_type="wazuh",
268
288
  )
269
289
  else:
270
290
  # For other SIEMs, store config in config_json
271
291
  return WazuhConfig.save_config(
272
292
  engagement_id=engagement_id,
273
- api_url=config.get('api_url', config.get('elasticsearch_url', '')),
274
- verify_ssl=config.get('verify_ssl', False),
293
+ api_url=config.get("api_url", config.get("elasticsearch_url", "")),
294
+ verify_ssl=config.get("verify_ssl", False),
275
295
  enabled=enabled,
276
296
  siem_type=siem_type,
277
- config_json=config
297
+ config_json=config,
278
298
  )
279
299
 
280
300
  @staticmethod
@@ -292,10 +312,12 @@ class WazuhConfig:
292
312
  if siem_type:
293
313
  cursor.execute(
294
314
  "DELETE FROM wazuh_config WHERE engagement_id = ? AND siem_type = ?",
295
- (engagement_id, siem_type)
315
+ (engagement_id, siem_type),
296
316
  )
297
317
  else:
298
- cursor.execute("DELETE FROM wazuh_config WHERE engagement_id = ?", (engagement_id,))
318
+ cursor.execute(
319
+ "DELETE FROM wazuh_config WHERE engagement_id = ?", (engagement_id,)
320
+ )
299
321
  conn.commit()
300
322
  return cursor.rowcount > 0
301
323
 
@@ -320,28 +342,34 @@ class WazuhConfig:
320
342
  cursor.execute("PRAGMA table_info(wazuh_config)")
321
343
  columns = [col[1] for col in cursor.fetchall()]
322
344
 
323
- if 'siem_type' not in columns:
345
+ if "siem_type" not in columns:
324
346
  # Old schema - only one config possible
325
- cursor.execute("""
347
+ cursor.execute(
348
+ """
326
349
  SELECT 'wazuh' as siem_type, enabled, api_url
327
350
  FROM wazuh_config
328
351
  WHERE engagement_id = ?
329
- """, (engagement_id,))
352
+ """,
353
+ (engagement_id,),
354
+ )
330
355
  else:
331
- cursor.execute("""
356
+ cursor.execute(
357
+ """
332
358
  SELECT siem_type, enabled, api_url, updated_at
333
359
  FROM wazuh_config
334
360
  WHERE engagement_id = ?
335
361
  ORDER BY siem_type
336
- """, (engagement_id,))
362
+ """,
363
+ (engagement_id,),
364
+ )
337
365
 
338
366
  rows = cursor.fetchall()
339
367
  return [
340
368
  {
341
- 'siem_type': row[0],
342
- 'enabled': bool(row[1]),
343
- 'api_url': row[2],
344
- 'updated_at': row[3] if len(row) > 3 else None
369
+ "siem_type": row[0],
370
+ "enabled": bool(row[1]),
371
+ "api_url": row[2],
372
+ "updated_at": row[3] if len(row) > 3 else None,
345
373
  }
346
374
  for row in rows
347
375
  ]
@@ -373,8 +401,8 @@ class WazuhConfig:
373
401
  """
374
402
  config = WazuhConfig.get_config(engagement_id)
375
403
  if config:
376
- return config.get('siem_type', 'wazuh')
377
- return 'wazuh'
404
+ return config.get("siem_type", "wazuh")
405
+ return "wazuh"
378
406
 
379
407
  @staticmethod
380
408
  def set_current_siem(engagement_id: int, siem_type: str) -> bool:
@@ -395,7 +423,7 @@ class WazuhConfig:
395
423
  cursor = conn.cursor()
396
424
  cursor.execute(
397
425
  "UPDATE wazuh_config SET updated_at = CURRENT_TIMESTAMP WHERE engagement_id = ? AND siem_type = ?",
398
- (engagement_id, siem_type)
426
+ (engagement_id, siem_type),
399
427
  )
400
428
  conn.commit()
401
429
  return cursor.rowcount > 0
@@ -17,11 +17,7 @@ class WazuhHostMapper:
17
17
  def __init__(self):
18
18
  self.db = get_db()
19
19
 
20
- def map_agent_to_host(
21
- self,
22
- engagement_id: int,
23
- agent_ip: str
24
- ) -> Optional[int]:
20
+ def map_agent_to_host(self, engagement_id: int, agent_ip: str) -> Optional[int]:
25
21
  """
26
22
  Find SoulEyez host_id matching an agent IP.
27
23
 
@@ -42,7 +38,7 @@ class WazuhHostMapper:
42
38
  result = self.db.execute_one(query, (engagement_id, agent_ip))
43
39
 
44
40
  if result:
45
- return result['id']
41
+ return result["id"]
46
42
 
47
43
  return None
48
44
 
@@ -66,7 +62,7 @@ class WazuhHostMapper:
66
62
 
67
63
  mapping = {}
68
64
  for agent in agents:
69
- agent_ip = agent.get('agent_ip')
65
+ agent_ip = agent.get("agent_ip")
70
66
  if agent_ip:
71
67
  host_id = self.map_agent_to_host(engagement_id, agent_ip)
72
68
  mapping[agent_ip] = host_id
@@ -78,10 +74,7 @@ class WazuhHostMapper:
78
74
  return mapping
79
75
 
80
76
  def _update_vuln_host_mapping(
81
- self,
82
- engagement_id: int,
83
- agent_ip: str,
84
- host_id: int
77
+ self, engagement_id: int, agent_ip: str, host_id: int
85
78
  ) -> int:
86
79
  """
87
80
  Update all vulnerabilities from an agent IP with the host_id.
@@ -103,7 +96,7 @@ class WazuhHostMapper:
103
96
  WHERE engagement_id = ? AND agent_ip = ? AND host_id = ?
104
97
  """
105
98
  result = self.db.execute_one(count_query, (engagement_id, agent_ip, host_id))
106
- return result.get('count', 0) if result else 0
99
+ return result.get("count", 0) if result else 0
107
100
 
108
101
  def get_unmapped_agents(self, engagement_id: int) -> List[Dict[str, any]]:
109
102
  """
@@ -167,18 +160,15 @@ class WazuhHostMapper:
167
160
 
168
161
  if result:
169
162
  return {
170
- 'mapped': result.get('mapped', 0) or 0,
171
- 'unmapped': result.get('unmapped', 0) or 0,
172
- 'total': result.get('total', 0) or 0
163
+ "mapped": result.get("mapped", 0) or 0,
164
+ "unmapped": result.get("unmapped", 0) or 0,
165
+ "total": result.get("total", 0) or 0,
173
166
  }
174
167
 
175
- return {'mapped': 0, 'unmapped': 0, 'total': 0}
168
+ return {"mapped": 0, "unmapped": 0, "total": 0}
176
169
 
177
170
  def manual_map(
178
- self,
179
- engagement_id: int,
180
- agent_ip: str,
181
- host_id: int
171
+ self, engagement_id: int, agent_ip: str, host_id: int
182
172
  ) -> Tuple[bool, int]:
183
173
  """
184
174
  Manually map an agent IP to a host.
@@ -225,7 +215,7 @@ class WazuhHostMapper:
225
215
  WHERE engagement_id = ? AND agent_ip = ? AND host_id IS NULL
226
216
  """
227
217
  result = self.db.execute_one(count_query, (engagement_id, agent_ip))
228
- return result.get('count', 0) if result else 0
218
+ return result.get("count", 0) if result else 0
229
219
 
230
220
  def suggest_mappings(self, engagement_id: int) -> List[Dict[str, any]]:
231
221
  """
@@ -250,38 +240,40 @@ class WazuhHostMapper:
250
240
  suggestions = []
251
241
 
252
242
  for agent in unmapped:
253
- agent_ip = agent.get('agent_ip')
243
+ agent_ip = agent.get("agent_ip")
254
244
  if not agent_ip:
255
245
  continue
256
246
 
257
247
  # Try to find hosts in same subnet
258
- agent_parts = agent_ip.split('.')
248
+ agent_parts = agent_ip.split(".")
259
249
  if len(agent_parts) != 4:
260
250
  continue
261
251
 
262
- agent_subnet = '.'.join(agent_parts[:3])
252
+ agent_subnet = ".".join(agent_parts[:3])
263
253
 
264
254
  for host in hosts:
265
- host_ip = host.get('ip_address')
255
+ host_ip = host.get("ip_address")
266
256
  if not host_ip:
267
257
  continue
268
258
 
269
- host_parts = host_ip.split('.')
259
+ host_parts = host_ip.split(".")
270
260
  if len(host_parts) != 4:
271
261
  continue
272
262
 
273
- host_subnet = '.'.join(host_parts[:3])
263
+ host_subnet = ".".join(host_parts[:3])
274
264
 
275
265
  # Same subnet = possible match
276
266
  if agent_subnet == host_subnet:
277
- suggestions.append({
278
- 'agent_ip': agent_ip,
279
- 'agent_name': agent.get('agent_name'),
280
- 'suggested_host_id': host['id'],
281
- 'suggested_host_ip': host_ip,
282
- 'suggested_host_name': host.get('hostname'),
283
- 'confidence': 'medium',
284
- 'reason': 'Same subnet'
285
- })
267
+ suggestions.append(
268
+ {
269
+ "agent_ip": agent_ip,
270
+ "agent_name": agent.get("agent_name"),
271
+ "suggested_host_id": host["id"],
272
+ "suggested_host_ip": host_ip,
273
+ "suggested_host_name": host.get("hostname"),
274
+ "confidence": "medium",
275
+ "reason": "Same subnet",
276
+ }
277
+ )
286
278
 
287
279
  return suggestions