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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +9526 -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 +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 +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 +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 +854 -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 +173 -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 +223 -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 +22827 -10678
  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-2.43.34.dist-info}/METADATA +1 -1
  353. souleyez-2.43.34.dist-info/RECORD +443 -0
  354. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/WHEEL +1 -1
  355. souleyez-2.43.29.dist-info/RECORD +0 -379
  356. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/entry_points.txt +0 -0
  357. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/licenses/LICENSE +0 -0
  358. {souleyez-2.43.29.dist-info → souleyez-2.43.34.dist-info}/top_level.txt +0 -0
@@ -28,7 +28,7 @@ class CredentialTester:
28
28
  service: str,
29
29
  username: str,
30
30
  password: str,
31
- protocol: str = 'tcp'
31
+ protocol: str = "tcp",
32
32
  ) -> Dict:
33
33
  """
34
34
  Test a single credential against a service.
@@ -45,44 +45,44 @@ class CredentialTester:
45
45
  Dict with test results
46
46
  """
47
47
  result = {
48
- 'host': host,
49
- 'port': port,
50
- 'service': service,
51
- 'username': username,
52
- 'status': 'unknown',
53
- 'message': '',
54
- 'tested_at': None
48
+ "host": host,
49
+ "port": port,
50
+ "service": service,
51
+ "username": username,
52
+ "status": "unknown",
53
+ "message": "",
54
+ "tested_at": None,
55
55
  }
56
56
 
57
57
  # Check if port is open first
58
58
  if not self._check_port(host, port, protocol):
59
- result['status'] = 'port_closed'
60
- result['message'] = f"Port {port}/{protocol} is not open"
59
+ result["status"] = "port_closed"
60
+ result["message"] = f"Port {port}/{protocol} is not open"
61
61
  return result
62
62
 
63
63
  # Route to appropriate tester
64
64
  service_lower = service.lower()
65
65
 
66
- if service_lower in ['ssh', 'ssh-2']:
66
+ if service_lower in ["ssh", "ssh-2"]:
67
67
  return self._test_ssh(host, port, username, password)
68
- elif service_lower in ['smb', 'microsoft-ds', 'netbios-ssn']:
68
+ elif service_lower in ["smb", "microsoft-ds", "netbios-ssn"]:
69
69
  return self._test_smb(host, username, password)
70
- elif service_lower in ['mysql', 'mariadb']:
70
+ elif service_lower in ["mysql", "mariadb"]:
71
71
  return self._test_mysql(host, port, username, password)
72
- elif service_lower in ['postgresql', 'postgres']:
72
+ elif service_lower in ["postgresql", "postgres"]:
73
73
  return self._test_postgresql(host, port, username, password)
74
- elif service_lower in ['rdp', 'ms-wbt-server', 'terminal-server']:
74
+ elif service_lower in ["rdp", "ms-wbt-server", "terminal-server"]:
75
75
  return self._test_rdp(host, port, username, password)
76
- elif service_lower in ['ftp', 'ftps']:
76
+ elif service_lower in ["ftp", "ftps"]:
77
77
  return self._test_ftp(host, port, username, password)
78
- elif service_lower in ['telnet']:
78
+ elif service_lower in ["telnet"]:
79
79
  return self._test_telnet(host, port, username, password)
80
80
  else:
81
- result['status'] = 'unsupported'
82
- result['message'] = f"Service '{service}' testing not yet supported"
81
+ result["status"] = "unsupported"
82
+ result["message"] = f"Service '{service}' testing not yet supported"
83
83
  return result
84
84
 
85
- def _check_port(self, host: str, port: int, protocol: str = 'tcp') -> bool:
85
+ def _check_port(self, host: str, port: int, protocol: str = "tcp") -> bool:
86
86
  """Check if a port is open."""
87
87
  try:
88
88
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -96,315 +96,324 @@ class CredentialTester:
96
96
  def _test_ssh(self, host: str, port: int, username: str, password: str) -> Dict:
97
97
  """Test SSH credentials using sshpass."""
