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
@@ -8,10 +8,10 @@ from souleyez.storage.database import get_db
8
8
 
9
9
 
10
10
  # Valid status values
11
- STATUS_NOT_TRIED = 'not_tried'
12
- STATUS_ATTEMPTED = 'attempted'
13
- STATUS_FAILED = 'failed'
14
- STATUS_SUCCESS = 'success'
11
+ STATUS_NOT_TRIED = "not_tried"
12
+ STATUS_ATTEMPTED = "attempted"
13
+ STATUS_FAILED = "failed"
14
+ STATUS_SUCCESS = "success"
15
15
 
16
16
  VALID_STATUSES = [STATUS_NOT_TRIED, STATUS_ATTEMPTED, STATUS_FAILED, STATUS_SUCCESS]
17
17
 
@@ -23,7 +23,7 @@ def record_attempt(
23
23
  exploit_title: str,
24
24
  status: str,
25
25
  service_id: Optional[int] = None,
26
- notes: Optional[str] = None
26
+ notes: Optional[str] = None,
27
27
  ) -> int:
28
28
  """
29
29
  Record an exploit attempt. Creates new record or updates existing one.
@@ -47,15 +47,19 @@ def record_attempt(
47
47
  conn = db.get_connection()
48
48
 
49
49
  # Check if record exists
50
- existing = conn.execute("""
50
+ existing = conn.execute(
51
+ """
51
52
  SELECT id FROM exploit_attempts
52
53
  WHERE engagement_id = ? AND host_id = ? AND service_id IS ? AND exploit_identifier = ?
53
- """, (engagement_id, host_id, service_id, exploit_identifier)).fetchone()
54
+ """,
55
+ (engagement_id, host_id, service_id, exploit_identifier),
56
+ ).fetchone()
54
57
 
55
58
  if existing:
56
59
  # Update existing record
57
- attempt_id = existing['id']
58
- conn.execute("""
60
+ attempt_id = existing["id"]
61
+ conn.execute(
62
+ """
59
63
  UPDATE exploit_attempts
60
64
  SET status = ?,
61
65
  exploit_title = ?,
@@ -63,18 +67,29 @@ def record_attempt(
63
67
  attempted_at = ?,
64
68
  updated_at = CURRENT_TIMESTAMP
65
69
  WHERE id = ?
66
- """, (status, exploit_title, notes, datetime.now(), attempt_id))
70
+ """,
71
+ (status, exploit_title, notes, datetime.now(), attempt_id),
72
+ )
67
73
  else:
68
74
  # Create new record
69
- cursor = conn.execute("""
75
+ cursor = conn.execute(
76
+ """
70
77
  INSERT INTO exploit_attempts (
71
78
  engagement_id, host_id, service_id, exploit_identifier,
72
79
  exploit_title, status, attempted_at, notes
73
80
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
74
- """, (
75
- engagement_id, host_id, service_id, exploit_identifier,
76
- exploit_title, status, datetime.now() if status != STATUS_NOT_TRIED else None, notes
77
- ))
81
+ """,
82
+ (
83
+ engagement_id,
84
+ host_id,
85
+ service_id,
86
+ exploit_identifier,
87
+ exploit_title,
88
+ status,
89
+ datetime.now() if status != STATUS_NOT_TRIED else None,
90
+ notes,
91
+ ),
92
+ )
78
93
  attempt_id = cursor.lastrowid
79
94
 
80
95
  conn.commit()
@@ -87,7 +102,7 @@ def get_attempt_status(
87
102
  engagement_id: int,
88
103
  host_id: int,
89
104
  exploit_identifier: str,
90
- service_id: Optional[int] = None
105
+ service_id: Optional[int] = None,
91
106
  ) -> Optional[str]:
92
107
  """
93
108
  Get the status of a specific exploit attempt.
