Skip to content

Commit 43526ee

Browse files
authored
Update redoc_exposed.md
1 parent 67490e4 commit 43526ee

File tree

1 file changed

+91
-39
lines changed

1 file changed

+91
-39
lines changed
Lines changed: 91 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,91 @@
1-
## Summary
2-
This module detects publicly exposed **ReDoc** API documentation pages.
3-
It performs safe, read-only HTTP GET requests and reports likely ReDoc instances based on common HTML markers.
4-
5-
## Module name
6-
`auxiliary/scanner/http/redoc_exposed`
7-
8-
## Options
9-
* **RPORT** – Target TCP port (default: 80)
10-
* **SSL** – Enable TLS (default: false)
11-
* **REDOC_PATHS** – Optional comma-separated list of paths to probe. When unset, the module probes: `/redoc, /redoc/, /docs, /api/docs, /openapi`.
12-
13-
## Verification steps
14-
1. Start `msfconsole`
15-
2. `use auxiliary/scanner/http/redoc_exposed`
16-
3. `set RHOSTS <target or file:/path/to/targets.txt>`
17-
4. (Optional) `set REDOC_PATHS /redoc,/docs`
18-
5. (Optional) `set RPORT <port>` and/or `set SSL true`
19-
6. `run`
20-
21-
### Expected
22-
23-
`[+] <ip> - ReDoc likely exposed at <path>`
24-
25-
### Scanning notes
26-
- DOM-driven checks via `get_html_document`:
27-
- `<redoc>` / `redoc-` custom elements
28-
- `#redoc` container
29-
- `<script src="...redoc(.standalone).js">`
30-
- Falls back to body/title heuristics if DOM parsing is unavailable.
31-
- No intrusive actions; **read-only** HTTP GET requests only.
32-
33-
### Example session
34-
35-
use auxiliary/scanner/http/redoc_exposed
36-
set RHOSTS 127.0.0.1
37-
set RPORT 8001
38-
set SSL false
39-
run
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Auxiliary
7+
include Msf::Auxiliary::Scanner
8+
include Msf::Exploit::Remote::HttpClient
9+
10+
def initialize(info = {})
11+
super(
12+
update_info(
13+
info,
14+
'Name' => 'ReDoc API Docs UI Exposed',
15+
'Description' => %q{
16+
Detects publicly exposed ReDoc API documentation pages.
17+
The module performs safe, read-only GET requests and reports likely
18+
ReDoc instances based on HTML markers.
19+
},
20+
'Author' => [
21+
'Hamza Sahin (@hamzasahin61)'
22+
],
23+
'License' => MSF_LICENSE,
24+
'Notes' => {
25+
'Stability' => [CRASH_SAFE], # GET requests only; should not crash or disrupt the target service
26+
'Reliability' => [], # Does not establish sessions; leaving this empty is acceptable
27+
'SideEffects' => [] # Add IOC_IN_LOGS if server logs may record these requests
28+
}
29+
)
30+
)
31+
32+
register_options(
33+
[
34+
Opt::RPORT(80),
35+
OptBool.new('SSL', [true, 'Negotiate SSL/TLS for outgoing connections', false]),
36+
OptString.new('REDOC_PATHS', [
37+
false,
38+
'Comma-separated list of paths to probe (overrides defaults)',
39+
nil
40+
])
41+
]
42+
)
43+
end
44+
45+
# returns true if the response looks like a ReDoc page
46+
def redoc_like?(res)
47+
return false unless res && res.code.between?(200, 403)
48+
49+
# Prefer DOM checks
50+
doc = res.get_html_document
51+
if doc
52+
return true if doc.at_css('redoc, redoc-, #redoc')
53+
return true if doc.css('script[src*="redoc"]').any?
54+
return true if doc.css('script[src*="redoc.standalone"]').any?
55+
end
56+
57+
# Fallback to body/title heuristics
58+
title = res.get_html_title.to_s
59+
body = res.body.to_s
60+
61+
return true if title =~ /redoc/i
62+
return true if body =~ /<redoc-?/i
63+
return true if body =~ /redoc(\.standalone)?\.js/i
64+
65+
false
66+
end
67+
68+
def check_path(path)
69+
res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(path) })
70+
redoc_like?(res)
71+
end
72+
73+
def run_host(ip)
74+
vprint_status("#{ip} - scanning for ReDoc")
75+
76+
paths =
77+
if (ds = datastore['REDOC_PATHS']) && !ds.empty?
78+
ds.split(',').map(&:strip)
79+
else
80+
['/redoc', '/redoc/', '/docs', '/api/docs', '/openapi']
81+
end
82+
83+
hit = paths.find { |p| check_path(p) }
84+
if hit
85+
print_good("#{ip} - ReDoc likely exposed at #{hit}")
86+
report_service(host: ip, port: rport, proto: 'tcp', name: 'http')
87+
else
88+
vprint_status("#{ip} - no ReDoc found")
89+
end
90+
end
91+
end

0 commit comments

Comments
 (0)