Skip to content

Instantly share code, notes, and snippets.

@jborean93
Created June 2, 2021 20:27
Show Gist options
  • Save jborean93/33c55bdd47541866dfaea43ab38d2c79 to your computer and use it in GitHub Desktop.
Save jborean93/33c55bdd47541866dfaea43ab38d2c79 to your computer and use it in GitHub Desktop.
Creates a process running as SYSTEM
. $PSScriptRoot\Start-ProcessEx.ps1
Add-Type -Namespace Runas -Name NativeMethods -UsingNamespace @(
'Microsoft.Win32.SafeHandles',
'System.ComponentModel',
'System.Security.Principal'
) -MemberDefinition @'
[DllImport("Advapi32.dll", EntryPoint = "DuplicateTokenEx", SetLastError = true)]
private static extern bool NativeDuplicateTokenEx(
SafeHandle hExistingToken,
TokenAccessLevels dwDesiredAccess,
IntPtr lpTokenAttributes,
int ImpersonationLevel,
int TokenType,
out SafeFileHandle phNewToken
);
public static SafeHandle DuplicateTokenEx(SafeHandle existingToken, TokenAccessLevels access, int tokenType,
int impLevel)
{
SafeFileHandle dupToken;
if (!NativeDuplicateTokenEx(existingToken, access, IntPtr.Zero, impLevel, tokenType, out dupToken))
throw new Win32Exception();
return dupToken;
}
[DllImport("Advapi32.dll", EntryPoint = "ImpersonateLoggedOnUser", SetLastError = true)]
private static extern bool NativeImpersonateLoggedOnUser(
SafeHandle hToken
);
public static void ImpersonateLoggedOnUser(SafeHandle token)
{
if (!NativeImpersonateLoggedOnUser(token))
throw new Win32Exception();
}
[DllImport("Advapi32.dll", EntryPoint = "RevertToSelf", SetLastError = true)]
private static extern bool NativeRevertToSelf();
public static void RevertToSelf()
{
if (!NativeRevertToSelf())
throw new Win32Exception();
}
[DllImport("Kernel32.dll", EntryPoint = "OpenProcess", SetLastError = true)]
private static extern SafeFileHandle NativeOpenProcess(
int dwDesiredAccess,
bool bInheritHandle,
int dwProcessId
);
public static SafeHandle OpenProcess(int processId, int access, bool inherit)
{
SafeFileHandle processHandle = NativeOpenProcess(access, inherit, processId);
if (processHandle.IsInvalid)
throw new Win32Exception();
return processHandle;
}
[DllImport("Advapi32.dll", EntryPoint = "OpenProcessToken", SetLastError = true)]
private static extern bool NativeOpenProcessToken(
SafeHandle ProcessHandle,
TokenAccessLevels DesiredAccess,
out SafeFileHandle TokenHandle
);
public static SafeHandle OpenProcessToken(SafeHandle process, TokenAccessLevels access)
{
SafeFileHandle tokenHandle;
if (!NativeOpenProcessToken(process, access, out tokenHandle))
throw new Win32Exception();
return tokenHandle;
}
[DllImport("Kernel32.dll", EntryPoint = "ProcessIdToSessionId", SetLastError = true)]
private static extern bool NativeProcessToSessionId(
int dwProcessId,
out int pSessionId
);
public static int ProcessToSessionId(int processId)
{
int sessionId;
if (!NativeProcessToSessionId(processId, out sessionId))
throw new Win32Exception();
return sessionId;
}
[DllImport("Advapi32.dll", SetLastError = true)]
private static extern bool SetTokenInformation(
SafeHandle TokenHandle,
int TokenInformationClass,
IntPtr TokenInformation,
int TokenInformationLength
);
public static void SetTokenSessionId(SafeHandle token, int sessionId)
{
byte[] sessionBytes = BitConverter.GetBytes(sessionId);
IntPtr sessionBuffer = Marshal.AllocHGlobal(sessionBytes.Length);
try
{
Marshal.Copy(sessionBytes, 0, sessionBuffer, sessionBytes.Length);
if (!SetTokenInformation(token, 12, sessionBuffer, sessionBytes.Length))
throw new Win32Exception();
}
finally
{
Marshal.FreeHGlobal(sessionBuffer);
}
}
'@
$currentId = [Runas.NativeMethods]::ProcessToSessionId($pid)
$procHandle = $tokenHandle = $impToken = $null
try {
$lsassId = Get-Process -Name lsass | Select-Object -ExpandProperty Id
$procHandle = [Runas.NativeMethods]::OpenProcess($lsassId, 0x0400, $false)
# First need to impersonate the SYSTEM token so we have the ability get a token with AdjustSessionId and actually
# set the session id which requires SeTcbPrivilege
$impToken = [Runas.NativeMethods]::OpenProcessToken($procHandle, 'Query, Duplicate')
[Runas.NativeMethods]::ImpersonateLoggedOnUser($impToken)
try {
$tokenHandle = [Runas.NativeMethods]::DuplicateTokenEx(
[Runas.NativeMethods]::OpenProcessToken($procHandle, 'Duplicate'),
'Query, Duplicate, AssignPrimary, AdjustSessionId, Write',
1, 0 # TokenPrimary and no impersonation level
)
[Runas.NativeMethods]::SetTokenSessionId($tokenHandle, $currentId)
}
finally {
[Runas.NativeMethods]::RevertToSelf()
}
# Requires the SeAssignPrimaryTokenPrivilege
Start-ProcessEx -FilePath powershell.exe -Token $tokenHandle
}
finally {
if ($impToken) { $impToken.Dispose() }
if ($procHandle) { $procHandle.Dispose() }
if ($tokenHandle) { $tokenHandle.Dispose() }
}
@jborean93
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment