PowerShell and Token Impersonation

This post will discuss bringing incognito-like functionality to PowerShell in the form of a new PowerShell script (Invoke-TokenManipulation), with some important differences. I’ll split this post up in to three sections:

  1. An overview on tokens and Windows authentication
  2. An overview of what the script does, and problems/solutions encountered when building it
  3. A demonstration of the script

Even if you think you know how tokens work, I’d recommend reading the token overview because it highlights differences between this script and incognito.

Why bother with this script? As many of you may know, Windows 8.1 introduces changes that make pass-the-hash style attacks more difficult. As part of this effort, LSASS can be turned in to a protected process (which should make dumping credentials harder). One way to get around this protection is to load a kernel driver and disable the protected process flag (Mimikatz 2.0 already has this built in). Unfortunately, installing a kernel driver might be noticed.

Another solution to the pivoting problem is to simply ignore credentials and instead impersonate the security tokens of logged on users you’d like to pivot with.

Token Overview

I’ll start this off by stating that you should read the Windows Internals books if you want a more complete overview of how stuff in Windows works. This will be a brief description to give users helpful background knowledge.

So what is a security token? In a nutshell, a security token is something that identifies a user. Whenever you create a process, it has a token associated with it so the system knows things like:

  • Is the process being run under an elevated context (UAC)
  • What privileges does the process have (such as SE_DEBUG_PRIVILEGE)
  • Can the process access a specific resource it requested access to?

Threads in a process use the processes security token by default, but they can also impersonate other users security tokens. For example, a user can authenticate to a service and the service can impersonate the users security token, allowing the service to perform actions on the users behalf. When new threads are created, they use the security token of the process (not the security token of the thread which created the new thread).

When a user logs in to Windows in a domain environment, they can visit authenticated network resources without re-entering their credentials thanks to Single Sign-On. Windows caches the credentials of the user so the user doesn’t need to be prompted for a password every time they access a network resource. The credentials are cached in the LSASS process, and Windows determines which credentials to use with SSO based on the security token of the process/thread.

Not all tokens can be used to authenticate to network resources. Why not? To authenticate to network resources, you need credentials. Windows has two general ways of authenticating to a remote system:

  • Network logon: In this logon type, the client proves to the server it knows the correct credential without giving it to the server. This can be done using NTLM authentication or using Kerberos authentication. The remote server caches no user credentials because it was never sent them.
  • Non-network logon: This includes things like Network Clear-text and Interactive logons.  These logon types send the users clear-text password to the server during authentication. The server can cache this password (and NTLM hash, and Kerberos TGT) in LSASS and use it to authenticate to other resources.

When a user authenticates using Network Logon, the user can logon to the remote server but will not be able to logon to other resources from the remote server. This is because the remote server doesn’t have any credentials cached for the user to authenticate with. If you want to do a “double hop”, meaning authenticate to a remote server, and from that server to another resource, you must provide credentials to the first hop.

Ultimately, the logon type is all that matters when determining if a token has credentials associated with it (and can therefore be used to connect to remote resources). Tokens created from network logons do not have credentials associated with them, and are therefore not useful to authenticate to other servers.

You may have noticed that incognito lists tokens in to two categories: Impersonation and delegation. When a client connects to a server, the client can specify what level of impersonation it would like it’s token to have on the server. The impersonation level “impersonation” allows the token to be used on the current server but not over the network. The impersonation level “delegation” allows the token to be used over the network; HOWEVER, this can only happen if the token has credentials associated with it. Remember, the token itself doesn’t go over the network; the credentials associated with the token go over the network.

If you’ve ever impersonated a “delegation” token and then failed to make a network connection using the token, this is the culprit. A lot of clients will authenticate with full delegation privileges, but only do a network logon. Even though the token could be used to authenticate to resources off box, it has no credentials to do so.

Token impersonation levels (impersonate, delegate, etc..) only apply to “Impersonation Tokens”. Impersonation tokens are tokens that are created when a thread impersonates another user. The second type of token is a “Primary Token”, which is the type of token associated with a process. Primary tokens don’t have impersonation levels; they are equivalent to an impersonation token with the delegation impersonation level from an attacker perspective.

When running as an administrator (which my script requires), you can turn a token, including an impersonation token, in to a primary token. So don’t worry about impersonation vs. delegation tokens, just make sure the token you choose wasn’t created by a Network Logon (type 3).

Script Overview:

What does it do?

Invoke-TokenManipulation allows you to enumerate all available security tokens on a system. You can create new processes with these tokens (run processes as another user without needing their password) or you can make the current PowerShell thread impersonate one of the tokens (which has issues, see below).

All right, so how does this script actually work?

First, you must enumerate the tokens on the system:

  1. Enumerate all processes
  2. Call OpenProcess to get a handle to each process
  3. Call OpenProcessToken to get the token of the process
  4. Enumerate all threads
  5. Call OpenThread to get a handle to each thread
  6. Call OpenThreadToken to get the token of the thread (if it has one)
  7. Call GetTokenInformation to retrieve information about the token such as if it is elevated, who it belongs to, and what privileges it has

