Access Token Manipulation Part 0x02

 · 5 mins read


This is part 2 of Access Token Manipulation blog. In this blog post I’m gonna talk about building a Token Vault to store your stolen tokens in memory.

Linked List

If you are building a C2 and you need to implement token vault into your C2 you may ask yourself what I need to store in the token vault? For sure you will need to store the token, Process ID of that token, TokenIndex, Domain Name,and who is the owner of that process. that’s it. So, Now we know what we need to store into token vault. Let’s answer how to store them?

Actually you can do a Linked List that contains your data for example:

typedef struct  _TOKEN_VAULT
    char User;
    char Domain;
    DWORD ProcessID;
    HANDLE Token;
    INT TokenIndex;
    struct _TOKEN_VAULT* Next;

}TokenVault, * PTokenVault;

Looks simple, right?

Q: Is this a new technique? A: No, many C2s are using that technique. Ref: Metasploit Meterpreter Payload


If you remember in part 1 we built MakeToken, Stealtoken, and Revert2Self functions. 1

So, in this blog, we are going to build three other functions first for adding a token, the second one for listing tokens, and the last one UseToken to reuse tokens in a token vault. So, Let’s get a start in building our header file. Simply we create a linked list to store our data into it.


As we see in the above screenshot we have 5 members in this data structure.

  1. User
  2. Domain
  3. ProcessID
  4. Token
  5. TokenIndex

And lastly we have pointer that point to the next node.

Then we defined our Token Header Ptr. Why is it NULL? because if it NULL that means the Token vault is empty.

and lastly we have defined a prototype of our three functions.


Let’s go through InsertToken Function.


InsertToken function takes 5 arguments as we discussed before. Then we have two other Pointers. One of these new pointers will be used as a new node to hold our data.


Q: Why we assigned NULL to EntryPtr->Next ? A: Because as we discussed before, that pointer will holder the location of the next pointer and as we adding new token that means that’s the last node.

Then we need to check if the HeadPtr is NULL or not. If it NULL that means this is the first add in the token vault. So if it equal NULL we are going to pass the EntryPtr to it.


Q: What if it not equal NULL? A: That means Token vault is not empty. So then we will need to find the last node. do you remember why we assigned NULL to EntryPtr? Becouse its the last node, right! Exactly that what are we going to do now we are going to do a While true until we find the next pointer equal NULL. Then we will modify that Next pointer to our EntryPtr.


Do not forget to set TokenIndex


That’s how we can create a Token Vault.


In the ListToken function we will need to create just one more pointer, that pointer will hold the HeaderPtr data and do a simple loop to extract the whole token.


In the above screenshot, we just check if the HeaderPtr is empty or not.

If not we are going to that loop.


As you see at the end of the loop we move to another node by

CurrentNode = CurrentNode->Next;


So, now what if you need to use one of these stored tokens. It’s so simple you can do like we did in the ListToken function.

  1. Check if the Token Vault isn’t NULL.
  2. Create a new Node.
  3. Loop until you find that the given index equals the CurrentNode->TokenIndex.
  4. Use ImpersonateLoggedOnUser.


Determine the owner of a process

How do determine the owner of a process to store the token in a token vault?

You can call GetTokenInformation function. by passing the Token Handle of that process. and for TokenInformationClass member you can pass TokenOwner to retrieve SID of the user. And to convert the SID to the actual user account you can use LookupAccountSidA

Then store that user account through

CurrentNode->Username = UserAccount;


Take care when we are going to check if the GetTokenInformation returned an error or not in the first call I mean when you NULL the TokenInformation member, It will return ERROR_INSUFFICIENT_BUFFER but that is the normal action when you NULL that member, so do not worry and keep going.

And here is how could you use these APIs.


If you have feedback please go ahead and DM me on Twitter, See you in the next blog post.

Peace out!✌️

Buy Me A Coffee