98
98
  result = {
99
- 'host': host,
100
- 'port': port,
101
- 'service': 'ssh',
102
- 'username': username,
103
- 'status': 'unknown',
104
- 'message': ''
99
+ "host": host,
100
+ "port": port,
101
+ "service": "ssh",
102
+ "username": username,
103
+ "status": "unknown",
104
+ "message": "",
105
105
  }
106
106
 
107
107
  try:
108
108
  # Use sshpass with ssh
109
109
  cmd = [
110
- 'sshpass', '-p', password,
111
- 'ssh',
112
- '-o', 'StrictHostKeyChecking=no',
113
- '-o', 'UserKnownHostsFile=/dev/null',
114
- '-o', f'ConnectTimeout={self.timeout}',
115
- '-p', str(port),
116
- f'{username}@{host}',
117
- 'echo "SUCCESS"'
110
+ "sshpass",
111
+ "-p",
112
+ password,
113
+ "ssh",
114
+ "-o",
115
+ "StrictHostKeyChecking=no",
116
+ "-o",
117
+ "UserKnownHostsFile=/dev/null",
118
+ "-o",
119
+ f"ConnectTimeout={self.timeout}",
120
+ "-p",
121
+ str(port),
122
+ f"{username}@{host}",
123
+ 'echo "SUCCESS"',
118
124
  ]
119
125
 
120
126
  proc = subprocess.run(
121
- cmd,
122
- capture_output=True,
123
- timeout=self.timeout + 5,
124
- text=True
127
+ cmd, capture_output=True, timeout=self.timeout + 5, text=True
125
128
  )
126
129
 
127
- if 'SUCCESS' in proc.stdout:
128
- result['status'] = 'valid'
129
- result['message'] = 'Authentication successful'
130
- elif 'Permission denied' in proc.stderr:
131
- result['status'] = 'invalid'
132
- result['message'] = 'Invalid credentials'
130
+ if "SUCCESS" in proc.stdout:
131
+ result["status"] = "valid"
132
+ result["message"] = "Authentication successful"
133
+ elif "Permission denied" in proc.stderr:
134
+ result["status"] = "invalid"
135
+ result["message"] = "Invalid credentials"
133
136
  else:
134
- result['status'] = 'error'
135
- result['message'] = f'Error: {proc.stderr[:100]}'
137
+ result["status"] = "error"
138
+ result["message"] = f"Error: {proc.stderr[:100]}"
136
139
 
137
140
  except FileNotFoundError:
138
- result['status'] = 'error'
139
- result['message'] = 'sshpass not installed (apt install sshpass)'
141
+ result["status"] = "error"
142
+ result["message"] = "sshpass not installed (apt install sshpass)"
140
143
  except subprocess.TimeoutExpired:
141
- result['status'] = 'timeout'
142
- result['message'] = 'Connection timeout'
144
+ result["status"] = "timeout"
145
+ result["message"] = "Connection timeout"
143
146
  except Exception as e:
144
- result['status'] = 'error'
145
- result['message'] = f'Error: {str(e)[:100]}'
147
+ result["status"] = "error"
148
+ result["message"] = f"Error: {str(e)[:100]}"
146
149
 
147
150
  return result
148
151
 
149
152
  def _test_smb(self, host: str, username: str, password: str) -> Dict:
150
153
  """Test SMB credentials using smbclient."""
151
154
  result = {
152
- 'host': host,
153
- 'port': 445,
154
- 'service': 'smb',
155
- 'username': username,
156
- 'status': 'unknown',
157
- 'message': ''
155
+ "host": host,
156
+ "port": 445,
157
+ "service": "smb",
158
+ "username": username,
159
+ "status": "unknown",
160
+ "message": "",
158
161
  }
159
162
 
160
163
  try:
161
164
  # Use smbclient to test
162
165
  cmd = [
163
- 'smbclient',
164
- f'//{host}/IPC$',
165
- '-U', f'{username}%{password}',
166
- '-c', 'quit'
166
+ "smbclient",
167
+ f"//{host}/IPC$",
168
+ "-U",
169
+ f"{username}%{password}",
170
+ "-c",
171
+ "quit",
167
172
  ]
168
173
 