Now the script has a list of the tokens available on the system. It’s worth noting that protected processes cannot be opened with the permissions required to capture their token.

To impersonate a users token:

  1. Call DuplicateTokenEx to get a copy of the token being impersonated
  2. Call ImpersonateLoggedOnUser to impersonate the token

To create a process using a users token:

  1. Call DuplicateTokenEx to get a copy of the token being impersonated
  2. Call CreateProcessWithTokenW to create a process using the specified token

I ended up running in to a few issues when writing this script.

1. Impersonation Issues

The first impersonation feature I implemented was the ability to impersonate a user with the current PowerShell thread. Unfortunately, I wasn’t able to authenticate off box using PowerShell remoting after impersonating the user (it would authenticate using the token of the process, not the thread). I haven’t done any disassembly, but I suspect that PowerShell is multithreaded; when you attempt to do PowerShell remoting, PowerShell likely spins up a new thread that inherits the token of the process, not the current threads token. This means the best way to use the script is to create new processes with alternate tokens.

2. GUI Issues

After I realized that impersonating users in the current thread wouldn’t work well in PowerShell, I set out to create processes using a users token. Whenever a new thread is created in a process, it uses the token of the process. If you can launch the PowerShell process using an alternate token, all threads inside the PowerShell process will also use the alternate token.

I was able to use the CreateProcessWithTokenW function to accomplish this, but I had an issue. When launching new processes as “NT AUTHORITY\SYSTEM”, everything worked fine. When launching new processes as other users, only part of the GUI was rendered. The process did run correctly, but you couldn’t interact with it.

The GUI of applications only partially renders due to the file permission of the Window Station and Desktop objects.

The GUI of applications only partially renders due to the file permission of the Window Station and Desktop objects.

In Windows, many default ACL’s give “NT AUTHORITY\SYSTEM” full permission and other users partial permission. Given that everything worked as SYSTEM, but the GUI only partially rendered when run as another user, I figured there was a permission issue with the Windows Station and Windows Desktop objects. Sure enough, adding an ACL to grant the “Everyone” group full control of my Window Station and Desktop (“winsta0\default”) did the trick. You can now create a process as any user and have a fully functional GUI.

Processes can now be launched with a full GUI.

Processes can now be launched with a full GUI.

Script Demonstration:

List unique tokens available on a system:

PS C:\Github\PowerShell\Invoke-TokenManipulation> invoke-tokenmanipulation

Domain : NT AUTHORITY
Username : NETWORK SERVICE
hToken : 3928
LogonType : 5
IsElevated : True
TokenType : Primary
SessionID : 0
ProcessId : 668

Domain : NT AUTHORITY
Username : SYSTEM
hToken : 3692
LogonType : 0
IsElevated : True
TokenType : Primary
SessionID : 3
ProcessId : 2296

Domain : DEMO
Username : non-admin
hToken : 3904
LogonType : 2
IsElevated : True
TokenType : Primary
SessionID : 3
ProcessId : 2764

Domain : DEMO
Username : Administrator
hToken : 3912
LogonType : 2
IsElevated : True
TokenType : Primary
SessionID : 2
ProcessId : 1228

Here’s an example of using the script to attack a user on a system running Windows 8.1 with LSASS set to be a protected process. You could install a kernel driver to turn off the protected process, or you could be a little sneakier and use this script:

First, create a new PowerShell process running as “demo\administrator”, a domain admin who is logged on to the Windows 8.1 system:

Invoke-TokenManipulation –CreateProcess “c:\windows\system32\windowspowershell\v1.0\powershell.exe” –Username “demo\administrator”

Then run Invoke-Mimikatz in the new PowerShell window against the domain controller (not running Windows 8.1) to get the clear-text password of all users logged in to the domain controller:

Invoke-Mimikatz –Computername “dc1.demo.local”

Since Invoke-Mimikatz is run from the PowerShell window created using “demo\administrators” token, it will authenticate over the network as the domain administrator.

References

Last but not least, I’d like to thank Matt Graeber for the debugging help and taking the time to review the script.

Tagged with: , , , , ,
Posted in Hacking, PowerShell, Uncategorized
3 comments on “PowerShell and Token Impersonation
  1. Meatballs says:

    You said you couldn’t get powershell to impersonate a token possibly due to multithreaded. Did you try with powershell -sta?

  2. Nomi says:

    Hey, awesome work on this script. Something like this is actually very useful for software packaging and Sys Admins that have to deploy scripts and software to users across a network. There is actually work going on in this thread to modify your work a little so it can be used for software packaging and scripting deployments in a managed enterprise setting. I’m sure any help you could give would be greatly appreciated.

    https://psappdeploytoolkit.codeplex.com/discussions/465270

Leave a comment