souleyez 2.43.28__py3-none-any.whl → 2.43.32__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. souleyez/__init__.py +1 -2
  2. souleyez/ai/__init__.py +21 -15
  3. souleyez/ai/action_mapper.py +249 -150
  4. souleyez/ai/chain_advisor.py +116 -100
  5. souleyez/ai/claude_provider.py +29 -28
  6. souleyez/ai/context_builder.py +80 -62
  7. souleyez/ai/executor.py +158 -117
  8. souleyez/ai/feedback_handler.py +136 -121
  9. souleyez/ai/llm_factory.py +27 -20
  10. souleyez/ai/llm_provider.py +4 -2
  11. souleyez/ai/ollama_provider.py +6 -9
  12. souleyez/ai/ollama_service.py +44 -37
  13. souleyez/ai/path_scorer.py +91 -76
  14. souleyez/ai/recommender.py +176 -144
  15. souleyez/ai/report_context.py +74 -73
  16. souleyez/ai/report_service.py +84 -66
  17. souleyez/ai/result_parser.py +222 -229
  18. souleyez/ai/safety.py +67 -44
  19. souleyez/auth/__init__.py +23 -22
  20. souleyez/auth/audit.py +36 -26
  21. souleyez/auth/engagement_access.py +65 -48
  22. souleyez/auth/permissions.py +14 -3
  23. souleyez/auth/session_manager.py +54 -37
  24. souleyez/auth/user_manager.py +109 -64
  25. souleyez/commands/audit.py +40 -43
  26. souleyez/commands/auth.py +35 -15
  27. souleyez/commands/deliverables.py +55 -50
  28. souleyez/commands/engagement.py +47 -28
  29. souleyez/commands/license.py +32 -23
  30. souleyez/commands/screenshots.py +36 -32
  31. souleyez/commands/user.py +82 -36
  32. souleyez/config.py +52 -44
  33. souleyez/core/credential_tester.py +87 -81
  34. souleyez/core/cve_mappings.py +179 -192
  35. souleyez/core/cve_matcher.py +162 -148
  36. souleyez/core/msf_auto_mapper.py +100 -83
  37. souleyez/core/msf_chain_engine.py +294 -256
  38. souleyez/core/msf_database.py +153 -70
  39. souleyez/core/msf_integration.py +679 -673
  40. souleyez/core/msf_rpc_client.py +40 -42
  41. souleyez/core/msf_rpc_manager.py +77 -79
  42. souleyez/core/msf_sync_manager.py +241 -181
  43. souleyez/core/network_utils.py +22 -15
  44. souleyez/core/parser_handler.py +34 -25
  45. souleyez/core/pending_chains.py +114 -63
  46. souleyez/core/templates.py +158 -107
  47. souleyez/core/tool_chaining.py +9592 -2879
  48. souleyez/core/version_utils.py +79 -94
  49. souleyez/core/vuln_correlation.py +136 -89
  50. souleyez/core/web_utils.py +33 -32
  51. souleyez/data/wordlists/ad_users.txt +378 -0
  52. souleyez/data/wordlists/api_endpoints_large.txt +769 -0
  53. souleyez/data/wordlists/home_dir_sensitive.txt +39 -0
  54. souleyez/data/wordlists/lfi_payloads.txt +82 -0
  55. souleyez/data/wordlists/passwords_brute.txt +1548 -0
  56. souleyez/data/wordlists/passwords_crack.txt +2479 -0
  57. souleyez/data/wordlists/passwords_spray.txt +386 -0
  58. souleyez/data/wordlists/subdomains_large.txt +5057 -0
  59. souleyez/data/wordlists/usernames_common.txt +694 -0
  60. souleyez/data/wordlists/web_dirs_large.txt +4769 -0
  61. souleyez/detection/__init__.py +1 -1
  62. souleyez/detection/attack_signatures.py +12 -17
  63. souleyez/detection/mitre_mappings.py +61 -55
  64. souleyez/detection/validator.py +97 -86
  65. souleyez/devtools.py +23 -10
  66. souleyez/docs/README.md +4 -4
  67. souleyez/docs/api-reference/cli-commands.md +2 -2
  68. souleyez/docs/developer-guide/adding-new-tools.md +562 -0
  69. souleyez/docs/user-guide/auto-chaining.md +30 -8
  70. souleyez/docs/user-guide/getting-started.md +1 -1
  71. souleyez/docs/user-guide/installation.md +26 -3
  72. souleyez/docs/user-guide/metasploit-integration.md +2 -2
  73. souleyez/docs/user-guide/rbac.md +1 -1
  74. souleyez/docs/user-guide/scope-management.md +1 -1
  75. souleyez/docs/user-guide/siem-integration.md +1 -1
  76. souleyez/docs/user-guide/tools-reference.md +1 -8
  77. souleyez/docs/user-guide/worker-management.md +1 -1
  78. souleyez/engine/background.py +1238 -535
  79. souleyez/engine/base.py +4 -1
  80. souleyez/engine/job_status.py +17 -49
  81. souleyez/engine/log_sanitizer.py +103 -77
  82. souleyez/engine/manager.py +38 -7
  83. souleyez/engine/result_handler.py +2198 -1550
  84. souleyez/engine/worker_manager.py +50 -41
  85. souleyez/export/evidence_bundle.py +72 -62
  86. souleyez/feature_flags/features.py +16 -20
  87. souleyez/feature_flags.py +5 -9
  88. souleyez/handlers/__init__.py +11 -0
  89. souleyez/handlers/base.py +188 -0
  90. souleyez/handlers/bash_handler.py +277 -0
  91. souleyez/handlers/bloodhound_handler.py +243 -0
  92. souleyez/handlers/certipy_handler.py +311 -0
  93. souleyez/handlers/crackmapexec_handler.py +486 -0
  94. souleyez/handlers/dnsrecon_handler.py +344 -0
  95. souleyez/handlers/enum4linux_handler.py +400 -0
  96. souleyez/handlers/evil_winrm_handler.py +493 -0
  97. souleyez/handlers/ffuf_handler.py +815 -0
  98. souleyez/handlers/gobuster_handler.py +1114 -0
  99. souleyez/handlers/gpp_extract_handler.py +334 -0
  100. souleyez/handlers/hashcat_handler.py +444 -0
  101. souleyez/handlers/hydra_handler.py +563 -0
  102. souleyez/handlers/impacket_getuserspns_handler.py +343 -0
  103. souleyez/handlers/impacket_psexec_handler.py +222 -0
  104. souleyez/handlers/impacket_secretsdump_handler.py +426 -0
  105. souleyez/handlers/john_handler.py +286 -0
  106. souleyez/handlers/katana_handler.py +425 -0
  107. souleyez/handlers/kerbrute_handler.py +298 -0
  108. souleyez/handlers/ldapsearch_handler.py +636 -0
  109. souleyez/handlers/lfi_extract_handler.py +464 -0
  110. souleyez/handlers/msf_auxiliary_handler.py +408 -0
  111. souleyez/handlers/msf_exploit_handler.py +380 -0
  112. souleyez/handlers/nikto_handler.py +413 -0
  113. souleyez/handlers/nmap_handler.py +821 -0
  114. souleyez/handlers/nuclei_handler.py +359 -0
  115. souleyez/handlers/nxc_handler.py +371 -0
  116. souleyez/handlers/rdp_sec_check_handler.py +353 -0
  117. souleyez/handlers/registry.py +288 -0
  118. souleyez/handlers/responder_handler.py +232 -0
  119. souleyez/handlers/service_explorer_handler.py +434 -0
  120. souleyez/handlers/smbclient_handler.py +344 -0
  121. souleyez/handlers/smbmap_handler.py +510 -0
  122. souleyez/handlers/smbpasswd_handler.py +296 -0
  123. souleyez/handlers/sqlmap_handler.py +1116 -0
  124. souleyez/handlers/theharvester_handler.py +601 -0
  125. souleyez/handlers/whois_handler.py +277 -0
  126. souleyez/handlers/wpscan_handler.py +554 -0
  127. souleyez/history.py +32 -16
  128. souleyez/importers/msf_importer.py +106 -75
  129. souleyez/importers/smart_importer.py +208 -147
  130. souleyez/integrations/siem/__init__.py +10 -10
  131. souleyez/integrations/siem/base.py +17 -18
  132. souleyez/integrations/siem/elastic.py +108 -122
  133. souleyez/integrations/siem/factory.py +207 -80
  134. souleyez/integrations/siem/googlesecops.py +146 -154
  135. souleyez/integrations/siem/rule_mappings/__init__.py +1 -1
  136. souleyez/integrations/siem/rule_mappings/wazuh_rules.py +8 -5
  137. souleyez/integrations/siem/sentinel.py +107 -109
  138. souleyez/integrations/siem/splunk.py +246 -212
  139. souleyez/integrations/siem/wazuh.py +65 -71
  140. souleyez/integrations/wazuh/__init__.py +5 -5
  141. souleyez/integrations/wazuh/client.py +70 -93
  142. souleyez/integrations/wazuh/config.py +85 -57
  143. souleyez/integrations/wazuh/host_mapper.py +28 -36
  144. souleyez/integrations/wazuh/sync.py +78 -68
  145. souleyez/intelligence/__init__.py +4 -5
  146. souleyez/intelligence/correlation_analyzer.py +309 -295
  147. souleyez/intelligence/exploit_knowledge.py +661 -623
  148. souleyez/intelligence/exploit_suggestions.py +159 -139
  149. souleyez/intelligence/gap_analyzer.py +132 -97
  150. souleyez/intelligence/gap_detector.py +251 -214
  151. souleyez/intelligence/sensitive_tables.py +266 -129
  152. souleyez/intelligence/service_parser.py +137 -123
  153. souleyez/intelligence/surface_analyzer.py +407 -268
  154. souleyez/intelligence/target_parser.py +159 -162
  155. souleyez/licensing/__init__.py +6 -6
  156. souleyez/licensing/validator.py +17 -19
  157. souleyez/log_config.py +79 -54
  158. souleyez/main.py +1505 -687
  159. souleyez/migrations/fix_job_counter.py +16 -14
  160. souleyez/parsers/bloodhound_parser.py +41 -39
  161. souleyez/parsers/crackmapexec_parser.py +178 -111
  162. souleyez/parsers/dalfox_parser.py +72 -77
  163. souleyez/parsers/dnsrecon_parser.py +103 -91
  164. souleyez/parsers/enum4linux_parser.py +183 -153
  165. souleyez/parsers/ffuf_parser.py +29 -25
  166. souleyez/parsers/gobuster_parser.py +301 -41
  167. souleyez/parsers/hashcat_parser.py +324 -79
  168. souleyez/parsers/http_fingerprint_parser.py +350 -103
  169. souleyez/parsers/hydra_parser.py +131 -111
  170. souleyez/parsers/impacket_parser.py +231 -178
  171. souleyez/parsers/john_parser.py +98 -86
  172. souleyez/parsers/katana_parser.py +316 -0
  173. souleyez/parsers/msf_parser.py +943 -498
  174. souleyez/parsers/nikto_parser.py +346 -65
  175. souleyez/parsers/nmap_parser.py +262 -174
  176. souleyez/parsers/nuclei_parser.py +40 -44
  177. souleyez/parsers/responder_parser.py +26 -26
  178. souleyez/parsers/searchsploit_parser.py +74 -74
  179. souleyez/parsers/service_explorer_parser.py +279 -0
  180. souleyez/parsers/smbmap_parser.py +180 -124
  181. souleyez/parsers/sqlmap_parser.py +434 -308
  182. souleyez/parsers/theharvester_parser.py +75 -57
  183. souleyez/parsers/whois_parser.py +135 -94
  184. souleyez/parsers/wpscan_parser.py +278 -190
  185. souleyez/plugins/afp.py +44 -36
  186. souleyez/plugins/afp_brute.py +114 -46
  187. souleyez/plugins/ard.py +48 -37
  188. souleyez/plugins/bloodhound.py +95 -61
  189. souleyez/plugins/certipy.py +303 -0
  190. souleyez/plugins/crackmapexec.py +186 -85
  191. souleyez/plugins/dalfox.py +120 -59
  192. souleyez/plugins/dns_hijack.py +146 -41
  193. souleyez/plugins/dnsrecon.py +97 -61
  194. souleyez/plugins/enum4linux.py +91 -66
  195. souleyez/plugins/evil_winrm.py +291 -0
  196. souleyez/plugins/ffuf.py +166 -90
  197. souleyez/plugins/firmware_extract.py +133 -29
  198. souleyez/plugins/gobuster.py +387 -190
  199. souleyez/plugins/gpp_extract.py +393 -0
  200. souleyez/plugins/hashcat.py +100 -73
  201. souleyez/plugins/http_fingerprint.py +854 -267
  202. souleyez/plugins/hydra.py +566 -200
  203. souleyez/plugins/impacket_getnpusers.py +117 -69
  204. souleyez/plugins/impacket_psexec.py +84 -64
  205. souleyez/plugins/impacket_secretsdump.py +103 -69
  206. souleyez/plugins/impacket_smbclient.py +89 -75
  207. souleyez/plugins/john.py +86 -69
  208. souleyez/plugins/katana.py +313 -0
  209. souleyez/plugins/kerbrute.py +237 -0
  210. souleyez/plugins/lfi_extract.py +541 -0
  211. souleyez/plugins/macos_ssh.py +117 -48
  212. souleyez/plugins/mdns.py +35 -30
  213. souleyez/plugins/msf_auxiliary.py +253 -130
  214. souleyez/plugins/msf_exploit.py +239 -161
  215. souleyez/plugins/nikto.py +134 -78
  216. souleyez/plugins/nmap.py +275 -91
  217. souleyez/plugins/nuclei.py +180 -89
  218. souleyez/plugins/nxc.py +285 -0
  219. souleyez/plugins/plugin_base.py +35 -36
  220. souleyez/plugins/plugin_template.py +13 -5
  221. souleyez/plugins/rdp_sec_check.py +130 -0
  222. souleyez/plugins/responder.py +112 -71
  223. souleyez/plugins/router_http_brute.py +76 -65
  224. souleyez/plugins/router_ssh_brute.py +118 -41
  225. souleyez/plugins/router_telnet_brute.py +124 -42
  226. souleyez/plugins/routersploit.py +91 -59
  227. souleyez/plugins/routersploit_exploit.py +77 -55
  228. souleyez/plugins/searchsploit.py +91 -77
  229. souleyez/plugins/service_explorer.py +1160 -0
  230. souleyez/plugins/smbmap.py +122 -72
  231. souleyez/plugins/smbpasswd.py +215 -0
  232. souleyez/plugins/sqlmap.py +301 -113
  233. souleyez/plugins/theharvester.py +127 -75
  234. souleyez/plugins/tr069.py +79 -57
  235. souleyez/plugins/upnp.py +65 -47
  236. souleyez/plugins/upnp_abuse.py +73 -55
  237. souleyez/plugins/vnc_access.py +129 -42
  238. souleyez/plugins/vnc_brute.py +109 -38
  239. souleyez/plugins/whois.py +77 -58
  240. souleyez/plugins/wpscan.py +173 -69
  241. souleyez/reporting/__init__.py +2 -1
  242. souleyez/reporting/attack_chain.py +411 -346
  243. souleyez/reporting/charts.py +436 -501
  244. souleyez/reporting/compliance_mappings.py +334 -201
  245. souleyez/reporting/detection_report.py +126 -125
  246. souleyez/reporting/formatters.py +828 -591
  247. souleyez/reporting/generator.py +386 -302
  248. souleyez/reporting/metrics.py +72 -75
  249. souleyez/scanner.py +35 -29
  250. souleyez/security/__init__.py +37 -11
  251. souleyez/security/scope_validator.py +175 -106
  252. souleyez/security/validation.py +223 -149
  253. souleyez/security.py +22 -6
  254. souleyez/storage/credentials.py +247 -186
  255. souleyez/storage/crypto.py +296 -129
  256. souleyez/storage/database.py +73 -50
  257. souleyez/storage/db.py +58 -36
  258. souleyez/storage/deliverable_evidence.py +177 -128
  259. souleyez/storage/deliverable_exporter.py +282 -246
  260. souleyez/storage/deliverable_templates.py +134 -116
  261. souleyez/storage/deliverables.py +135 -130
  262. souleyez/storage/engagements.py +109 -56
  263. souleyez/storage/evidence.py +181 -152
  264. souleyez/storage/execution_log.py +31 -17
  265. souleyez/storage/exploit_attempts.py +93 -57
  266. souleyez/storage/exploits.py +67 -36
  267. souleyez/storage/findings.py +48 -61
  268. souleyez/storage/hosts.py +176 -144
  269. souleyez/storage/migrate_to_engagements.py +43 -19
  270. souleyez/storage/migrations/_001_add_credential_enhancements.py +22 -12
  271. souleyez/storage/migrations/_002_add_status_tracking.py +10 -7
  272. souleyez/storage/migrations/_003_add_execution_log.py +14 -8
  273. souleyez/storage/migrations/_005_screenshots.py +13 -5
  274. souleyez/storage/migrations/_006_deliverables.py +13 -5
  275. souleyez/storage/migrations/_007_deliverable_templates.py +12 -7
  276. souleyez/storage/migrations/_008_add_nuclei_table.py +10 -4
  277. souleyez/storage/migrations/_010_evidence_linking.py +17 -10
  278. souleyez/storage/migrations/_011_timeline_tracking.py +20 -13
  279. souleyez/storage/migrations/_012_team_collaboration.py +34 -21
  280. souleyez/storage/migrations/_013_add_host_tags.py +12 -6
  281. souleyez/storage/migrations/_014_exploit_attempts.py +22 -10
  282. souleyez/storage/migrations/_015_add_mac_os_fields.py +15 -7
  283. souleyez/storage/migrations/_016_add_domain_field.py +10 -4
  284. souleyez/storage/migrations/_017_msf_sessions.py +16 -8
  285. souleyez/storage/migrations/_018_add_osint_target.py +10 -6
  286. souleyez/storage/migrations/_019_add_engagement_type.py +10 -6
  287. souleyez/storage/migrations/_020_add_rbac.py +36 -15
  288. souleyez/storage/migrations/_021_wazuh_integration.py +20 -8
  289. souleyez/storage/migrations/_022_wazuh_indexer_columns.py +6 -4
  290. souleyez/storage/migrations/_023_fix_detection_results_fk.py +16 -6
  291. souleyez/storage/migrations/_024_wazuh_vulnerabilities.py +26 -10
  292. souleyez/storage/migrations/_025_multi_siem_support.py +3 -5
  293. souleyez/storage/migrations/_026_add_engagement_scope.py +31 -12
  294. souleyez/storage/migrations/_027_multi_siem_persistence.py +32 -15
  295. souleyez/storage/migrations/__init__.py +26 -26
  296. souleyez/storage/migrations/migration_manager.py +19 -19
  297. souleyez/storage/msf_sessions.py +100 -65
  298. souleyez/storage/osint.py +17 -24
  299. souleyez/storage/recommendation_engine.py +269 -235
  300. souleyez/storage/screenshots.py +33 -32
  301. souleyez/storage/smb_shares.py +136 -92
  302. souleyez/storage/sqlmap_data.py +183 -128
  303. souleyez/storage/team_collaboration.py +135 -141
  304. souleyez/storage/timeline_tracker.py +122 -94
  305. souleyez/storage/wazuh_vulns.py +64 -66
  306. souleyez/storage/web_paths.py +33 -37
  307. souleyez/testing/credential_tester.py +221 -205
  308. souleyez/ui/__init__.py +1 -1
  309. souleyez/ui/ai_quotes.py +12 -12
  310. souleyez/ui/attack_surface.py +2439 -1516
  311. souleyez/ui/chain_rules_view.py +914 -382
  312. souleyez/ui/correlation_view.py +312 -230
  313. souleyez/ui/dashboard.py +2382 -1130
  314. souleyez/ui/deliverables_view.py +148 -62
  315. souleyez/ui/design_system.py +13 -13
  316. souleyez/ui/errors.py +49 -49
  317. souleyez/ui/evidence_linking_view.py +284 -179
  318. souleyez/ui/evidence_vault.py +393 -285
  319. souleyez/ui/exploit_suggestions_view.py +555 -349
  320. souleyez/ui/export_view.py +100 -66
  321. souleyez/ui/gap_analysis_view.py +315 -171
  322. souleyez/ui/help_system.py +105 -97
  323. souleyez/ui/intelligence_view.py +436 -293
  324. souleyez/ui/interactive.py +23142 -10430
  325. souleyez/ui/interactive_selector.py +75 -68
  326. souleyez/ui/log_formatter.py +47 -39
  327. souleyez/ui/menu_components.py +22 -13
  328. souleyez/ui/msf_auxiliary_menu.py +184 -133
  329. souleyez/ui/pending_chains_view.py +336 -172
  330. souleyez/ui/progress_indicators.py +5 -3
  331. souleyez/ui/recommendations_view.py +195 -137
  332. souleyez/ui/rule_builder.py +343 -225
  333. souleyez/ui/setup_wizard.py +678 -284
  334. souleyez/ui/shortcuts.py +217 -165
  335. souleyez/ui/splunk_gap_analysis_view.py +452 -270
  336. souleyez/ui/splunk_vulns_view.py +139 -86
  337. souleyez/ui/team_dashboard.py +498 -335
  338. souleyez/ui/template_selector.py +196 -105
  339. souleyez/ui/terminal.py +6 -6
  340. souleyez/ui/timeline_view.py +198 -127
  341. souleyez/ui/tool_setup.py +264 -164
  342. souleyez/ui/tutorial.py +202 -72
  343. souleyez/ui/tutorial_state.py +40 -40
  344. souleyez/ui/wazuh_vulns_view.py +235 -141
  345. souleyez/ui/wordlist_browser.py +260 -107
  346. souleyez/ui.py +464 -312
  347. souleyez/utils/tool_checker.py +427 -367
  348. souleyez/utils.py +33 -29
  349. souleyez/wordlists.py +134 -167
  350. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/METADATA +1 -1
  351. souleyez-2.43.32.dist-info/RECORD +441 -0
  352. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/WHEEL +1 -1
  353. souleyez-2.43.28.dist-info/RECORD +0 -379
  354. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/entry_points.txt +0 -0
  355. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/licenses/LICENSE +0 -0
  356. {souleyez-2.43.28.dist-info → souleyez-2.43.32.dist-info}/top_level.txt +0 -0
@@ -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