Skip to content

Commit 58cd2c7

Browse files
committed
Add a bind port setting to reverse listeners
This adds a `ReverseListenerBindPort` advanced setting to the reverse listeners whic allows for the local bind port to be separated from the `LHOST` setting used in the payload. This means that listeners can bind to different ports in cases where the attacker isn't able to listen on the same port that the victim can call out on, but there are NATs/portforwards/whatever in place that allow the connection to happen.
1 parent 813bd2c commit 58cd2c7

File tree

3 files changed

+106
-61
lines changed

3 files changed

+106
-61
lines changed

lib/msf/core/handler/reverse_http.rb

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -83,23 +83,10 @@ def ssl?
8383
# addresses.
8484
#
8585
def full_uri
86-
unless datastore['HIDDENHOST'].nil? or datastore['HIDDENHOST'].empty?
87-
lhost = datastore['HIDDENHOST']
88-
else
89-
lhost = datastore['LHOST']
90-
end
91-
if lhost.empty? or lhost == "0.0.0.0" or lhost == "::"
92-
lhost = Rex::Socket.source_address
93-
end
94-
lhost = "[#{lhost}]" if Rex::Socket.is_ipv6?(lhost)
86+
addrs = bind_address(datastore)
87+
local_port = bind_port(datastore)
9588
scheme = (ssl?) ? "https" : "http"
96-
unless datastore['HIDDENPORT'].nil? or datastore['HIDDENPORT'] == 0
97-
uri = "#{scheme}://#{lhost}:#{datastore["HIDDENPORT"]}/"
98-
else
99-
uri = "#{scheme}://#{lhost}:#{datastore["LPORT"]}/"
100-
end
101-
102-
uri
89+
"#{scheme}://#{addrs[0]}:#{local_port}/"
10390
end
10491

10592
#
@@ -163,6 +150,7 @@ def initialize(info = {})
163150
OptString.new('MeterpreterUserAgent', [ false, 'The user-agent that the payload should use for communication', 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)' ]),
164151
OptString.new('MeterpreterServerName', [ false, 'The server header that the handler will send in response to requests', 'Apache' ]),
165152
OptAddress.new('ReverseListenerBindAddress', [ false, 'The specific IP address to bind to on the local system']),
153+
OptInt.new('ReverseListenerBindPort', [ false, 'The port to bind to on the local system if different from LPORT' ]),
166154
OptString.new('HttpUnknownRequestResponse', [ false, 'The returned HTML response body when the handler receives a request that is not from a payload', '<html><body><h1>It works!</h1></body></html>' ])
167155
], Msf::Handler::ReverseHttp)
168156
end
@@ -186,17 +174,13 @@ def setup_handler
186174
comm = nil
187175
end
188176

189-
# Determine where to bind the HTTP(S) server to
190-
bindaddrs = ipv6 ? '::' : '0.0.0.0'
191-
192-
if not datastore['ReverseListenerBindAddress'].to_s.empty?
193-
bindaddrs = datastore['ReverseListenerBindAddress']
194-
end
177+
local_port = bind_port(datastore)
178+
addrs = bind_address(datastore)
195179