169
174
  proc = subprocess.run(
170
- cmd,
171
- capture_output=True,
172
- timeout=self.timeout + 5,
173
- text=True
175
+ cmd, capture_output=True, timeout=self.timeout + 5, text=True
174
176
  )
175
177
 
176
178
  if proc.returncode == 0:
177
- result['status'] = 'valid'
178
- result['message'] = 'Authentication successful'
179
- elif 'NT_STATUS_LOGON_FAILURE' in proc.stderr:
180
- result['status'] = 'invalid'
181
- result['message'] = 'Invalid credentials'
182
- elif 'NT_STATUS_ACCOUNT_DISABLED' in proc.stderr:
183
- result['status'] = 'account_disabled'
184
- result['message'] = 'Account is disabled'
179
+ result["status"] = "valid"
180
+ result["message"] = "Authentication successful"
181
+ elif "NT_STATUS_LOGON_FAILURE" in proc.stderr:
182
+ result["status"] = "invalid"
183
+ result["message"] = "Invalid credentials"
184
+ elif "NT_STATUS_ACCOUNT_DISABLED" in proc.stderr:
185
+ result["status"] = "account_disabled"
186
+ result["message"] = "Account is disabled"
185
187
  else:
186
- result['status'] = 'error'
187
- result['message'] = f'Error: {proc.stderr[:100]}'
188
+ result["status"] = "error"
189
+ result["message"] = f"Error: {proc.stderr[:100]}"
188
190
 
189
191
  except FileNotFoundError:
190
- result['status'] = 'error'
191
- result['message'] = 'smbclient not installed (apt install smbclient)'
192
+ result["status"] = "error"
193
+ result["message"] = "smbclient not installed (apt install smbclient)"
192
194
  except subprocess.TimeoutExpired:
193
- result['status'] = 'timeout'
194
- result['message'] = 'Connection timeout'
195
+ result["status"] = "timeout"
196
+ result["message"] = "Connection timeout"
195
197
  except Exception as e:
196
- result['status'] = 'error'
197
- result['message'] = f'Error: {str(e)[:100]}'
198
+ result["status"] = "error"
199
+ result["message"] = f"Error: {str(e)[:100]}"
198
200
 
199
201
  return result
200
202
 
201
203
  def _test_mysql(self, host: str, port: int, username: str, password: str) -> Dict:
202
204
  """Test MySQL credentials."""
203
205
  result = {
204
- 'host': host,
205
- 'port': port,
206
- 'service': 'mysql',
207
- 'username': username,
208
- 'status': 'unknown',
209
- 'message': ''
206
+ "host": host,
207
+ "port": port,
208
+ "service": "mysql",
209
+ "username": username,
210
+ "status": "unknown",
211
+ "message": "",
210
212
  }
211
213
 
212
214
  try:
213
215
  cmd = [
214
- 'mysql',
215
- '-h', host,
216
- '-P', str(port),
217
- '-u', username,
218
- f'-p{password}',
219
- '-e', 'SELECT 1;'
216
+ "mysql",
217
+ "-h",
218
+ host,
219
+ "-P",
220
+ str(port),
221
+ "-u",
222
+ username,
223
+ f"-p{password}",
224
+ "-e",
225
+ "SELECT 1;",
220
226
  ]
221
227
 
222
228
  proc = subprocess.run(
223
- cmd,
224
- capture_output=True,
225
- timeout=self.timeout + 5,
226
- text=True
229
+ cmd, capture_output=True, timeout=self.timeout + 5, text=True
227
230
  )
228
231
 
229
232
  if proc.returncode == 0:
230
- result['status'] = 'valid'
231
- result['message'] = 'Authentication successful'
232
- elif 'Access denied' in proc.stderr:
233
- result['status'] = 'invalid'
234
- result['message'] = 'Invalid credentials'
233
+ result["status"] = "valid"
234
+ result["message"] = "Authentication successful"
235
+ elif "Access denied" in proc.stderr:
236
+ result["status"] = "invalid"
237
+ result["message"] = "Invalid credentials"
235
238
  else:
236
- result['status'] = 'error'
237
- result['message'] = f'Error: {proc.stderr[:100]}'
239
+ result["status"] = "error"
240
+ result["message"] = f"Error: {proc.stderr[:100]}"
238
241
 
