souleyez 2.43.29__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 +22783 -10678
  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.29.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.29.dist-info → souleyez-2.43.32.dist-info}/WHEEL +1 -1
  353. souleyez-2.43.29.dist-info/RECORD +0 -379
  354. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/entry_points.txt +0 -0
  355. {souleyez-2.43.29.dist-info → souleyez-2.43.32.dist-info}/licenses/LICENSE +0 -0
  356. {souleyez-2.43.29.dist-info → souleyez-2.43.32.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"]