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
@@ -51,56 +51,58 @@ def parse_nikto_output(output: str, target: str = "") -> Dict[str, Any]:
51
51
  }
52
52
  """
53
53
  result = {
54
- 'target': target,
55
- 'target_ip': '',
56
- 'target_hostname': '',
57
- 'target_port': 80,
58
- 'server': '',
59
- 'findings': [],
60
- 'stats': {
61
- 'total': 0,
62
- 'by_severity': {'high': 0, 'medium': 0, 'low': 0, 'info': 0}
63
- }
54
+ "target": target,
55
+ "target_ip": "",
56
+ "target_hostname": "",
57
+ "target_port": 80,
58
+ "server": "",
59
+ "findings": [],
60
+ "stats": {
61
+ "total": 0,
62
+ "by_severity": {"high": 0, "medium": 0, "low": 0, "info": 0},
63
+ },
64
64
  }
65
65
 
66
- lines = output.split('\n')
66
+ lines = output.split("\n")
67
67
 
68
68
  for line in lines:
69
69
  line = line.strip()
70
70
 
71
71
  # Skip empty lines and dividers
72
- if not line or line.startswith('---') or line.startswith('==='):
72
+ if not line or line.startswith("---") or line.startswith("==="):
73
73
  continue
74
74
 
75
75
  # Parse target info
76
- if line.startswith('+ Target IP:'):
77
- match = re.search(r'\+ Target IP:\s+(.+)', line)
76
+ if line.startswith("+ Target IP:"):
77
+ match = re.search(r"\+ Target IP:\s+(.+)", line)
78
78
  if match:
79
- result['target_ip'] = match.group(1).strip()
79
+ result["target_ip"] = match.group(1).strip()
80
80
 
81
- elif line.startswith('+ Target Hostname:'):
82
- match = re.search(r'\+ Target Hostname:\s+(.+)', line)
81
+ elif line.startswith("+ Target Hostname:"):
82
+ match = re.search(r"\+ Target Hostname:\s+(.+)", line)
83
83
  if match:
84
- result['target_hostname'] = match.group(1).strip()
84
+ result["target_hostname"] = match.group(1).strip()
85
85
 
86
- elif line.startswith('+ Target Port:'):
87
- match = re.search(r'\+ Target Port:\s+(\d+)', line)
86
+ elif line.startswith("+ Target Port:"):
87
+ match = re.search(r"\+ Target Port:\s+(\d+)", line)
88
88
  if match:
89
- result['target_port'] = int(match.group(1))
89
+ result["target_port"] = int(match.group(1))
90
90
 
91
- elif line.startswith('+ Server:'):
92
- match = re.search(r'\+ Server:\s+(.+)', line)
91
+ elif line.startswith("+ Server:"):
92
+ match = re.search(r"\+ Server:\s+(.+)", line)
93
93
  if match:
94
- result['server'] = match.group(1).strip()
94
+ result["server"] = match.group(1).strip()
95
95
 
96
96
  # Parse findings (any line starting with + that isn't metadata)
97
- elif line.startswith('+'):
97
+ elif line.startswith("+"):
98
98
  finding = _parse_finding_line(line)
99
99
  if finding:
100
- result['findings'].append(finding)
101
- severity = finding.get('severity', 'info')
102
- result['stats']['by_severity'][severity] = result['stats']['by_severity'].get(severity, 0) + 1
103
- result['stats']['total'] += 1
100
+ result["findings"].append(finding)
101
+ severity = finding.get("severity", "info")
102
+ result["stats"]["by_severity"][severity] = (
103
+ result["stats"]["by_severity"].get(severity, 0) + 1
104
+ )
105
+ result["stats"]["total"] += 1
104
106
 
105
107
  return result
106
108
 
@@ -116,54 +118,54 @@ def _parse_finding_line(line: str) -> Dict[str, Any]:
116
118
  + Server: Apache/2.4.41 (Ubuntu) <- Skip these
117
119
  """
118
120
  # Skip metadata lines