239
242
  except FileNotFoundError:
240
- result['status'] = 'error'
241
- result['message'] = 'mysql client not installed (apt install mysql-client)'
243
+ result["status"] = "error"
244
+ result["message"] = "mysql client not installed (apt install mysql-client)"
242
245
  except subprocess.TimeoutExpired:
243
- result['status'] = 'timeout'
244
- result['message'] = 'Connection timeout'
246
+ result["status"] = "timeout"
247
+ result["message"] = "Connection timeout"
245
248
  except Exception as e:
246
- result['status'] = 'error'
247
- result['message'] = f'Error: {str(e)[:100]}'
249
+ result["status"] = "error"
250
+ result["message"] = f"Error: {str(e)[:100]}"
248
251
 
249
252
  return result
250
253
 
251
- def _test_postgresql(self, host: str, port: int, username: str, password: str) -> Dict:
254
+ def _test_postgresql(
255
+ self, host: str, port: int, username: str, password: str
256
+ ) -> Dict:
252
257
  """Test PostgreSQL credentials."""
253
258
  result = {
254
- 'host': host,
255
- 'port': port,
256
- 'service': 'postgresql',
257
- 'username': username,
258
- 'status': 'unknown',
259
- 'message': ''
259
+ "host": host,
260
+ "port": port,
261
+ "service": "postgresql",
262
+ "username": username,
263
+ "status": "unknown",
264
+ "message": "",
260
265
  }
261
266
 
262
267
  try:
263
268
  # Set PGPASSWORD environment variable
264
269
  import os
270
+
265
271
  env = os.environ.copy()
266
- env['PGPASSWORD'] = password
272
+ env["PGPASSWORD"] = password
267
273
 
268
274
  cmd = [
269
- 'psql',
270
- '-h', host,
271
- '-p', str(port),
272
- '-U', username,
273
- '-d', 'postgres',
274
- '-c', 'SELECT 1;'
275
+ "psql",
276
+ "-h",
277
+ host,
278
+ "-p",
279
+ str(port),
280
+ "-U",
281
+ username,
282
+ "-d",
283
+ "postgres",
284
+ "-c",
285
+ "SELECT 1;",
275
286
  ]
276
287
 
277
288
  proc = subprocess.run(
278
- cmd,
279
- capture_output=True,
280
- timeout=self.timeout + 5,
281
- text=True,
282
- env=env
289
+ cmd, capture_output=True, timeout=self.timeout + 5, text=True, env=env
283
290
  )
284
291
 
285
292
  if proc.returncode == 0:
286
- result['status'] = 'valid'
287
- result['message'] = 'Authentication successful'
288
- elif 'authentication failed' in proc.stderr.lower():
289
- result['status'] = 'invalid'
290
- result['message'] = 'Invalid credentials'
293
+ result["status"] = "valid"
294
+ result["message"] = "Authentication successful"
295
+ elif "authentication failed" in proc.stderr.lower():
296
+ result["status"] = "invalid"
297
+ result["message"] = "Invalid credentials"
291
298
  else:
292
- result['status'] = 'error'
293
- result['message'] = f'Error: {proc.stderr[:100]}'
299
+ result["status"] = "error"
300
+ result["message"] = f"Error: {proc.stderr[:100]}"
294
301
 
295
302
  except FileNotFoundError:
296
- result['status'] = 'error'
297
- result['message'] = 'psql not installed (apt install postgresql-client)'
303
+ result["status"] = "error"
304
+ result["message"] = "psql not installed (apt install postgresql-client)"
298
305
  except subprocess.TimeoutExpired:
299
- result['status'] = 'timeout'
300
- result['message'] = 'Connection timeout'
306
+ result["status"] = "timeout"
307
+ result["message"] = "Connection timeout"
301
308
  except Exception as e:
302
- result['status'] = 'error'
303
- result['message'] = f'Error: {str(e)[:100]}'
309
+ result["status"] = "error"
310
+ result["message"] = f"Error: {str(e)[:100]}"
304
311
 
305
312
  return result
306
313
 
