Token Theft

Token theft in kernel exploitation refers to the act of acquiring and impersonating the access token of a privileged process or user. Here, we will manually assign tokens in the debugger.

In the Windows OS, Access Tokens are stored in the kernel's Non-Paged Pool memory. The Non-Paged Pool is a region of memory that is always kept in physical memory and not paged out to disk, ensuring fast and consistent access.

Access Tokens contain information about the security context of a user or process, including user account information, group memberships, privileges, and more.

These tokens are created and managed by the Windows security subsystem and are stored in the kernel's memory space for efficient access and enforcement of security policies.

The _EPROCESS structure, part of the kernel's representation of a process, contains a pointer to a token at offset 0x385 (this may vary on versions of Windows):

The System process always has a PID (process ID) of 4. This is helpful to us. If we can exploit the kernel we can essentially enumerate the System process find out the address of the token it is pointing to, copy the address and assign it to the token pointer in an arbitrary process:

This would be carried out in shellcode as part of a privilege escalation exploit. To understand how this works we can also do it manually by using the debugger.

System Process Context

Make sure Windbg Preview is connected to the Windows 10 host.

On the debugger, break into the kernel and locate the System process:

0: kd> !process 0 0 System

Use the process address to set the process context:

0: kd> .process ffffad8309e1f040
Implicit process is now ffffad83`09e1f040
WARNING: .cache forcedecodeuser is not enabled

Note: the process address will differ on your host.

We can view the _EPROCESS object associated with the System process by using the ?? @&proc command.

When the structure is displayed, locate the Token property. This is located at +0x358. Click on this property:

Note: if you cannot click on the Token property, you may have Debugger Markup Language (DML) disabled; enable it by typing .prefer_dml 1.

0: kd> dx -id 0,0,ffffad8309e1f040 -r1 (*((ntkrnlmp!_EX_FAST_REF *)0xffffad8309e1f398))
(*((ntkrnlmp!_EX_FAST_REF *)0xffffad8309e1f398))                 [Type: _EX_FAST_REF]
    [+0x000] Object           : 0xffff970947417044 [Type: void *]
    [+0x000 ( 3: 0)] RefCnt           : 0x4 [Type: unsigned __int64]
    [+0x000] Value            : 0xffff970947417044 [Type: unsigned __int64]

This indicates that the token pointer is located at 0xffffad8309e1f398. We can find what the address is of the System context token:

0: kd> dq 0xffffad8309e1f398 L1
ffffad83`09e1f398  ffff9709`47417044

The token is located at address ffff970947417044. We should keep a note of this for later (again this will differ on your host).

Low Privileged Process

Issue the g command, then go to the target machine and run a new cmd.exe process in a low privileged context.

Issue the whoami command in the command console:

We can now go back to the debugger and pause the target host and find the address of the new process:

0: kd> !process 0 0 cmd.exe

[ommitted for brevity]

0: kd> .process ffffad8309eea080
Implicit process is now ffffad83`09eea080
WARNING: .cache forcedecodeuser is not enabled

We can view the _EPROCESS object associated with the new process by using the ?? @&proc command.

Again we can locate the Token property, this time we are going to overwrite the token it points to:

0: kd> dx -id 0,0,ffffad8309eea080 -r1 (*((ntkrnlmp!_EX_FAST_REF *)0xffffad8309eea3d8))
(*((ntkrnlmp!_EX_FAST_REF *)0xffffad8309eea3d8))                 [Type: _EX_FAST_REF]
    [+0x000] Object           : 0xffff97094e221066 [Type: void *]
    [+0x000 ( 3: 0)] RefCnt           : 0x6 [Type: unsigned __int64]
    [+0x000] Value            : 0xffff97094e221066 [Type: unsigned __int64]

Take the address of the privileged token and assign it to the command console process:

0: kd> eq 0xffffad8309eea3d8 ffff9709`47417044

Press g to continue the target host. In the command console issue the whoami command again and observe the change:

This section showed how we can use the debugger to assign the System privileged token to other processes. Whilst this is interesting and insightful, leveraging this technique using shellcode is a bit more involved. This will be discussed in a later section.

Demo

Work in progress

Last updated