Let’s explore Windows Impersonation, a technique in Asp.Net development that allows a thread to execute under the identity of a different user than the one running the process.
Every process runs under a specific user’s security context. This means the user’s Access Token, known as a Primary Token, is attached to the process and used for security checks whenever the process attempts to access secure resources. Threads within a process may or may not have their own Access Token. When a thread has an associated Access Token, called an Impersonation Token, it utilizes this token for validating access to secure objects. If no impersonation is in place, the process’s Primary Token is used. For a deeper dive into this, refer to here.
An Access Token holds security details for a logon session. It’s created upon user login, and each process running on behalf of the user receives a copy. This token identifies the user, their groups, and privileges. The system leverages this token to manage access to secure objects and govern the user’s ability to perform system-related tasks on the local machine. There are two types of access tokens: primary and impersonation.
Threads are created without an Impersonation Token, inheriting the security context of their parent process. This holds true whether or not the parent thread itself is impersonating. Similarly, when a new process is spawned, the “impersonation status” of the calling thread has no bearing on the new process; it receives its own Primary Token mirroring the calling process, unless explicitly run as a different user via methods like CreateProcessAsUser, CreateProcessWithLogonW, or CreateProcessWithTokenW. This process is well-detailed in here.
Threads, upon creation via CreateThread
(and its .Net counterparts), do not receive an Impersonation Token by default. They can, however, impersonate at a later stage during execution and revert back if needed. This involves obtaining a Primary Token and subsequently using it to generate an Impersonation Token.
Since the .Net Base Library lacks direct managed equivalents for this, PInvoke comes into play:
|
|
Here’s how it’s used:
|
|
Creating a process under a different account with known credentials is directly supported by the Base Library:
|
|
The necessity to construct a SecureString by individually appending characters, rather than directly using a string constructor, might seem unusual.
Note the two impersonation methods: one accepting username and password, the other an Access Token. This mirrors the Win32 API, where some functions work with user credentials, and others with tokens. In .Net, obtaining the identity of the running thread (impersonated or not) is straightforward:
|
|
This WindowsIdentity object provides access to its associated token through Token property. However, it only returns a handle (IntPtr) to the token. To manipulate token fields, you would need to utilize native GetTokenInformation and SetTokenInformation functions.