Token Theft
"I adore you. Tell him if you must, I no longer care. I mean to have you even if it must be burglary."
FINALLY, WE ARRIVE!
To briefly summarize our prior post, Primary and Delegate Tokens are an extension of the user's identity and will show up pretty much anywhere the user does and some places they don't.
They also allow us to more or less become the user and that's a feature not a bug.
Token Theft
Token theft is sort of a catchall term for the process by which an attacker will gain control of your access tokens (either Primary or Delegate) and then run code from within that security context.
There are a few different ways of doing this.
Reflective DLL Injection
Let's talk a little about the Brown-Headed Cowbird.
The Brown-Headed Cowbird is a brood parasite, which is a fancy way for saying it's a shithead.
When the Brown-Headed Cowbird ready to lay an egg, it will replace another bird's egg with its own, allowing the unsuspecting bird to hatch and raise the Cowbird chick. Since Cowbirds usually hatch early, they'll get the most food and generally fare better than the actual offspring of the nest's owner.
This is more or less what happens with reflective DLL injection. You use an existing good, hard working process to hatch your own, more evil, threads.
Here's what happens:
- Your evil process is loaded into memory using the
LoadLibraryA()
function or jumping toDllMain
. - Evil process attaches to the target process using the
OpenProcess()
function. - Evil process uses the
VirtualAllocEx()
function to allocate memory within the target process. - Evil process copies evil DLL into the target processes memory.
- Evil process uses
CreateRemoteThreat()
orNtCreateThreadEx()
to create an evil thread in the target process.
When you use the migrate
command in a Meterpreter shell, you're using Reflective DLL Injection. There's a lot of memory manipulation here, so you're going to need either Administrator or SeDebugPrivilege privileges, but for your trouble you get control of a thread that, as we learned earlier, inherits the security context of its parent.
A simple way of thinking about this is that the administrator of a system can assume the identify of any user with an active process on that system. As we learned earlier, these processes are usually the result of interactive logons.
An even simpler way to think about this is that any user logging onto a compromised machine is compromised.
Spawn Process With User's Token
If the brood parasite is a CTRL+X
, CTRL+V
, spawning a process is more of a CTRL+C
, CTRL+V
. We just create a new process using any access token present on the system.
Here's what shakes down:
- Call
DuplicateTokenEx
, which duplicates an existing access token. - Call
CreateProcessWithTokenW
to create a new process with the duplicated access token attached to it.
Now we have a process under our control with the rights and privileges of someone else. That's a bad day if you happen to be that someone else.
Attach User's Token to Current Thread
I am out of clipboard analogies.
This is almost the same as the previous method, but insead of spawning a shiny new process, the thread calling the function inherits the security context of the target user. That's a fancy way of saying it copies its token.
- Call
DuplicateTokenEx
, which duplicates an existing access token - Call
ImpersonateLoggedOnUser
to attach the token to the current thread.
Example Attack
Here's a practical example of how a token theft attack may play out. This example uses the reflective DLL injection technique we talked about earlier.
- Attacker sends a spear phishing email to a user who clicks the link. Malicious code is executed, and a remote shell is launched in a process that inherits the user's access token.
- Since the user is a local administrator, the attacker's Meterpreter shell is also running with administrator privileges.
- Attacker launches
ps
and finds that there is a process (av.exe
) linked to a service running under a domain account, NULL\svc_antivirus. - Attacker runs
net user "svc_antivirus" /domain
and finds that the user is a member of Domain Admins. - Attacker uses
migrate
orpsinject
to inject a malicious DLL into the av.exe process, gaining access to the NULL\svc_antivirus token. - Attacker runs
net user evilaccount evilpassword /ADD /DOMAIN
to create an evil account, followed bynet group "Domain Admins" evilaccount /DOMAIN /ADD
to add it to Domain Admins. Game over.
The above attack could just as easily have happened on a web server with Delegation privileges to connecting users. Either way, once you hit step 5 and the attacker has access to the token, it's pretty much game over.
ELI5
In almost every case, a user logging onto a system using anything other than a Type 3 (network) logon will create Primary or Delegate Tokens. These can be stolen by anyone with local Administrator privileges on that machine, allowing them to effectively become that user. This also applies to scheduled tasks and the accounts used to run services.
Use the technical levers you have to restrict this access wherever possible, and ensure that operationally you don't undermine the whole thing by having admins in more than one group (e.g. jdoe is a Domain Admin and a Workstation Admin).
I have prepared a selection of hand-crafted free range artisinal levers for your perusal. See you in a few weeks :)
Resources
- CreateProcessWithTokenW function
- DuplicateTokenEx function
- Fun with Incognito
- How Access Tokens Work
- How Does Process Migration Work in Meterpreter
- ImpersonateLoggedOnUser function
- Security Implications of Windows Access Tokens – A Penetration Tester’s Guide
- When the manual is not enough – runas /netonly, Unexpected Credential Exposure and the Need for Reality Based Holistic Threat Models
- Windows DLL Injection Basics