196180
# Start the HTTPS server service on this host/port
197181
self.service = Rex::ServiceManager.start(Rex::Proto::Http::Server,
198-
datastore['LPORT'].to_i,
199-
bindaddrs,
182+
local_port,
183+
addrs[0],
200184
ssl?,
201185
{
202186
'Msf' => framework,
@@ -413,6 +397,33 @@ def on_request(cli, req, obj)
413397
obj.service.close_client( cli )
414398
end
415399

400+
protected
401+
402+
def bind_port(datastore)
403+
port = datastore['ReverseListenerBindPort'].to_i
404+
port > 0 ? port : datastore['LPORT'].to_i
405+
end
406+
407+
def bind_address(datastore)
408+
# Switch to IPv6 ANY address if the LHOST is also IPv6
409+
addr = Rex::Socket.resolv_nbo(datastore['LHOST'])
410+
# First attempt to bind LHOST. If that fails, the user probably has
411+
# something else listening on that interface. Try again with ANY_ADDR.
412+
any = (addr.length == 4) ? "0.0.0.0" : "::0"
413+
414+
addrs = [ Rex::Socket.addr_ntoa(addr), any ]
415+
416+
if not datastore['ReverseListenerBindAddress'].to_s.empty?
417+
# Only try to bind to this specific interface
418+
addrs = [ datastore['ReverseListenerBindAddress'] ]
419+
420+
# Pick the right "any" address if either wildcard is used
421+
addrs[0] = any if (addrs[0] == "0.0.0.0" or addrs == "::0")
422+
end
423+
424+
addrs
425+
end
426+
416427

417428
end
418429

lib/msf/core/handler/reverse_tcp.rb

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,9 @@ def initialize(info = {})
5353
[
5454
OptInt.new('ReverseConnectRetries', [ true, 'The number of connection attempts to try before exiting the process', 5 ]),
5555
OptAddress.new('ReverseListenerBindAddress', [ false, 'The specific IP address to bind to on the local system']),
56+
OptInt.new('ReverseListenerBindPort', [ false, 'The port to bind to on the local system if different from LPORT' ]),
5657
OptString.new('ReverseListenerComm', [ false, 'The specific communication channel to use for this listener']),
57-
OptBool.new('ReverseAllowProxy', [ true, 'Allow reverse tcp even with Proxies specified. Connect back will NOT go through proxy but directly to LHOST', false]),
58+
OptBool.new('ReverseAllowProxy', [ true, 'Allow reverse tcp even with Proxies specified. Connect back will NOT go through proxy but directly to LHOST', false])
5859
], Msf::Handler::ReverseTcp)
5960

6061

@@ -72,13 +73,6 @@ def setup_handler
7273
end
7374

7475
ex = false
75-
# Switch to IPv6 ANY address if the LHOST is also IPv6
76-
addr = Rex::Socket.resolv_nbo(datastore['LHOST'])
77-
# First attempt to bind LHOST. If that fails, the user probably has
78-
# something else listening on that interface. Try again with ANY_ADDR.
79-
any = (addr.length == 4) ? "0.0.0.0" : "::0"
80-
81-
addrs = [ Rex::Socket.addr_ntoa(addr), any ]
8276

8377
comm = datastore['ReverseListenerComm']
8478
if comm.to_s == "local"
@@ -87,19 +81,15 @@ def setup_handler
8781
comm = nil
8882
end
8983

90-
if not datastore['ReverseListenerBindAddress'].to_s.empty?
91-
# Only try to bind to this specific interface
92-
addrs = [ datastore['ReverseListenerBindAddress'] ]
84+
local_port = bind_port(datastore)
85+
addrs = bind_address(datastore)
9386

94-
# Pick the right "any" address if either wildcard is used
95-
addrs[0] = any if (addrs[0] == "0.0.0.0" or addrs == "::0")
96-
end
9787
addrs.each { |ip|
9888
begin
9989

10090
self.listener_sock = Rex::Socket::TcpServer.create(
10191
'LocalHost' => ip,
102-
'LocalPort' => datastore['LPORT'].to_i,
92+
'LocalPort' => local_port,
10393
'Comm' => comm,
10494
'Context' =>
10595
{
@@ -119,11 +109,11 @@ def setup_handler
119109
via = ""
120110
end
121111

122-
print_status("Started reverse handler on #{ip}:#{datastore['LPORT']} #{via}")
112+
print_status("Started reverse handler on #{ip}:#{local_port} #{via}")
123113
break
124114
rescue
125115
ex = $!
126-
print_error("Handler failed to bind to #{ip}:#{datastore['LPORT']}")
116+
print_error("Handler failed to bind to #{ip}:#{local_port}")
127117
end
128118
}
129119
raise ex if (ex)
@@ -140,7 +130,8 @@ def cleanup_handler
140130
# Starts monitoring for an inbound connection.
141131
#
142132
def start_handler
143-
self.listener_thread = framework.threads.spawn("ReverseTcpHandlerListener-#{datastore['LPORT']}", false) {
133+
local_port = bind_port(datastore)
134+
self.listener_thread = framework.threads.spawn("ReverseTcpHandlerListener-#{local_port}", false) {
144135
client = nil
145136

146137
begin
@@ -159,7 +150,7 @@ def start_handler
159150
end while true
160151
}
161152

162-
self.handler_thread = framework.threads.spawn("ReverseTcpHandlerWorker-#{datastore['LPORT']}", false) {
153+
self.handler_thread = framework.threads.spawn("ReverseTcpHandlerWorker-#{local_port}", false) {
163154
while true
164155
client = self.handler_queue.pop
165156
begin
@@ -241,6 +232,31 @@ def stop_handler
241232

242233
protected
243234

235+
def bind_port(datastore)
236+
port = datastore['ReverseListenerBindPort'].to_i
237+
port > 0 ? port : datastore['LPORT'].to_i
238+
end
239+
240+
def bind_address(datastore)
241+
# Switch to IPv6 ANY address if the LHOST is also IPv6
242+
addr = Rex::Socket.resolv_nbo(datastore['LHOST'])
243+
# First attempt to bind LHOST. If that fails, the user probably has
244+
# something else listening on that interface. Try again with ANY_ADDR.
245+
any = (addr.length == 4) ? "0.0.0.0" : "::0"
246+
247+
addrs = [ Rex::Socket.addr_ntoa(addr), any ]
248+
249+
if not datastore['ReverseListenerBindAddress'].to_s.empty?
250+
# Only try to bind to this specific interface
251+
addrs = [ datastore['ReverseListenerBindAddress'] ]
252+
253+
# Pick the right "any" address if either wildcard is used
254+
addrs[0] = any if (addrs[0] == "0.0.0.0" or addrs == "::0")
255+
end
256+
257+
addrs
258+
end
259+
244260
attr_accessor :listener_sock # :nodoc:
245261
attr_accessor :listener_thread # :nodoc:
246262
attr_accessor :handler_thread # :nodoc:

lib/msf/core/handler/reverse_tcp_ssl.rb

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ def initialize(info = {})
4343
super
4444
register_advanced_options(
4545
[
46-
OptPath.new('SSLCert', [ false, 'Path to a custom SSL certificate (default is randomly generated)'])
46+
OptPath.new('SSLCert', [ false, 'Path to a custom SSL certificate (default is randomly generated)']),
47+
OptAddress.new('ReverseListenerBindAddress', [ false, 'The specific IP address to bind to on the local system']),
48+
OptInt.new('ReverseListenerBindPort', [ false, 'The port to bind to on the local system if different from LPORT' ])
4749
], Msf::Handler::ReverseTcpSsl)
4850

4951
end
@@ -59,13 +61,6 @@ def setup_handler
5961
end
6062

6163
ex = false
62-
# Switch to IPv6 ANY address if the LHOST is also IPv6
63-
addr = Rex::Socket.resolv_nbo(datastore['LHOST'])
64-
# First attempt to bind LHOST. If that fails, the user probably has
65-
# something else listening on that interface. Try again with ANY_ADDR.
66-
any = (addr.length == 4) ? "0.0.0.0" : "::0"
67-
68-
addrs = [ Rex::Socket.addr_ntoa(addr), any ]
6964

7065
comm = datastore['ReverseListenerComm']
7166
if comm.to_s == "local"
@@ -74,20 +69,16 @@ def setup_handler
7469
comm = nil
7570
end
7671

77-
if not datastore['ReverseListenerBindAddress'].to_s.empty?
78-
# Only try to bind to this specific interface
79-
addrs = [ datastore['ReverseListenerBindAddress'] ]
72+
local_port = bind_port(datastore)
73+
addrs = bind_address(datastore)
8074

81-
# Pick the right "any" address if either wildcard is used
82-
addrs[0] = any if (addrs[0] == "0.0.0.0" or addrs == "::0")
83-
end
8475
addrs.each { |ip|
8576
begin
8677

8778
comm.extend(Rex::Socket::SslTcp)
8879
self.listener_sock = Rex::Socket::SslTcpServer.create(
89-
'LocalHost' => datastore['LHOST'],
90-
'LocalPort' => datastore['LPORT'].to_i,
80+
'LocalHost' => ip,
81+
'LocalPort' => local_port,
9182
'Comm' => comm,
9283
'SSLCert' => datastore['SSLCert'],
9384
'Context' =>
@@ -108,16 +99,43 @@ def setup_handler
10899
via = ""
109100
end
110101

111-
print_status("Started reverse SSL handler on #{ip}:#{datastore['LPORT']} #{via}")
102+
print_status("Started reverse SSL handler on #{ip}:#{local_port} #{via}")
112103
break
113104
rescue
114105
ex = $!
115-
print_error("Handler failed to bind to #{ip}:#{datastore['LPORT']}")
106+
print_error("Handler failed to bind to #{ip}:#{local_port}")
116107
end
117108
}
118109
raise ex if (ex)
119110
end
120111

112+
protected
113+
114+
def bind_port(datastore)
115+
port = datastore['ReverseListenerBindPort'].to_i
116+
port > 0 ? port : datastore['LPORT'].to_i
117+
end
118+
119+
def bind_address(datastore)
120+
# Switch to IPv6 ANY address if the LHOST is also IPv6
121+
addr = Rex::Socket.resolv_nbo(datastore['LHOST'])
122+
# First attempt to bind LHOST. If that fails, the user probably has
123+
# something else listening on that interface. Try again with ANY_ADDR.
124+
any = (addr.length == 4) ? "0.0.0.0" : "::0"
125+
126+
addrs = [ Rex::Socket.addr_ntoa(addr), any ]
127+
128+
if not datastore['ReverseListenerBindAddress'].to_s.empty?
129+
# Only try to bind to this specific interface
130+
addrs = [ datastore['ReverseListenerBindAddress'] ]
131+
132+
# Pick the right "any" address if either wildcard is used
133+
addrs[0] = any if (addrs[0] == "0.0.0.0" or addrs == "::0")
134+
end
135+
136+
addrs
137+
end
138+
121139
end
122140

123141
end

0 commit comments

Comments
 (0)