119
- if line.startswith('+ Server:') or line.startswith('+ Start Time:'):
121
+ if line.startswith("+ Server:") or line.startswith("+ Start Time:"):
120
122
  return None
121
- if line.startswith('+ Target'):
123
+ if line.startswith("+ Target"):
122
124
  return None
123
- if line.startswith('+ End Time:'):
125
+ if line.startswith("+ End Time:"):
124
126
  return None
125
- if line.startswith('+ No CGI'):
127
+ if line.startswith("+ No CGI"):
126
128
  return None
127
- if 'host(s) tested' in line:
129
+ if "host(s) tested" in line:
128
130
  return None
129
- if 'items checked:' in line:
131
+ if "items checked:" in line:
130
132
  return None
131
133
 
132
134
  try:
133
135
  # Remove leading +
134
- content = line.lstrip('+ ').strip()
136
+ content = line.lstrip("+ ").strip()
135
137
 
136
138
  osvdb = None
137
- path = ''
138
- description = ''
139
+ path = ""
140
+ description = ""
139
141
 
140
142
  # Check for OSVDB reference
141
- osvdb_match = re.match(r'(OSVDB-\d+):\s*(.+)', content)
143
+ osvdb_match = re.match(r"(OSVDB-\d+):\s*(.+)", content)
142
144
  if osvdb_match:
143
145
  osvdb = osvdb_match.group(1)
144
146
  content = osvdb_match.group(2)
145
147
 
146
148
  # Extract path and description
147
149
  # Format: /path/: Description or /path: Description
148
- path_match = re.match(r'(/[^:]*):?\s*(.+)', content)
150
+ path_match = re.match(r"(/[^:]*):?\s*(.+)", content)
149
151
  if path_match:
150
- path = path_match.group(1).rstrip(':').strip()
152
+ path = path_match.group(1).rstrip(":").strip()
151
153
  description = path_match.group(2).strip()
152
154
  else:
153
155
  description = content
154
156
 
155
157
  # Skip if no meaningful content
156
- if not description or description.startswith('Target'):
158
+ if not description or description.startswith("Target"):
157
159
  return None
158
160
 
159
161
  # Determine severity based on keywords
160
162
  severity = _determine_severity(description, osvdb)
161
163
 
162
164
  return {
163
- 'osvdb': osvdb,
164
- 'path': path,
165
- 'description': description,
166
- 'severity': severity
165
+ "osvdb": osvdb,
166
+ "path": path,
167
+ "description": description,
168
+ "severity": severity,
167
169
  }
168
170
 
169
171
  except Exception:
@@ -178,52 +180,331 @@ def _determine_severity(description: str, osvdb: str = None) -> str:
178
180
 
179
181
  # High severity indicators
180
182
  high_keywords = [
181
- 'remote code execution', 'rce', 'command execution', 'shell',
182
- 'sql injection', 'file inclusion', 'lfi', 'rfi',
183
- 'arbitrary file', 'password', 'credentials',
184
- 'authentication bypass', 'backdoor'
183
+ "remote code execution",
184
+ "rce",
185
+ "command execution",
186
+ "shell",
187
+ "sql injection",
188
+ "file inclusion",
189
+ "lfi",
190
+ "rfi",
191
+ "arbitrary file",
192
+ "password",
193
+ "credentials",
194
+ "authentication bypass",
195
+ "backdoor",
185
196
  ]
186
197
  for keyword in high_keywords:
187
198
  if keyword in desc_lower:
188
- return 'high'
199
+ return "high"
189
200
 
190
201
  # Medium severity indicators
191
202
  medium_keywords = [
192
- 'directory indexing', 'directory listing', 'backup file',
193
- 'config file', 'sensitive', 'exposure', 'disclosure',
194
- 'xss', 'cross-site', 'injection', 'traversal',
195
- 'default', 'admin', '.bak', '.old', '.swp'
203
+ "directory indexing",
204
+ "directory listing",
205
+ "backup file",
206
+ "config file",
207
+ "sensitive",
208
+ "exposure",
209
+ "disclosure",
210
+ "xss",
211
+ "cross-site",
212
+ "injection",
213
+ "traversal",
214
+ "default",
215
+ "admin",
216
+ ".bak",
217
+ ".old",
218
+ ".swp",
196
219
  ]