@@ -98,14 +113,17 @@ def get_attempt_status(
98
113
  db = get_db()
99
114
  conn = db.get_connection()
100
115
 
101
- result = conn.execute("""
116
+ result = conn.execute(
117
+ """
102
118
  SELECT status FROM exploit_attempts
103
119
  WHERE engagement_id = ? AND host_id = ? AND service_id IS ? AND exploit_identifier = ?
104
- """, (engagement_id, host_id, service_id, exploit_identifier)).fetchone()
120
+ """,
121
+ (engagement_id, host_id, service_id, exploit_identifier),
122
+ ).fetchone()
105
123
 
106
124
  conn.close()
107
125
 
108
- return result['status'] if result else None
126
+ return result["status"] if result else None
109
127
 
110
128
 
111
129
  def get_attempts_by_host(host_id: int) -> List[Dict[str, Any]]:
@@ -113,7 +131,8 @@ def get_attempts_by_host(host_id: int) -> List[Dict[str, Any]]:
113
131
  db = get_db()
114
132
  conn = db.get_connection()
115
133
 
116
- results = conn.execute("""
134
+ results = conn.execute(
135
+ """
117
136
  SELECT
118
137
  ea.*,
119
138
  s.port,
@@ -125,14 +144,18 @@ def get_attempts_by_host(host_id: int) -> List[Dict[str, Any]]:
125
144
  LEFT JOIN hosts h ON ea.host_id = h.id
126
145
  WHERE ea.host_id = ?
127
146
  ORDER BY ea.updated_at DESC
128
- """, (host_id,)).fetchall()
147
+ """,
148
+ (host_id,),
149
+ ).fetchall()
129
150
 
130
151
  conn.close()
131
152
 
132
153
  return [dict(r) for r in results]
133
154
 
134
155
 
135
- def get_attempts_by_engagement(engagement_id: int, status_filter: Optional[str] = None) -> List[Dict[str, Any]]:
156
+ def get_attempts_by_engagement(
157
+ engagement_id: int, status_filter: Optional[str] = None
158
+ ) -> List[Dict[str, Any]]:
136
159
  """
137
160
  Get all exploit attempts for an engagement, optionally filtered by status.
138
161
 
@@ -162,7 +185,9 @@ def get_attempts_by_engagement(engagement_id: int, status_filter: Optional[str]
162
185
 
163
186
  if status_filter:
164
187
  if status_filter not in VALID_STATUSES:
165
- raise ValueError(f"Invalid status filter. Must be one of: {', '.join(VALID_STATUSES)}")
188
+ raise ValueError(
189
+ f"Invalid status filter. Must be one of: {', '.join(VALID_STATUSES)}"
190
+ )
166
191
  query += " AND ea.status = ?"
167
192
  params.append(status_filter)
168
193
 
@@ -186,43 +211,43 @@ def get_attempt_stats(engagement_id: int) -> Dict[str, Any]:
186
211
  conn = db.get_connection()
187
212
 
188
213
  # Get status breakdown
189
- status_counts = conn.execute("""
214
+ status_counts = conn.execute(
215
+ """
190
216
  SELECT status, COUNT(*) as count
191
217
  FROM exploit_attempts
192
218
  WHERE engagement_id = ?
193
219
  GROUP BY status
194
- """, (engagement_id,)).fetchall()
220
+ """,
221
+ (engagement_id,),
222
+ ).fetchall()
195
223
 
196
- stats = {
197
- 'total': 0,
198
- 'not_tried': 0,
199
- 'attempted': 0,
200
- 'failed': 0,
201
- 'success': 0
202
- }
224
+ stats = {"total": 0, "not_tried": 0, "attempted": 0, "failed": 0, "success": 0}
203
225
 
204
226
  for row in status_counts:
205
- stats['total'] += row['count']
206
- stats[row['status']] = row['count']
227
+ stats["total"] += row["count"]
228
+ stats[row["status"]] = row["count"]
207
229
 
208
230
  # Get success rate if attempts have been made
209
- total_attempts = stats['attempted'] + stats['failed'] + stats['success']
231
+ total_attempts = stats["attempted"] + stats["failed"] + stats["success"]
210
232
  if total_attempts > 0:
211
- stats['success_rate'] = (stats['success'] / total_attempts) * 100
233
+ stats["success_rate"] = (stats["success"] / total_attempts) * 100
212
234
  else:
213
- stats['success_rate'] = 0
235
+ stats["success_rate"] = 0
214
236
 
215
237
  # Get host coverage
216
- host_coverage = conn.execute("""
238
+ host_coverage = conn.execute(
239
+ """
217
240
  SELECT
218
241
  COUNT(DISTINCT host_id) as hosts_with_attempts,
219
242
  (SELECT COUNT(*) FROM hosts WHERE engagement_id = ?) as total_hosts
220
243
  FROM exploit_attempts
221
244
  WHERE engagement_id = ?
222
- """, (engagement_id, engagement_id)).fetchone()
245
+ """,
246
+ (engagement_id, engagement_id),
247
+ ).fetchone()
223
248
 
224
- stats['hosts_with_attempts'] = host_coverage['hosts_with_attempts']
225
- stats['total_hosts'] = host_coverage['total_hosts']
249
+ stats["hosts_with_attempts"] = host_coverage["hosts_with_attempts"]
250
+ stats["total_hosts"] = host_coverage["total_hosts"]
226
251
 
227
252
  conn.close()
228
253
 
@@ -230,9 +255,7 @@ def get_attempt_stats(engagement_id: int) -> Dict[str, Any]:
230
255
 
231
256
 
232
257
  def update_attempt_status(
233
- attempt_id: int,
234
- status: str,
235
- notes: Optional[str] = None
258
+ attempt_id: int, status: str, notes: Optional[str] = None
236
259
  ) -> bool:
237
260
  """
238
261
  Update the status of an existing attempt.
@@ -251,14 +274,22 @@ def update_attempt_status(
251
274
  db = get_db()
252
275
  conn = db.get_connection()
253
276
 
254
- cursor = conn.execute("""
277
+ cursor = conn.execute(
278
+ """
255
279
  UPDATE exploit_attempts
256
280
  SET status = ?,
257
281
  notes = ?,
258
282
  attempted_at = ?,
259
283
  updated_at = CURRENT_TIMESTAMP
260
284
  WHERE id = ?
261
- """, (status, notes, datetime.now() if status != STATUS_NOT_TRIED else None, attempt_id))
285
+ """,
286
+ (
287
+ status,
288
+ notes,
289
+ datetime.now() if status != STATUS_NOT_TRIED else None,
290
+ attempt_id,
291
+ ),
292
+ )
262
293
 
263
294
  rows_updated = cursor.rowcount
264
295
 
@@ -287,7 +318,9 @@ def delete_attempts_by_engagement(engagement_id: int) -> int:
287
318
  db = get_db()
288
319
  conn = db.get_connection()
289
320
 
290
- cursor = conn.execute("DELETE FROM exploit_attempts WHERE engagement_id = ?", (engagement_id,))
321
+ cursor = conn.execute(
322
+ "DELETE FROM exploit_attempts WHERE engagement_id = ?", (engagement_id,)
323
+ )
291
324
  rows_deleted = cursor.rowcount
292
325
 
293
326
  conn.commit()
@@ -327,13 +360,13 @@ def bulk_record_attempts(attempts: List[Dict[str, Any]]) -> int:
327
360
  count = 0
328
361
  for attempt in attempts:
329
362
  record_attempt(
330
- engagement_id=attempt['engagement_id'],
331
- host_id=attempt['host_id'],
332
- exploit_identifier=attempt['exploit_identifier'],
333
- exploit_title=attempt['exploit_title'],
334
- status=attempt['status'],
335
- service_id=attempt.get('service_id'),
336
- notes=attempt.get('notes')
363
+ engagement_id=attempt["engagement_id"],
364
+ host_id=attempt["host_id"],
365
+ exploit_identifier=attempt["exploit_identifier"],
366
+ exploit_title=attempt["exploit_title"],
367
+ status=attempt["status"],
368
+ service_id=attempt.get("service_id"),
369
+ notes=attempt.get("notes"),
337
370
  )
338
371
  count += 1
339
372
 
@@ -352,12 +385,15 @@ def get_untried_exploits_for_host(engagement_id: int, host_id: int) -> List[str]
352
385
  db = get_db()
353
386
  conn = db.get_connection()
354
387
 
355
- results = conn.execute("""
388
+ results = conn.execute(
389
+ """
356
390
  SELECT exploit_identifier
357
391
  FROM exploit_attempts
358
392
  WHERE engagement_id = ? AND host_id = ? AND status = ?
359
- """, (engagement_id, host_id, STATUS_NOT_TRIED)).fetchall()
393
+ """,
394
+ (engagement_id, host_id, STATUS_NOT_TRIED),
395
+ ).fetchall()
360
396
 
361
397
  conn.close()
362
398
 
363
- return [r['exploit_identifier'] for r in results]
399
+ return [r["exploit_identifier"] for r in results]
@@ -15,26 +15,36 @@ def add_exploit(
15
15
  url: str,
16
16
  date_published: str,
17
17
  search_term: str,
18
- service_id: Optional[int] = None
18
+ service_id: Optional[int] = None,
19
19
  ) -> int:
20
20
  """Add a new exploit to the database."""
21
21
  db = get_db()
22
22
  conn = db.get_connection()
23
-
24
- cursor = conn.execute("""
23
+
24
+ cursor = conn.execute(
25
+ """
25
26
  INSERT INTO exploits (
26
27
  engagement_id, service_id, edb_id, title, platform,
27
28
  type, url, date_published, search_term
28
29
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
29
- """, (
30
- engagement_id, service_id, edb_id, title, platform,
31
- exploit_type, url, date_published, search_term
32
- ))
33
-
30
+ """,
31
+ (
32
+ engagement_id,
33
+ service_id,
34
+ edb_id,
35
+ title,
36
+ platform,
37
+ exploit_type,
38
+ url,
39
+ date_published,
40
+ search_term,
41
+ ),
42
+ )
43
+
34
44
  exploit_id = cursor.lastrowid
35
45
  conn.commit()
36
46
  conn.close()
37
-
47
+
38
48
  return exploit_id
39
49
 
40
50
 
@@ -42,8 +52,9 @@ def get_exploits_by_engagement(engagement_id: int) -> List[Dict[str, Any]]:
42
52
  """Get all exploits for an engagement."""
43
53
  db = get_db()
44
54
  conn = db.get_connection()
45
-
46
- results = conn.execute("""
55
+
56
+ results = conn.execute(
57
+ """
47
58
  SELECT
48
59
  e.*,
49
60
  s.port,
@@ -55,10 +66,12 @@ def get_exploits_by_engagement(engagement_id: int) -> List[Dict[str, Any]]:
55
66
  LEFT JOIN hosts h ON s.host_id = h.id
56
67
  WHERE e.engagement_id = ?
57
68
  ORDER BY e.found_at DESC
58
- """, (engagement_id,)).fetchall()
59
-
69
+ """,
70
+ (engagement_id,),
71
+ ).fetchall()
72
+
60
73
  conn.close()
61
-
74
+
62
75
  return [dict(r) for r in results]
63
76
 
64
77
 
@@ -66,15 +79,18 @@ def get_exploits_by_service(service_id: int) -> List[Dict[str, Any]]:
66
79
  """Get all exploits for a specific service."""
67
80
  db = get_db()
68
81
  conn = db.get_connection()
69
-
70
- results = conn.execute("""
82
+
83
+ results = conn.execute(
84
+ """
71
85
  SELECT * FROM exploits
72
86
  WHERE service_id = ?
73
87
  ORDER BY found_at DESC
74
- """, (service_id,)).fetchall()
75
-
88
+ """,
89
+ (service_id,),
90
+ ).fetchall()
91
+
76
92
  conn.close()
77
-
93
+
78
94
  return [dict(r) for r in results]
79
95
 
80
96
 
@@ -84,7 +100,8 @@ def get_exploit_stats(engagement_id: int) -> Dict[str, Any]:
84
100
  conn = db.get_connection()
85
101
 
86
102
  # Get basic stats
87
- stats = conn.execute("""
103
+ stats = conn.execute(
104
+ """
88
105
  SELECT
89
106
  COUNT(*) as total,
90
107
  COUNT(DISTINCT platform) as platforms,
@@ -92,36 +109,48 @@ def get_exploit_stats(engagement_id: int) -> Dict[str, Any]:
92
109
  COUNT(DISTINCT service_id) as services_with_exploits
93
110
  FROM exploits
94
111
  WHERE engagement_id = ?
95
- """, (engagement_id,)).fetchone()
112
+ """,
113
+ (engagement_id,),
114
+ ).fetchone()
96
115
 
97
- result = dict(stats) if stats else {
98
- 'total': 0,
99
- 'platforms': 0,
100
- 'types': 0,
101
- 'services_with_exploits': 0
102
- }
116
+ result = (
117
+ dict(stats)
118
+ if stats
119
+ else {"total": 0, "platforms": 0, "types": 0, "services_with_exploits": 0}
120
+ )
103
121
 
104
122
  # Get platform breakdown (top 5)
105
- platform_breakdown = conn.execute("""
123
+ platform_breakdown = conn.execute(
124
+ """
106
125
  SELECT platform, COUNT(*) as count
107
126
  FROM exploits
108
127
  WHERE engagement_id = ?
109
128
  GROUP BY platform
110
129
  ORDER BY count DESC
111
130
  LIMIT 5
112
- """, (engagement_id,)).fetchall()
113
- result['platform_breakdown'] = [{'platform': row['platform'], 'count': row['count']} for row in platform_breakdown]
131
+ """,
132
+ (engagement_id,),
133
+ ).fetchall()
134
+ result["platform_breakdown"] = [
135
+ {"platform": row["platform"], "count": row["count"]}
136
+ for row in platform_breakdown
137
+ ]
114
138
 
115
139
  # Get type breakdown (top 5)
116
- type_breakdown = conn.execute("""
140
+ type_breakdown = conn.execute(
141
+ """
117
142
  SELECT type, COUNT(*) as count
118
143
  FROM exploits
119
144
  WHERE engagement_id = ?
120
145
  GROUP BY type
121
146
  ORDER BY count DESC
122
147
  LIMIT 5
123
- """, (engagement_id,)).fetchall()
124
- result['type_breakdown'] = [{'type': row['type'], 'count': row['count']} for row in type_breakdown]
148
+ """,
149
+ (engagement_id,),
150
+ ).fetchall()
151
+ result["type_breakdown"] = [
152
+ {"type": row["type"], "count": row["count"]} for row in type_breakdown
153
+ ]
125
154
 
126
155
  conn.close()
127
156
 
@@ -147,7 +176,9 @@ def delete_exploits_by_engagement(engagement_id: int) -> int:
147
176
  db = get_db()
148
177
  conn = db.get_connection()
149
178
 
150
- cursor = conn.execute("DELETE FROM exploits WHERE engagement_id = ?", (engagement_id,))
179
+ cursor = conn.execute(
180
+ "DELETE FROM exploits WHERE engagement_id = ?", (engagement_id,)
181
+ )
151
182
  rows_deleted = cursor.rowcount
152
183
 
153
184
  conn.commit()
@@ -164,7 +195,7 @@ def delete_exploits_by_ids(exploit_ids: List[int]) -> int:
164
195
  db = get_db()
165
196
  conn = db.get_connection()
166
197
 
167
- placeholders = ','.join('?' * len(exploit_ids))
198
+ placeholders = ",".join("?" * len(exploit_ids))
168
199
  query = f"DELETE FROM exploits WHERE id IN ({placeholders})"
169
200
 
170
201
  cursor = conn.execute(query, exploit_ids)
@@ -210,7 +241,7 @@ def search_exploits(engagement_id: int, search_term: str) -> List[Dict[str, Any]
210
241
  )
211
242
  """
212
243
  # Add three parameters (one for each field) for this keyword
213
- keyword_pattern = f'%{keyword}%'
244
+ keyword_pattern = f"%{keyword}%"
214
245
  params.extend([keyword_pattern, keyword_pattern, keyword_pattern])
215
246
 
216
247
  query += "ORDER BY e.found_at DESC"