Created
June 2, 2021 20:27
-
-
Save jborean93/33c55bdd47541866dfaea43ab38d2c79 to your computer and use it in GitHub Desktop.
Creates a process running as SYSTEM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
. $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() } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This uses Start-ProcessEx, it requires these 2 lines to be commented out though https://gist.github.com/jborean93/a7c181b1ea0a4c0c8b815af9a8cbe508#file-start-processex-ps1-L919-L920.