197
220
  for keyword in medium_keywords:
198
221
  if keyword in desc_lower:
199
- return 'medium'
222
+ return "medium"
200
223
 
201
224
  # Low severity indicators
202
225
  low_keywords = [
203
- 'header', 'x-frame', 'x-content-type', 'x-xss',
204
- 'cookie', 'httponly', 'secure flag', 'hsts',
205
- 'content-security-policy', 'csp', 'clickjacking'
226
+ "header",
227
+ "x-frame",
228
+ "x-content-type",
229
+ "x-xss",
230
+ "cookie",
231
+ "httponly",
232
+ "secure flag",
233
+ "hsts",
234
+ "content-security-policy",
235
+ "csp",
236
+ "clickjacking",
206
237
  ]
207
238
  for keyword in low_keywords:
208
239
  if keyword in desc_lower:
209
- return 'low'
240
+ return "low"
210
241
 
211
242
  # OSVDB references often indicate real issues
212
243
  if osvdb:
213
- return 'medium'
244
+ return "medium"
214
245
 
215
- return 'info'
246
+ return "info"
216
247
 
217
248
 
218
- def get_findings_by_severity(parsed: Dict[str, Any], severity: str) -> List[Dict[str, Any]]:
249
+ def get_findings_by_severity(
250
+ parsed: Dict[str, Any], severity: str
251
+ ) -> List[Dict[str, Any]]:
219
252
  """
220
253
  Filter findings by severity level.
221
254
  """
222
- return [f for f in parsed.get('findings', []) if f.get('severity') == severity]
255
+ return [f for f in parsed.get("findings", []) if f.get("severity") == severity]
223
256
 
224
257
 
225
258
  def get_high_value_findings(parsed: Dict[str, Any]) -> List[Dict[str, Any]]:
226
259
  """
227
260
  Get findings that are high or medium severity.
228
261
  """
