SeImpersonatePrivilege
Overview
The SeImpersonatePrivilege, also known as the Impersonate a client after authentication privilege, is a Windows security privilege that allows a process to impersonate another user or security principal.
This privilege is assigned by default to the built-in Network Service, the LocalService account, the default IIS account and the default MSSQL service account.
Using SeImpersonatePrivilege for privilege escalation
If we have the SeImpersonatePrivilege privilege, we can often use the Win32 DuplicateTokenEx API to create a primary token from an impersonation token and create a new process in the context of the impersonated user.
Named pipes
Named pipes are a type of inter-process communication (IPC) mechanism available in Windows operating systems. They are used to transfer data between one or more processes on the same machine. Named pipes are a simple way to implement a client/server model of communication between processes.
Creating named pipe and impersonating token of authenticating users
This technique leverages the following below kernel32 APIs.
CreateNamedPipe - This API is used to create a named pipe, which is a communication channel that can be used for inter-process communication between two or more processes on the same machine. The named pipe can be used for both client-server and peer-to-peer communication.
ConnectNamedPipe - This API is used to establish a connection between a named pipe server and a client. The server must have already created a named pipe using CreateNamedPipe, and this API is called by the client to connect to the named pipe.
ImpersonateNamedPipeClient - This API is used to impersonate a named pipe client to perform operations on behalf of that client. It is often used in server applications that need to access resources on behalf of a client, such as file or printer access.
DuplicateTokenEx - This API is used to create a new access token that is a duplicate of an existing access token. The new access token can be used to impersonate the same user as the original token, but with different levels of access or privileges.
CreateProcessWithTokenW - This API is used to create a new process using the security context of an existing user or service account. It allows a process to be created with elevated privileges or a different set of permissions than the currently logged-in user. This API is commonly used in system services or other applications that need to run with elevated privileges.
Code example
Explaination
Firstly, we will create a named pipe.
Then we will connect to our named pipe and wait for another client to connect.
Once another client to connects we will impersonate the in incoming connection.
We'll then open a handle to the impersonated token.
Duplicate the stolen token.
And spawn a new process with the duplicated token.
Creating a named pipe
pipeName
: This is a string that specifies the name of the named pipe. It must follow certain rules for naming pipes, such as starting with\\.\pipe\
.(uint)PipeOpenModeFlags.PIPE_ACCESS_DUPLEX
: This specifies the type of access that can be requested for the pipe. In this case,PIPE_ACCESS_DUPLEX
indicates that the pipe can be used for both reading and writing.(uint)PipeModeFlags.PIPE_TYPE_BYTE | (uint)PipeModeFlags.PIPE_WAIT
: These are flags that specify the behavior of the pipe.PIPE_TYPE_BYTE
indicates that the pipe operates in byte mode (as opposed to message mode), andPIPE_WAIT
indicates that the pipe is blocking (as opposed to non-blocking).10
: This is the maximum number of pending connections that can be queued for this pipe.0x1000
: This is the size of the input buffer for the pipe, in bytes.0x1000
: This is the size of the output buffer for the pipe, in bytes.0
: This is the default timeout for the pipe, in milliseconds.IntPtr.Zero
: This is a pointer to a security attributes structure, which is not used in this case (hence the value of zero).
Connect to our named pipe
pipeHandle
: This is a handle to the named pipe that was returned byCreateNamedPipe
. It identifies the pipe that should be connected.IntPtr.Zero
: This is a pointer to an overlapped structure, which is not used in this case (hence the value of zero). An overlapped structure is used to perform asynchronous I/O operations, but in this case theConnectNamedPipe
function will block until a client connects to the named pipe.
Impersonate incoming connection thread
Open handle to thread
GetCurrentThread()
: This is a function that returns a handle to the current thread. The access token associated with this thread will be opened.(uint)DesiredAccess.TOKEN_ALL_ACCESS
: This is a bitmask that specifies the desired access rights to the token. In this case,TOKEN_ALL_ACCESS
indicates that the caller wants to have full access to the token.false
: This parameter specifies whether to open the primary or impersonation token. In this case,false
indicates that the primary token should be opened.out tokenHandle
: This is an output parameter that will contain a handle to the opened access token, if the function succeeds.
Duplicate stolen token
tokenHandle
: This is a handle to the original token object that we want to duplicate.0xF01FF
: This is a combination of flags that specify the access rights that the new token should have. In this case, the flag value0xF01FF
corresponds toTOKEN_ALL_ACCESS
, which grants all possible access rights to the token.IntPtr.Zero
: This parameter is not used in this case, so it is set toIntPtr.Zero
.2
: This parameter specifies the security impersonation level for the new token. A value of2
corresponds toSecurityImpersonation
, which means that the new token can be used to impersonate the security context of the original token.1
: This parameter specifies the type of the new token. A value of1
corresponds toTokenPrimary
, which means that the new token is a primary token that can be used to create a new process.systemTokenHandle
: This is an output parameter that will contain a handle to the new token object that is created.
Spawn a new process with the duplicated token
PROCESS_INFORMATION pi = new PROCESS_INFORMATION()
: This is a structure that will contain information about the new process that is created.STARTUPINFO si = new STARTUPINFO()
: This is a structure that contains information about how the new process should be started.si.cb = Marshal.SizeOf(si)
: This line sets thecb
field of theSTARTUPINFO
structure to the size of theSTARTUPINFO
structure itself. This is required by theCreateProcessWithTokenW
function.CreateProcessWithTokenW(sysToken, 0, null, "C:\\Windows\\System32\\cmd.exe", 0, IntPtr.Zero, null, ref si, out pi)
: This is the function that creates the new process. Here is an explanation of the parameters:sysToken
: This is the access token that should be used to create the new process. The token must have theTOKEN_DUPLICATE
andTOKEN_IMPERSONATE
access rights.0
: This parameter is not used in this case, so it is set to zero.null
: This parameter specifies the name of the application to be executed. In this case, no application name is specified, so this parameter is set to null."C:\\Windows\\System32\\cmd.exe"
: This parameter specifies the command line to be executed. In this case, thecmd.exe
command shell is executed.0
: This parameter specifies the creation flags for the new process. In this case, no special flags are specified, so this parameter is set to zero.IntPtr.Zero
: This parameter specifies the environment block for the new process. In this case, the default environment block is used, so this parameter is set to IntPtr.Zero.null
: This parameter specifies the current directory for the new process. In this case, the default current directory is used, so this parameter is set to null.ref si
: This parameter is a reference to theSTARTUPINFO
structure that was created earlier. It specifies how the new process should be started.out pi
: This parameter is a reference to thePROCESS_INFORMATION
structure that was created earlier. It will contain information about the new process that is created.
Last updated