metasploit-framework
metasploit-framework copied to clipboard
Reverse Port Forward Can't Listen on Localhost
Steps to reproduce
- Get a Meterpreter shell (I used
windows/x64/meterpreter/reverse_tcp
but it should not matter) - Start Python HTTP server on MSF host:
python3 -m http.server 8080
- Add a reverse port forward
portfwd add -R -l 8080 -L 127.0.0.1 -p 2222 -r 127.0.0.1
- Observe the inaccurate message saying the reverse listener is open on 127.0.0.1:2222
- Use
netstat
to confirm the listener is actually open on0.0.0.0
😢

Environment: Meterpreter executed on Windows 10 Enterprise, 20H2 OS Build 19042.1110
Were you following a specific guide/tutorial or reading documentation?
Nope
Expected behavior
Meterpreter should listen on whatever address it's given (in this case, the loopback address).
Current behavior
Meterpreter listens on 0.0.0.0
instead.
Metasploit version
Framework: 6.2.28-dev-39da40e4b533bd55e2479f3d44cd9fe41b140b60 Console : 6.2.28-dev-39da40e4b533bd55e2479f3d44cd9fe41b140b60
Few additional notes since troubleshooting this issue:
The first issue seems to be missing Ruby code to allow sending of a localHost
value for the Windows machine to listen on:
# Add additional checks to make sure rhost is set ...
channel = client.net.socket.create(
Rex::Socket::Parameters.new(
'LocalPort' => rport,
'LocalHost' => rhost, # <-- include this line to pass localHost to the Meterpreter side
'Proto' => 'tcp',
'Server' => true
)
)
and possibly also here
# Start the local TCP reverse relay in association with this stream
relay = service.start_reverse_tcp_relay(channel,
'LocalPort' => channel.params.localport,
'LocalHost' => channel.params.localhost, # <-- Add this line to avoid defaulting to 0.0.0.0
'PeerHost' => lhost,
'PeerPort' => lport,
'MeterpreterRelay' => true)
https://github.com/rapid7/metasploit-framework/blob/fa125e19430d7907471edc8d46d2920b7e1d2ffd/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb#L454-L458
In the Metasploit-Payloads code, a logic bug exists that only allows the code which sets the localHost
to the specified value (instead of defaulting to 0.0.0.0
) if the system is XP, and falls back to V4 support only.
if (v4Fallback)
{
struct sockaddr_in* v4Addr = (struct sockaddr_in*)&sockAddr;
v4Addr->sin_addr.s_addr = localHost == NULL ? htons(INADDR_ANY) : inet_addr(localHost); // <-- localHost is set *HERE*
v4Addr->sin_family = AF_INET;
v4Addr->sin_port = htons(localPort);
sockAddrSize = sizeof(struct sockaddr_in);
}
https://github.com/rapid7/metasploit-payloads/blob/ffa80978321fe399b02b759479bba06ecc7241d1/c/meterpreter/source/extensions/stdapi/server/net/socket/tcp_server.c#L329-L336
So there's two issues here.
- The
portfwd
command does not pass the LocalHost for binding to Rex API which then sends a default to the remote Meterpreter instance - The remote Meterpreter instance ignores whatever LocalHost is sent to it by the lower-level Rex API. Additionally, different Meterpreters do different things when starting TCP server sockets.
We're going to fix number 2, it's going to require some changes to the Meterpreters which will take some time because each will need to be tested. I've got the code for the Python and Windows Meterpreters done that I'll submit in the next day or two. We're going to normalize the functoinality such that when creating a TCP server socket, the Meterpreters will all honor the bind address information. When no bind address is sent (either it's omitted entirely or it is an empty string) then the Meterpreter will bind to all available addresses, both IPv4 and IPv6. Right now Mettle and the Windows Meterpreters are binding to all IPv4 and IPv6 addresses while Python is binding to all IPv4 unless an explicit address was set.
Unfortunately, we're not going to fix issue number 1. We're concerned that it will break instances where users are passing a specific address but relying on the existing (incorrect) behavior of most Meterpreters ignoring it and binding to everything. I've updated my PR to reflect this, we're going to throw a warning in portfwd
when used with -r
so users know it's ignored, thus retaining the original functionality but at least printing a warning so users know whats happening.
Once the Meterpreter updates are in place, I'll send you a work around so you can start a portforward that's bound to an explicit address, bypassing the aforementioned UI-imposed restriction.
Hi!
This issue has been left open with no activity for a while now.
We get a lot of issues, so we currently close issues after 60 days of inactivity. It’s been at least 30 days since the last update here. If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!
As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request.
Now that #685 is landed, all of the Meterpreters behave consistently and will bind to the specified address.