307
314
  def _test_rdp(self, host: str, port: int, username: str, password: str) -> Dict:
308
315
  """Test RDP credentials using xfreerdp."""
309
316
  result = {
310
- 'host': host,
311
- 'port': port,
312
- 'service': 'rdp',
313
- 'username': username,
314
- 'status': 'unknown',
315
- 'message': ''
317
+ "host": host,
318
+ "port": port,
319
+ "service": "rdp",
320
+ "username": username,
321
+ "status": "unknown",
322
+ "message": "",
316
323
  }
317
324
 
318
325
  try:
319
326
  cmd = [
320
- 'xfreerdp',
321
- f'/v:{host}:{port}',
322
- f'/u:{username}',
323
- f'/p:{password}',
324
- '/cert:ignore',
325
- '+auth-only',
326
- '/timeout:5000'
327
+ "xfreerdp",
328
+ f"/v:{host}:{port}",
329
+ f"/u:{username}",
330
+ f"/p:{password}",
331
+ "/cert:ignore",
332
+ "+auth-only",
333
+ "/timeout:5000",
327
334
  ]
328
335
 
329
336
  proc = subprocess.run(
330
- cmd,
331
- capture_output=True,
332
- timeout=self.timeout + 5,
333
- text=True
337
+ cmd, capture_output=True, timeout=self.timeout + 5, text=True
334
338
  )
335
339
 
336
340
  # xfreerdp returns 0 on successful auth
337
341
  if proc.returncode == 0:
338
- result['status'] = 'valid'
339
- result['message'] = 'Authentication successful'
340
- elif 'Authentication failure' in proc.stderr or 'ERRCONNECT_LOGON_FAILURE' in proc.stderr:
341
- result['status'] = 'invalid'
342
- result['message'] = 'Invalid credentials'
342
+ result["status"] = "valid"
343
+ result["message"] = "Authentication successful"
344
+ elif (
345
+ "Authentication failure" in proc.stderr
346
+ or "ERRCONNECT_LOGON_FAILURE" in proc.stderr
347
+ ):
348
+ result["status"] = "invalid"
349
+ result["message"] = "Invalid credentials"
343
350
  else:
344
- result['status'] = 'error'
345
- result['message'] = f'Error: {proc.stderr[:100]}'
351
+ result["status"] = "error"
352
+ result["message"] = f"Error: {proc.stderr[:100]}"
346
353
 
347
354
  except FileNotFoundError:
348
- result['status'] = 'error'
349
- result['message'] = 'xfreerdp not installed (apt install freerdp2-x11)'
355
+ result["status"] = "error"
356
+ result["message"] = "xfreerdp not installed (apt install freerdp2-x11)"
350
357
  except subprocess.TimeoutExpired:
351
- result['status'] = 'timeout'
352
- result['message'] = 'Connection timeout'
358
+ result["status"] = "timeout"
359
+ result["message"] = "Connection timeout"
353
360
  except Exception as e:
354
- result['status'] = 'error'
355
- result['message'] = f'Error: {str(e)[:100]}'
361
+ result["status"] = "error"
362
+ result["message"] = f"Error: {str(e)[:100]}"
356
363
 
357
364
  return result
358
365
 
359
366
  def _test_ftp(self, host: str, port: int, username: str, password: str) -> Dict:
360
367
  """Test FTP credentials."""
361
368
  result = {
362
- 'host': host,
363
- 'port': port,
364
- 'service': 'ftp',
365
- 'username': username,
366
- 'status': 'unknown',
367
- 'message': ''
369
+ "host": host,
370
+ "port": port,
371
+ "service": "ftp",
372
+ "username": username,
373
+ "status": "unknown",
374
+ "message": "",
368
375
  }
369
376
 
370
377
  try:
371
378
  from ftplib import FTP # nosec B402 - Intentionally testing FTP credentials
372
379
 
373
- ftp = FTP() # nosec B321 - Penetration testing tool, testing insecure protocols
380
+ ftp = FTP() # nosec B321 - Penetration testing tool, FTP cred testing
374
381
  ftp.connect(host, port, timeout=self.timeout)
375
382
  ftp.login(username, password)
376
383
  ftp.quit()
