Skip to content

Commit 252909a

Browse files
committed
Land rapid7#2448, @OJ's ReverseListenerBindPort :)
2 parents ad2ec49 + 063da8a commit 252909a

File tree

5 files changed

+142
-73
lines changed

5 files changed

+142
-73
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
87+
local_port = bind_port
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
178+
addrs = bind_address
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
403+
port = datastore['ReverseListenerBindPort'].to_i
404+
port > 0 ? port : datastore['LPORT'].to_i
405+
end
406+
407+
def bind_address
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_https_proxy.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,17 @@ def initialize(info = {})
4242
OptPort.new('LPORT', [ true, "The local listener port", 8443 ]),
4343
OptString.new('PROXYHOST', [true, "The address of the http proxy to use" ,"127.0.0.1"]),
4444
OptInt.new('PROXYPORT', [ false, "The Proxy port to connect to", 8080 ]),
45-
OptString.new('HIDDENHOST', [false, "The tor hidden host to connect to, when set it will be used instead of LHOST for stager generation"]),
46-
OptInt.new('HIDDENPORT', [ false, "The hidden port to connect to, when set it will be used instead of LPORT for stager generation"]),
4745
OptEnum.new('PROXY_TYPE', [true, 'Http or Socks4 proxy type', 'HTTP', ['HTTP', 'SOCKS']]),
4846
OptString.new('PROXY_USERNAME', [ false, "An optional username for HTTP proxy authentification"]),
4947
OptString.new('PROXY_PASSWORD', [ false, "An optional password for HTTP proxy authentification"])
5048
], Msf::Handler::ReverseHttpsProxy)
5149

50+
register_advanced_options(
51+
[
52+
OptAddress.new('ReverseListenerBindAddress', [ false, 'The specific IP address to bind to on the local system']),
53+
OptInt.new('ReverseListenerBindPort', [ false, 'The port to bind to on the local system if different from LPORT' ])
54+
], Msf::Handler::ReverseHttpsProxy)
55+
5256
end
5357

5458
end

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
85+
addrs = bind_address
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
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
236+
port = datastore['ReverseListenerBindPort'].to_i
237+
port > 0 ? port : datastore['LPORT'].to_i
238+
end
239+
240+
def bind_address
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
73+
addrs = bind_address
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
115+
port = datastore['ReverseListenerBindPort'].to_i
116+
port > 0 ? port : datastore['LPORT'].to_i
117+
end
118+
119+
def bind_address
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

modules/payloads/stagers/windows/reverse_https_proxy.rb

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,7 @@ def generate
132132
p[p.length - 4, 4] = [p[p.length - 4, 4].unpack("l")[0] + jmp_offset].pack("V")
133133

134134
# patch the LPORT
135-
unless datastore['HIDDENPORT'].nil? or datastore['HIDDENPORT'] == 0
136-
lport = datastore['HIDDENPORT']
137-
else
138-
lport = datastore['LPORT']
139-
end
135+
lport = bind_port
140136

141137
lportloc = p.index("\x68\x5c\x11\x00\x00") # PUSH DWORD 4444
142138
p[lportloc+1] = [lport.to_i].pack('V')[0]
@@ -146,11 +142,7 @@ def generate
146142

147143
# append LHOST and return payload
148144

149-
unless datastore['HIDDENHOST'].nil? or datastore['HIDDENHOST'].empty?
150-
lhost = datastore['HIDDENHOST']
151-
else
152-
lhost = datastore['LHOST']
153-
end
145+
lhost = bind_address
154146
p + lhost.to_s + "\x00"
155147

156148
end
@@ -161,5 +153,33 @@ def generate
161153
def wfs_delay
162154
20
163155
end
156+
157+
protected
158+
159+
def bind_port
160+
port = datastore['ReverseListenerBindPort'].to_i
161+
port > 0 ? port : datastore['LPORT'].to_i
162+
end
163+
164+
def bind_address
165+
# Switch to IPv6 ANY address if the LHOST is also IPv6
166+
addr = Rex::Socket.resolv_nbo(datastore['LHOST'])
167+
# First attempt to bind LHOST. If that fails, the user probably has
168+
# something else listening on that interface. Try again with ANY_ADDR.
169+
any = (addr.length == 4) ? "0.0.0.0" : "::0"
170+
171+
addrs = [ Rex::Socket.addr_ntoa(addr), any ]
172+
173+
if not datastore['ReverseListenerBindAddress'].to_s.empty?
174+
# Only try to bind to this specific interface
175+
addrs = [ datastore['ReverseListenerBindAddress'] ]
176+
177+
# Pick the right "any" address if either wildcard is used
178+
addrs[0] = any if (addrs[0] == "0.0.0.0" or addrs == "::0")
179+
end
180+
181+
addrs
182+
end
183+
164184
end
165185

0 commit comments

Comments
 (0)