Tokenvator Release 3 is a long overdue update that includes a major overhaul to the tool. From the user interface, it will be mostly familiar with some command line tweaks. Under the surface, large portions of the code base have been reworked, and parts of the base have had some updates. In this series, we will go over some of the changes and new features added. Teaser Alert: Adding Privileges & Creating Tokens

Improvements

First and foremost, the user interface. Historically, every action had a series of positional arguments that were clunky and generally difficult to remember. They were also not very flexible, and as the commands started to have more, and additional optional arguments, they became completely unwieldy. These have been replaced with flags that will auto complete.

For instance, to list and enable privileges:

To list and enable privileges

This also works in the non-interactive mode (though it won’t tab complete – sorry, it’s Windows):

Works in the non-interactive mode

Additionally, the scroll back function was improved and numerous bugs were resolved. For instance, now when you press up you will always go to the last command issued. A printable command history has also been added if you want to copy and paste instead or keep a log of your actions.

A printable command history has also been added if you want to copy and paste instead or keep a log of actions.

The info functionality was improved again, removing many bugs and adding additional information, such as impersonation contexts:

(Tokens) > whoami
[*] Operating as NT AUTHORITY\SYSTEM

(Tokens) > info
[*] Primary Token
[+] User:
S-1-5-21-258464558-1780981397-2849438727-1001      DESKTOP-J5KC1AR\0xbadjuju

[*] Impersonation Tokens
[*] Primary Token Groups
[+] Enumerated 15 Groups:
S-1-5-21-258464558-1780981397-2849438727-513       DESKTOP-J5KC1AR\None
S-1-1-0                                            Everyone
S-1-5-114                                          NT AUTHORITY\Local account and member of Administrators group
S-1-5-32-544                                       BUILTIN\Administrators
S-1-5-32-559                                       BUILTIN\Performance Log Users
S-1-5-32-545                                       BUILTIN\Users
S-1-5-4                                            NT AUTHORITY\INTERACTIVE
S-1-2-1                                            CONSOLE LOGON
S-1-5-11                                           NT AUTHORITY\Authenticated Users
S-1-5-15                                           NT AUTHORITY\This Organization
S-1-5-113                                          NT AUTHORITY\Local account
S-1-5-5-0-870189                                   Some or all identity references could not be translated.
S-1-2-0                                            LOCAL
S-1-5-64-10                                        NT AUTHORITY\NTLM Authentication
S-1-16-12288                                       Some or all identity references could not be translated.

Now, you have the option to get additional information by using the /all flag.

(Tokens) > info /all

Option     Value
------     -----
all

[*] Primary Token
[+] User:
S-1-5-21-258464558-1780981397-2849438727-1001      DESKTOP-J5KC1AR\0xbadjuju

[*] Impersonation Tokens
[*] Thread ID: 5820
[+] User:
S-1-5-18                                           NT AUTHORITY\SYSTEM
[*] Thread ID: 1120
[*] Thread ID: 7108
[*] Thread ID: 9180
[*] Thread ID: 1152
[*] Thread ID: 8592
[*] Thread ID: 8076

[*] Primary Token Groups
[+] Enumerated 15 Groups:
S-1-5-21-258464558-1780981397-2849438727-513       DESKTOP-J5KC1AR\None
S-1-1-0                                            Everyone
S-1-5-114                                          NT AUTHORITY\Local account and member of Administrators group
S-1-5-32-544                                       BUILTIN\Administrators
S-1-5-32-559                                       BUILTIN\Performance Log Users
S-1-5-32-545                                       BUILTIN\Users
S-1-5-4                                            NT AUTHORITY\INTERACTIVE
S-1-2-1                                            CONSOLE LOGON
S-1-5-11                                           NT AUTHORITY\Authenticated Users
S-1-5-15                                           NT AUTHORITY\This Organization
S-1-5-113                                          NT AUTHORITY\Local account
S-1-5-5-0-870189                                   Some or all identity references could not be translated.
S-1-2-0                                            LOCAL
S-1-5-64-10                                        NT AUTHORITY\NTLM Authentication
S-1-16-12288                                       Some or all identity references could not be translated.

[+] Source: User32

[*] Enumerating Token Privileges
[*] GetTokenInformation - Pass 1
[*] GetTokenInformation - Pass 2
[+] Enumerated 24 Privileges

Privilege Name                               Enabled
--------------                               -------
SeIncreaseQuotaPrivilege                     False
SeSecurityPrivilege                          False
SeTakeOwnershipPrivilege                     False
SeLoadDriverPrivilege                        False
SeSystemProfilePrivilege                     False
SeSystemtimePrivilege                        False
SeProfileSingleProcessPrivilege              False
SeIncreaseBasePriorityPrivilege              False
SeCreatePagefilePrivilege                    False
SeBackupPrivilege                            False
SeRestorePrivilege                           False
SeShutdownPrivilege                          False
SeDebugPrivilege                             True
SeSystemEnvironmentPrivilege                 False
SeChangeNotifyPrivilege                      True
SeRemoteShutdownPrivilege                    False
SeUndockPrivilege                            False
SeManageVolumePrivilege                      False
SeImpersonatePrivilege                       True
SeCreateGlobalPrivilege                      True
SeIncreaseWorkingSetPrivilege                False
SeTimeZonePrivilege                          False
SeCreateSymbolicLinkPrivilege                False
SeDelegateSessionUserImpersonatePrivilege    False


[+] Owner:
S-1-5-32-544                                       BUILTIN\Administrators

[+] Primary Group:
S-1-5-21-258464558-1780981397-2849438727-513       DESKTOP-J5KC1AR\None

[+] ACL Count: 572

[+] Primary Token
[+] TokenElevationTypeFull
[*] Token: Split
[+] ProcessIntegrity: High

Impersonation Tokens

Previously, I had glossed over Impersonation (Thread) Tokens in the Tokenvator tool. When you impersonate a token, it doesn’t replace your primary token in your process. What it does is place the token in the calling thread. In this tool, this is typically the primary thread. Going forward, I will use Thread Token and Impersonation Token interchangeably.

In this example, we show the privileges on our primary token (List_Privileges), impersonate the SYSTEM account (GetSystem), list the privileges on our primary token again to show it hasn’t been altered (List_Privileges), and then finally list the privileges for the SYSTEM token we are impersonating (List_Privileges /Impersonation).

In the following example, we show the privileges on our primary token (List_Privileges), impersonate the SYSTEM account (GetSystem), list the privileges on our primary token again to show it hasn’t been altered (List_Privileges), and finally list the privileges for the SYSTEM token we are impersonating (List_Privileges /Impersonation).

In this second more complex example, we show the privileges on our primary token (List_Privileges), impersonate the SYSTEM account (GetSystem), list the privileges for the SYSTEM token we are impersonating (List_Privileges /Impersonation).

In this second, more complex example, we show:

  • The privileges on our primary token (List_Privileges)
  • Impersonate the SYSTEM account (GetSystem)
  • List the privileges for the SYSTEM token we are impersonating (List_Privileges /Impersonation)

We then:

  • Disable the SeAssignPrimaryTokenPrivilege on the Thread Token for SYSTEM (Disable_Privilege /Privilege:SeAssignPrimaryTokenPrivilege /Impersonation)
  • List the thread token privileges again (List_Privileges /Impersonation)
  • Re-enable the privilege on the token (Enable_Privilege /Privilege:SeAssignPrimaryTokenPrivilege /Impersonation)
  • List the privileges one last time (List_Privileges /Impersonation) to show that it has been reenabled

This could all be done against a remote process as well by passing /ProcessID:<ID> flag.

Similarly, thread tokens can be impersonated with the Steal_Token command by specifiying the /Thread Flag.

Similarly, Thread Tokens can be impersonated with the Steal_Token command by specifying the /Thread Flag.

Now for the Cool Stuff

The number one request I’ve gotten has been, “Can I add a privilege with this tool?” Until now, that issue has been open on GitHub. I can happily say, I can finally close this issue.

Like Morpheus said, some of these rules can be bent others can be broken. To change the privileges on the token, I’ve historically used advapi32!AdjustTokenPrivileges. This allows for privileges to be enabled, disabled, or removed. As far as I’ve been able to tell, this does not allow for adding privileges onto a token. But because that doesn’t work, it doesn’t mean that there are no other options. It’s time to enter the world of the kernel.

Exploring the Kernel

To look at the Windows kernel, you will probably need WinDbg. It involves installing several development kits from Microsoft (https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/getting-started-with-windbg–kernel-mode-). A local instance of the debugger can be started from an elevated command prompt: 

  • “C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\kd.exe” -kl
Exploring the Kernel

From here we can start exploring.

Opaque Structures

As expansive as Microsoft Developer Network (MSDN) is, it is not all-encompassing. There are things that are intentionally not documented as they are not intended to be used. Among these is the EPROCESS structure. 

Part of this is that this structure can change without notice from Microsoft. I can personally confirm that this happened. While it may be difficult to track down the layout of this structure online, we can easily view it with WinDbg. Using the dt command in WinDbg we can view each instance of it.

Exploring with windbg

Let’s look at the process structure of an elevated Tokenvator instance:

It’s running with process ID of 8140, converted to hex it is 1FCC.

Process ID of 8140

Examining that process shows:

Exploring windbg proces

The line we are looking for is:

  • PROCESS ffff9a890b963080

The EPROCESS structure can be found at is at address ffff9a890b963080. Querying for the EPROCESS structure:

Querying for the EPROCESS structure

