
baby's first zero day
and why we shouldn't drink and drive(r)
during my summer 2023 internship, i was able to learn a lot about windows driver
reversing and fuzzing. my team was extremely helpful in getting started, but i think
that voidsec
has a really great article going over the specifics of one example. i'll be going
over the the driver i was assigned at the time, which i'll just call X
since idt i'm supposed to say the real name.
who cares
what's the problem? well, in general the kernel usually takes care of memory mappings
and usermode processes never really get the chance to interact. drivers are one of the
few instances where we can get a chance to mess around with memory. if
we can get arbitrary read/write in physical memory, we have ourselves a nice LPE gadget!
windows in particular has a system called signing in order to verify drivers. in recent
memory, i think the mhyprot2.sys driver for genshin impact had such a
vulnerability. that's why the main methodology for this type of attack, BYoD (bring your own driver),
is to search through widely used signed drivers.
preliminary testing
first, we start off by looking at the DriverEntry function, where we can
identify different dispatches to other sections of code. to be honest, i wasn't
very familiar with c# going into this, but i have some (read: too much) with c++. by
doing a lot of back and forth with the windows documentation website, i was able to
slowly piece together.
in particular, i was interested in an unchecked ZwMapViewOfSection call. this is a rare opportunity to be able to interact with virtual memory mappings in the operating system, and
is the major headache for driver vulnerabilities in general.
reaching the call
to reach this call, we have to recreate the control flow of the driver when it usually uses this function. this introduces
us to DeviceIOControl. this API is essentially how the programs can interact with the driver. for mice this
can be maybe changing the rgb, or setting sensitivity, y'know the sort.
switch(IOCTL){ // example from voidsec
case 0xDEADBEEF:
DoThis();
break;
case 0xC0FFEE;
DoThat();
break;
case 0x600DBABE;
DoElse();
break;
}
here, we'll be able to trace the call back to specific ioctl codes as shown
above like 0xDEADBEEF. now, the codes aren't actually random like
this. we can extrat more information out of it by throwing it into a
decoder
to grab device info, accesses, and methods. this will be neccessary once we
actually want to simulate the requests.
the setup is fairly standard: fire up a vm running your target operating system
and another to vm to bind windbg to survey activity. a tangent: i hate windbg,
but if you're interested in a completely pink theme version checkout my dotfiles
on github :3. also, the setup itself will require you to enable and disable a
list of permissions on your tagret, but i was able to find a good tutorial online
just by googling for it. anyways, once we get this attached, with can use an
opensource driver loader like osrloader
to actually get it onto our target system. after this, i ended up using ioctlpus
to actually fire off the ioctl codes to the driver. this is where the extracted
information comes in handy. though do make sure you identify the correct device.
X was strange in that it loaded 10 instances of itself, all of which
seemed to do similar things. it seemed to stem from its functionality as a
support driver for remote debugging.
with the setup complete, let the headbashing begin!
ok but how do we actually get to it
great question champ! i spent the longest time on X since it
seemed like i was so close to getting a write primitive but just wasnt about
able to. the issue came with the fact that this call to
ZwMapViewOfSection wasn't actually completely unchecked. the lower
4 bytes of the input were indeed validated before entry. here i give the credit
to me coworker M! he suggested that we might be able to just bruteforce it. we
were on a 32 bit system, meaning we had a reasonable address space left to
bruteforce for our write.
after bashing my head into the keyboard a few times, i was able to write a patch to integrate this with the system the team already had set up. all that was left was to write a poc to test out the bruteforce mechanic. boom ;-; baby's first zero day.... has been achieved !