377
384
 
378
- result['status'] = 'valid'
379
- result['message'] = 'Authentication successful'
385
+ result["status"] = "valid"
386
+ result["message"] = "Authentication successful"
380
387
 
381
388
  except Exception as e:
382
389
  error_str = str(e).lower()
383
- if '530' in error_str or 'login' in error_str:
384
- result['status'] = 'invalid'
385
- result['message'] = 'Invalid credentials'
386
- elif 'timeout' in error_str:
387
- result['status'] = 'timeout'
388
- result['message'] = 'Connection timeout'
390
+ if "530" in error_str or "login" in error_str:
391
+ result["status"] = "invalid"
392
+ result["message"] = "Invalid credentials"
393
+ elif "timeout" in error_str:
394
+ result["status"] = "timeout"
395
+ result["message"] = "Connection timeout"
389
396
  else:
390
- result['status'] = 'error'
391
- result['message'] = f'Error: {str(e)[:100]}'
397
+ result["status"] = "error"
398
+ result["message"] = f"Error: {str(e)[:100]}"
392
399
 
393
400
  return result
394
401
 
395
402
  def _test_telnet(self, host: str, port: int, username: str, password: str) -> Dict:
396
403
  """Test Telnet credentials."""
397
404
  result = {
398
- 'host': host,
399
- 'port': port,
400
- 'service': 'telnet',
401
- 'username': username,
402
- 'status': 'unsupported',
403
- 'message': 'Telnet testing requires interactive session (not yet implemented)'
405
+ "host": host,
406
+ "port": port,
407
+ "service": "telnet",
408
+ "username": username,
409
+ "status": "unsupported",
410
+ "message": "Telnet testing requires interactive session (not yet implemented)",
404
411
  }
405
412
  return result
406
413
 
407
- def batch_test(self, credentials: List[Dict], services: List[Dict], verbose: bool = False) -> List[Dict]:
414
+ def batch_test(
415
+ self, credentials: List[Dict], services: List[Dict], verbose: bool = False
416
+ ) -> List[Dict]:
408
417
  """
409
418
  Batch test credentials against multiple services.
410
419
 
@@ -421,28 +430,35 @@ class CredentialTester:
421
430
  current = 0
422
431
 
423
432
  for cred in credentials:
424
- username = cred.get('username')
425
- password = cred.get('password')
433
+ username = cred.get("username")
434
+ password = cred.get("password")
426
435
 
427
436
  if not username or not password:
428
437
  continue
429
438
 
430
439
  for svc in services:
431
440
  current += 1
432
- host = svc.get('host') or svc.get('ip_address')
433
- port = svc.get('port')
434
- service = svc.get('service') or svc.get('service_name')
441
+ host = svc.get("host") or svc.get("ip_address")
442
+ port = svc.get("port")
443
+ service = svc.get("service") or svc.get("service_name")
435
444
 
436
445
  if not all([host, port, service]):
437
446
  continue
438
447
 
439
448
  if verbose:
440
- click.echo(f"[{current}/{total}] Testing {username} @ {host}:{port} ({service})")
449
+ click.echo(
450
+ f"[{current}/{total}] Testing {username} @ {host}:{port} ({service})"
451
+ )
441
452
 
442
453
  result = self.test_credential(host, port, service, username, password)
443
454
  results.append(result)
444
455
 
445
- if verbose and result['status'] == 'valid':
446
- click.echo(click.style(f" ✓ Valid: {username}:{password} @ {host}:{port}", fg='green'))
456
+ if verbose and result["status"] == "valid":
457
+ click.echo(
458
+ click.style(
459
+ f" ✓ Valid: {username}:{password} @ {host}:{port}",
460
+ fg="green",
461
+ )
462
+ )
447
463
 
448
464
  return results
souleyez/ui/__init__.py CHANGED
@@ -5,4 +5,4 @@ souleyez.ui - User interface components
5
5
  from .interactive import run_interactive_menu
6
6
  from .dashboard import run_dashboard
7
7
 
8
- __all__ = ['run_interactive_menu', 'run_dashboard']
8
+ __all__ = ["run_interactive_menu", "run_dashboard"]