It’s mostly truncated here, but it’s big. Really big. Excluding the KPROCESS structure which takes up the address 0x000 – 0x438 it has 238 entries.

dt nt!_EPROCESS ffff9a890b963080
   +0x000 Pcb              : _KPROCESS
  …
   +0x460 PrimaryTokenFrozen : Pos 15, 1 Bit
  …
   +0x4b8 Token            : _EX_FAST_REF
  …
   +0xa10 DynamicEnforcedCetCompatibleRanges : _PS_DYNAMIC_ENFORCED_ADDRESS_RANGES

But in this structure, there is a field called Token which references the _EX_FAST_REF structure.

Querying the _EX_FAST_REF structure for the Token field shows the following.

Querying the _EX_FAST_REF structure for the Token field shows the following.

If we were query that address for a _TOKEN structure it wouldn’t work but looking the verbose process information with the command.

If we were query that address for a _TOKEN structure it wouldn’t work but looking the verbose process information with the command.

I didn’t immediately realize why the addresses were different. Fortunately, the ired.team was able to provide a useful insight:. they realized a bitwise AND (&) would correct the address.

We can see that it is at a similar address, now at this point I need to that the ired.team blog for getting me unstuck. They realized a bitwise and would correct the address.

Evaluate expression: -65372684652448 = ffffc48b`3c5a7060

Querying that address for the token we see a structure where the privileges are stored. 

Querying that address for the token we see a structure where the privileges are stored.

Querying that field reveals a structure that contains the present field where a bitwise or for each privilege can detect if it is present.

Querying that field reveals a structure that contains the present field where a bitwise or for each privilege can detect if it is present.

AND’ing that field can allow us to put privileges back on the token. 

Pulling it All Together

We’ve found what needs to be changed in the kernel, so how do we do that? Well, that involves creating a kernel mode driver that can interact with kernel memory. Introducing: the KernelTokens driver. 

This introduces several additional commands:

  • install_driver
  • start_driver
  • uninstall_driver
  • add_privilege
  • freeze_token
  • unfreeze_token

First, we need to install the driver. The default name is TokenDriver.

First, we need to install the driver. The default name is TokenDriver.

Now, let’s look at the existing privileges on the Tokens:

In this instance we see at the start there are 24 privileges. Let’s add two privileges SeTcbPrivilege and SeCreateTokenPrivilege.

In this instance we see at the start there are 24 privileges. Let’s add two privileges SeTcbPrivilege and SeCreateTokenPrivilege. First, we run the command Add_Privilege /Privilege:SeTcbPrivilege. This connects to the driver and updates the bitfield in memory. Running List_Privileges again we see SeTcbPrivilege is now on the token. Running the Add_Privilege /Privilege:SeCreateTokenPrivilege command again allows us to add this privilege as well. As can be seen during the final List_Privileges command, 26 privileges are now present on the token including SeTcbPrivilege and SeCreateTokenPrivilege.

Causing Some Shenanigans

Critical Processes are a fun flag that can be added to a process to indicate that it is critical to the system functionality. This can be used to force a system to blue screen, or in some cases prevented the process from being killed.

Critical Processes are a fun flag that can be added to a process to indicate that it is critical to the system functionality.

When it does, well…

This can be used to force a system to blue screen or in some cases prevented the process from being killed.

Becoming Someone Else:

One of the interesting things that I always wanted to add was the ability to become another user on the system without having to steal their token from a running process. There are several ways to accomplish this with increasing levels of difficulty:

  • RunAs
  • Logon_User
  • Create_Token

Each one of these methods calls a different API.

RunAs

The RunAs is almost identical to the RunAs /netonly command. Under the surface this is just calling CreateProcessWithLogonW.

The RunAs is almost identical to the RunAs /netonly command. Under the surface this is just calling CreateProcessWithLogonW.

Logon_User

Logon_User is a little more complex, depending on the options provided it is either calling LogonUser or LogonUserExExW (no, not a typo) and then uses the newly created token to call CreateProcessWithTokenW.

Logon_User is a little more complex, depending on the options provided it is either calling LogonUser or LogonUserExExW (no, not a typo) and then uses the newly created token to call CreateProcessWithTokenW.

Using this we can become any user we have credentials for as well as local service accounts such as Network Service or Local Service.

Create_Token

Lastly, the final technique for this part of the post is create_token. Under the surface this calls ntdll!CreateToken – this is a bit of a bear. This manually crafts the token from scratch and then calls CreateProcessWithTokenW.

This manually crafts the token from scratch and then calls CreateProcessWithTokenW.

As can be seen above, with this we can become disabled users and ephemerally add them to groups by adding the group onto the token at creation time.

This release can now be accessed on GitHub. To download and learn more about Tokenvator visit: https://github.com/0xbadjuju/Tokenvator.

Discover how NetSPI ASM solution helps organizations identify, inventory, and reduce risk to both known and unknown assets.

X