229
- return [f for f in parsed.get('findings', []) if f.get('severity') in ('high', 'medium')]
262
+ return [
263
+ f for f in parsed.get("findings", []) if f.get("severity") in ("high", "medium")
264
+ ]
265
+
266
+
267
+ def generate_next_steps(
268
+ parsed: Dict[str, Any], target: str = ""
269
+ ) -> List[Dict[str, Any]]:
270
+ """
271
+ Generate suggested next steps based on nikto findings.
272
+
273
+ Translates cryptic OSVDB references and generic findings into
274
+ actionable exploitation steps.
275
+
276
+ Args:
277
+ parsed: Output from parse_nikto_output()
278
+ target: Target URL for command examples
279
+
280
+ Returns:
281
+ List of next step dicts with title, commands, reason
282
+ """
283
+ next_steps = []
284
+ findings = parsed.get("findings", [])
285
+ base_url = target.rstrip("/") or f"http://{parsed.get('target_hostname', 'target')}"
286
+
287
+ if not findings:
288
+ return next_steps
289
+
290
+ # Categorize findings
291
+ dir_indexing = []
292
+ backup_files = []
293
+ config_exposure = []
294
+ outdated_server = []
295
+ missing_headers = []
296
+ cgi_vulns = []
297
+ file_inclusion = []
298
+ injection_vulns = []
299
+ auth_issues = []
300
+
301
+ server = parsed.get("server", "")
302
+
303
+ for finding in findings:
304
+ desc = finding.get("description", "").lower()
305
+ path = finding.get("path", "")
306
+ osvdb = finding.get("osvdb", "")
307
+ severity = finding.get("severity", "info")
308
+
309
+ # Directory indexing
310
+ if "directory indexing" in desc or "directory listing" in desc:
311
+ dir_indexing.append({"path": path, "osvdb": osvdb})
312
+ # Backup files
313
+ elif any(
314
+ kw in desc
315
+ for kw in ["backup", ".bak", ".old", ".orig", ".save", "configuration file"]
316
+ ):
317
+ backup_files.append({"path": path, "desc": finding.get("description", "")})
318
+ # Config files
319
+ elif any(
320
+ kw in desc
321
+ for kw in ["config", "phpinfo", ".htaccess", ".htpasswd", "web.config"]
322
+ ):
323
+ config_exposure.append(
324
+ {"path": path, "desc": finding.get("description", "")}
325
+ )
326
+ # Outdated server
327
+ elif "outdated" in desc or "appears to be" in desc:
328
+ outdated_server.append(
329
+ {"desc": finding.get("description", ""), "server": server}
330
+ )
331
+ # Missing security headers
332
+ elif any(
333
+ kw in desc
334
+ for kw in [
335
+ "x-frame",
336
+ "x-xss",
337
+ "x-content-type",
338
+ "httponly",
339
+ "secure flag",
340
+ "hsts",
341
+ "csp",
342
+ ]
343
+ ):
344
+ missing_headers.append({"desc": finding.get("description", "")})
345
+ # CGI vulnerabilities
346
+ elif "/cgi-bin/" in path or ".cgi" in path or "cgi" in desc:
347
+ cgi_vulns.append(
348
+ {"path": path, "desc": finding.get("description", ""), "osvdb": osvdb}
349
+ )
350
+ # File inclusion
351
+ elif any(
352
+ kw in desc
353
+ for kw in ["file inclusion", "lfi", "rfi", "traversal", "arbitrary file"]
354
+ ):
355
+ file_inclusion.append(
356
+ {"path": path, "desc": finding.get("description", ""), "osvdb": osvdb}
357
+ )
358
+ # Injection
359
+ elif any(kw in desc for kw in ["injection", "xss", "sql", "command execution"]):
360
+ injection_vulns.append(
361
+ {"path": path, "desc": finding.get("description", ""), "osvdb": osvdb}
362
+ )
363
+ # Auth issues
364
+ elif any(
365
+ kw in desc
366
+ for kw in ["authentication", "bypass", "default", "password", "credential"]
367
+ ):
368
+ auth_issues.append({"path": path, "desc": finding.get("description", "")})
369
+
370
+ # Directory indexing - browse for sensitive files
371
+ if dir_indexing:
372
+ paths = [d["path"] for d in dir_indexing[:3]]
373
+ next_steps.append(
374
+ {
375
+ "title": "Browse indexed directories for sensitive files",
376
+ "commands": [f'curl -s "{base_url}{p}"' for p in paths]
377
+ + [f"# Look for: passwords, configs, source code, database files"],
378
+ "reason": f"Found {len(dir_indexing)} directory with indexing enabled - may expose sensitive files",
379
+ }
380
+ )
381
+
382
+ # Backup files - download and analyze
383
+ if backup_files:
384
+ next_steps.append(
385
+ {
386
+ "title": "Download and review backup files",
387
+ "commands": [
388
+ f'curl -s "{base_url}{b["path"]}" -o backup_file'
389
+ for b in backup_files[:3]
390
+ ],
391
+ "reason": f"Found {len(backup_files)} backup file(s) - may contain source code, credentials",
392
+ }
393
+ )
394
+
395
+ # Config exposure - extract credentials
396
+ if config_exposure:
397
+ next_steps.append(
398
+ {
399
+ "title": "Extract credentials from exposed configs",
400
+ "commands": [
401
+ f'curl -s "{base_url}{c["path"]}"' for c in config_exposure[:3]
402
+ ],
403
+ "reason": f"Found {len(config_exposure)} config file(s) - check for database passwords, API keys",
404
+ }
405
+ )
406
+
407
+ # Outdated server - searchsploit
408
+ if outdated_server or server:
409
+ server_info = (
410
+ server or outdated_server[0].get("desc", "") if outdated_server else ""
411
+ )
412
+ if server_info:
413
+ next_steps.append(
414
+ {
415
+ "title": f"Search for exploits for {server_info[:40]}",
416
+ "commands": [
417
+ f'searchsploit "{server_info}"',
418
+ f'# Or: searchsploit -w "{server_info}" for web links',
419
+ ],
420
+ "reason": f"Server version detected - check for known CVEs and public exploits",
421
+ }
422
+ )
423
+
424
+ # CGI vulnerabilities
425
+ if cgi_vulns:
426
+ cgi_path = cgi_vulns[0]["path"]
427
+ full_url = f"{base_url}{cgi_path}"
428
+ next_steps.append(
429
+ {
430
+ "title": "Test CGI scripts for command injection",
431
+ "commands": [
432
+ f'curl "{full_url}?cmd=id"',
433
+ f'curl "{full_url}?file=/etc/passwd"',
434
+ f"curl -A '() {{ :; }}; echo; /bin/id' \"{full_url}\"",
435
+ ],
436
+ "reason": f"Nikto found {len(cgi_vulns)} CGI issue(s) - test for injection and Shellshock",
437
+ }
438
+ )
439
+
440
+ # File inclusion
441
+ if file_inclusion:
442
+ lfi_path = file_inclusion[0]["path"]
443
+ next_steps.append(
444
+ {
445
+ "title": "Exploit file inclusion vulnerability",
446
+ "commands": [
447
+ f'curl "{base_url}{lfi_path}?file=../../../etc/passwd"',
448
+ f'curl "{base_url}{lfi_path}?page=php://filter/convert.base64-encode/resource=index.php"',
449
+ ],
450
+ "reason": f"File inclusion detected - test path traversal and PHP wrappers",
451
+ }
452
+ )
453
+
454
+ # Injection vulnerabilities
455
+ if injection_vulns:
456
+ inj = injection_vulns[0]
457
+ next_steps.append(
458
+ {
459
+ "title": "Test injection vulnerability",
460
+ "commands": [
461
+ f'sqlmap -u "{base_url}{inj["path"]}" --batch --risk=3 --level=5',
462
+ ],
463
+ "reason": f'Injection point found at {inj["path"]} - run automated testing',
464
+ }
465
+ )
466
+
467
+ # Auth issues
468
+ if auth_issues:
469
+ next_steps.append(
470
+ {
471
+ "title": "Test authentication bypass",
472
+ "commands": [
473
+ f"# Try: admin/admin, admin/password, root/root",
474
+ f'hydra -L data/wordlists/usernames_common.txt -P data/wordlists/top20_quick.txt {base_url.replace("http://", "").replace("https://", "").split("/")[0]} http-get /',
475
+ ],
476
+ "reason": f"Authentication issue detected - test default credentials",
477
+ }
478
+ )
479
+
480
+ # Missing headers - only include if high severity findings exist
481
+ # (headers alone are low value, but good to mention for completeness)
482
+ high_severity = [f for f in findings if f.get("severity") in ("high", "medium")]
483
+ if missing_headers and not high_severity:
484
+ next_steps.append(
485
+ {
486
+ "title": "Report missing security headers",
487
+ "commands": [
488
+ f'curl -I "{base_url}" | grep -i "x-frame\\|x-xss\\|x-content\\|strict-transport"',
489
+ ],
490
+ "reason": f"{len(missing_headers)} security header(s) missing - low risk but worth documenting",
491
+ }
492
+ )
493
+
494
+ # If OSVDB references exist, suggest looking them up
495
+ osvdb_refs = [f.get("osvdb") for f in findings if f.get("osvdb")]
496
+ if osvdb_refs:
497
+ unique_osvdb = list(set(osvdb_refs))[:3]
498
+ next_steps.append(
499
+ {
500
+ "title": "Look up OSVDB references",
501
+ "commands": [
502
+ f"# OSVDB is deprecated, use CVE/NVD instead",
503
+ f"# Search: https://cve.mitre.org/cve/search_cve_list.html",
504
+ f"searchsploit --cve <CVE-XXXX-XXXXX>",
505
+ ],
506
+ "reason": f'Found {len(unique_osvdb)} OSVDB reference(s): {", ".join(unique_osvdb)} - cross-reference with CVE database',
507
+ }
508
+ )
509
+
510
+ return next_steps