-
Notifications
You must be signed in to change notification settings - Fork 14.6k
auxiliary(scanner/http/redoc_exposed): detect exposed ReDoc API docs UI #20594
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
bwatters-r7
merged 13 commits into
rapid7:master
from
HamzaSahin61:feat/redoc-exposed-scanner
Oct 24, 2025
+123
−0
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
c2f554b
auxiliary(scanner/http/redoc_exposed): detect exposed ReDoc API docs UI
HamzaSahin61 fc35a8a
Update redoc_exposed.rb
HamzaSahin61 67490e4
Create redoc_exposed.md
HamzaSahin61 43526ee
Update redoc_exposed.md
HamzaSahin61 941f3f3
Update redoc_exposed.md
HamzaSahin61 33825d0
Update redoc_exposed.rb
HamzaSahin61 4577a3d
Update redoc_exposed.rb
HamzaSahin61 db6dbf4
Update redoc_exposed.md
HamzaSahin61 33244f6
style: rubocop auto-corrections + add Notes metadata
HamzaSahin61 bbd2767
Update redoc_exposed.md
HamzaSahin61 49c1481
Update redoc_exposed.md
HamzaSahin61 9640152
Update redoc_exposed.md
HamzaSahin61 e17b2a0
Remove 'How It Works' section from redoc_exposed.md
HamzaSahin61 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
37 changes: 37 additions & 0 deletions
37
documentation/modules/auxiliary/scanner/http/redoc_exposed.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| ## Vulnerable Application | ||
|
|
||
| Detects publicly exposed ReDoc API documentation pages by looking for known DOM elements and script names. The module | ||
| is read-only and sends safe `GET` requests. | ||
|
|
||
| ### How It Works | ||
| - Prefers DOM checks (`<redoc>`, `#redoc`, or scripts containing `redoc` / `redoc.standalone`). | ||
| - Falls back to title/body heuristics for “redoc”. | ||
| - Considers only **2xx** and **403** responses (avoids noisy redirects). | ||
|
|
||
HamzaSahin61 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ## Verification Steps | ||
|
|
||
| 1. Start `msfconsole`. | ||
| 2. `use auxiliary/scanner/http/redoc_exposed` | ||
| 3. `set RHOSTS <target-or-range>` | ||
| 4. (Optional) `set SSL true` | ||
| 5. (Optional) `set REDOC_PATHS /redoc,/docs` | ||
| 6. `run` | ||
|
|
||
| ## Options | ||
| ### REDOC_PATHS | ||
| Comma-separated custom paths to probe. If unset, defaults to `/redoc,/redoc/,/docs,/api/docs,/openapi` | ||
|
|
||
| ## Scenarios | ||
|
|
||
| ```text | ||
| msf6 > use auxiliary/scanner/http/redoc_exposed | ||
| msf6 auxiliary(scanner/http/redoc_exposed) > set RHOSTS 192.0.2.0/24 | ||
| msf6 auxiliary(scanner/http/redoc_exposed) > run | ||
| [+] 192.0.2.15 - ReDoc likely exposed at /docs | ||
| [*] 192.0.2.23 - no ReDoc found | ||
| ``` | ||
| ## Notes | ||
|
|
||
| * **Stability**: `CRASH_SAFE` (GET requests only). | ||
| * **Reliability**: No session creation. | ||
| * **SideEffects**: Requests may appear in server logs (`IOC_IN_LOGS`). | ||
HamzaSahin61 marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| ## | ||
| # This module requires Metasploit: https://metasploit.com/download | ||
| # Current source: https://github.com/rapid7/metasploit-framework | ||
| ## | ||
|
|
||
| class MetasploitModule < Msf::Auxiliary | ||
| include Msf::Auxiliary::Scanner | ||
| include Msf::Exploit::Remote::HttpClient | ||
|
|
||
| def initialize(info = {}) | ||
| super( | ||
| update_info( | ||
| info, | ||
| 'Name' => 'ReDoc API Docs UI Exposed', | ||
| 'Description' => %q{ | ||
| Detects publicly exposed ReDoc API documentation pages. | ||
| The module performs safe, read-only GET requests and reports likely | ||
| ReDoc instances based on HTML markers. | ||
| }, | ||
| 'Author' => [ | ||
| 'Hamza Sahin (@hamzasahin61)' | ||
| ], | ||
| 'License' => MSF_LICENSE, | ||
| 'Notes' => { | ||
| 'Stability' => [CRASH_SAFE], # GET requests only; should not crash or disrupt the target service | ||
| 'Reliability' => [], # Does not establish sessions; leaving this empty is acceptable | ||
| 'SideEffects' => [IOC_IN_LOGS] # Requests may be logged by the target web server | ||
| }, | ||
| 'DefaultOptions' => { | ||
| 'RPORT' => 80 | ||
| } | ||
| ) | ||
| ) | ||
|
|
||
| register_options( | ||
| [ | ||
| # Mark as required and surface the built-in defaults here | ||
| OptString.new('REDOC_PATHS', [ | ||
| true, | ||
| 'Comma-separated list of paths to probe', | ||
| '/redoc,/redoc/,/docs,/api/docs,/openapi' | ||
| ]) | ||
| ] | ||
| ) | ||
| end | ||
|
|
||
| # returns true if the response looks like a ReDoc page | ||
| def redoc_like?(res) | ||
| # Accept only 2xx or 403 (exclude redirects; many 3xx lack HTML to analyze) | ||
| return false unless res && (res.code.between?(200, 299) || res.code == 403) | ||
|
|
||
| # Prefer DOM checks | ||
| doc = res.get_html_document | ||
| if doc && (doc.at_css('redoc, redoc-, #redoc') || | ||
| doc.css('script[src*="redoc"]').any? || | ||
| doc.css('script[src*="redoc.standalone"]').any?) | ||
| return true | ||
| end | ||
|
|
||
| # Fallback to body/title heuristics | ||
| title = res.get_html_title.to_s | ||
| body = res.body.to_s | ||
| return true if title =~ /redoc/i || body =~ /<redoc-?/i || body =~ /redoc(\.standalone)?\.js/i | ||
|
|
||
| false | ||
| end | ||
|
|
||
| def check_path(path) | ||
| redoc_like?(send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(path) })) | ||
| end | ||
|
|
||
| def run_host(ip) | ||
| vprint_status("#{ip} - scanning for ReDoc") | ||
|
|
||
| # REDOC_PATHS is required and has defaults; always use it directly | ||
| paths = datastore['REDOC_PATHS'].split(',').map(&:strip) | ||
|
|
||
| hit = paths.find { |p| check_path(p) } | ||
| if hit | ||
| print_good("#{ip} - ReDoc likely exposed at #{hit}") | ||
| report_service(host: ip, port: rport, proto: 'tcp', name: 'http') | ||
| else | ||
| vprint_status("#{ip} - no ReDoc found") | ||
| end | ||
| end | ||
| end |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.