1、使用ntrights.exe 添加SeAssignPrimaryTokenPrivilege权限
对应 “计算机配置” -> “Windows 设置” -> “安全设置” -> “本地策略” -> “用户权限分配”->”替换一个进程级令牌”
C#
public static void AddTokenPrivilege()
{
if (OperatingSystem.IsWindows())
{
WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
Execute("cmd.exe", new string[] {
$"ntrights +r SeAssignPrimaryTokenPrivilege -u {windowsIdentity.Name}"
});
}
}
public static string Execute(string fileName, string arg, string[] commands)
{
Process proc = new Process();
proc.StartInfo.WorkingDirectory = Path.GetFullPath(Path.Join("./"));
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName = fileName;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.Arguments = arg;
proc.StartInfo.Verb = "runas";
proc.Start();
if (commands.Length > 0)
{
for (int i = 0; i < commands.Length; i++)
{
proc.StandardInput.WriteLine(commands[i]);
}
}
proc.StandardInput.AutoFlush = true;
proc.StandardInput.WriteLine("exit");
proc.StandardInput.Close();
string output = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
proc.Close();
proc.Dispose();
return output;
}
2、提权定义
将程序提权到SYSTEM权限
C#
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern nint GetCommandLine();
public static string GetCommandLineStr()
{
nint commandLinePtr = GetCommandLineStr();
return Marshal.PtrToStringAuto(commandLinePtr) ?? string.Empty;
}
[DataContract]
public enum WindowsSessionType
{
Console = 1,
RDP = 2
}
public enum WTS_INFO_CLASS
{
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType,
WTSIdleTime,
WTSLogonTime,
WTSIncomingBytes,
WTSOutgoingBytes,
WTSIncomingFrames,
WTSOutgoingFrames,
WTSClientInfo,
WTSSessionInfo
}
[StructLayout(LayoutKind.Sequential)]
public struct WTS_SESSION_INFO
{
public uint SessionID;
[MarshalAs(UnmanagedType.LPStr)]
public string pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
}
public enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public nint lpReserved2;
public nint hStdInput;
public nint hStdOutput;
public nint hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public nint hProcess;
public nint hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int Length;
public nint lpSecurityDescriptor;
public bool bInheritHandle;
}
public enum SECURITY_IMPERSONATION_LEVEL : int
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
public enum TOKEN_TYPE : int
{
TokenPrimary = 1,
TokenImpersonation = 2
}
[DllImport("kernel32.dll")]
public static extern uint WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll")]
public static extern bool WTSQuerySessionInformation(nint hServer, uint sessionId, WTS_INFO_CLASS wtsInfoClass, out nint ppBuffer, out uint pBytesReturned);
[DllImport("wtsapi32.dll", ExactSpelling = true, SetLastError = false)]
public static extern void WTSFreeMemory(nint memory);
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern int WTSEnumerateSessions( nint hServer,int Reserved,int Version, ref nint ppSessionInfo, ref int pCount);
[DllImport("kernel32.dll")]
public static extern nint OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
[DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurity]
public static extern bool OpenProcessToken(nint ProcessHandle, int DesiredAccess, ref nint TokenHandle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool DuplicateTokenEx(
nint hExistingToken,
uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpTokenAttributes,
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
TOKEN_TYPE TokenType,
out nint phNewToken);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool CreateProcessAsUser(
nint hToken,
string? lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
nint lpEnvironment,
string? lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
public static string GetUsernameFromSessionId(uint sessionId)
{
string username = string.Empty;
if (WTSQuerySessionInformation(nint.Zero, sessionId,WTS_INFO_CLASS.WTSUserName, out var buffer, out var strLen) && strLen > 1)
{
username = Marshal.PtrToStringAnsi(buffer);
WTSFreeMemory(buffer);
}
return username ?? string.Empty;
}
public static List<WindowsSession> GetActiveSessions()
{
List<WindowsSession> sessions = new List<WindowsSession>();
uint consoleSessionId = WTSGetActiveConsoleSessionId();
sessions.Add(new WindowsSession()
{
Id = consoleSessionId,
Type = WindowsSessionType.Console,
Name = "Console",
Username = GetUsernameFromSessionId(consoleSessionId)
});
nint ppSessionInfo = nint.Zero;
int count = 0;
int enumSessionResult = WTSAPI32.WTSEnumerateSessions(nint.Zero, 0, 1, ref ppSessionInfo, ref count);
int dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
nint current = ppSessionInfo;
if (enumSessionResult != 0)
{
for (int i = 0; i < count; i++)
{
object wtsInfo = Marshal.PtrToStructure(current, typeof(WTS_SESSION_INFO));
if (wtsInfo is null)
{
continue;
}
WTS_SESSION_INFO sessionInfo = (WTS_SESSION_INFO)wtsInfo;
current += dataSize;
if (sessionInfo.State == WTS_CONNECTSTATE_CLASS.WTSActive && sessionInfo.SessionID != consoleSessionId)
{
sessions.Add(new WindowsSession()
{
Id = sessionInfo.SessionID,
Name = sessionInfo.pWinStationName,
Type = WindowsSessionType.RDP,
Username = GetUsernameFromSessionId(sessionInfo.SessionID)
});
}
}
}
return sessions;
}
private static uint GetWinLogonPid(uint dwSessionId)
{
uint winlogonPid = 0;
Process[] processes = Process.GetProcessesByName("winlogon");
foreach (Process p in processes)
{
if ((uint)p.SessionId == dwSessionId)
{
winlogonPid = (uint)p.Id;
}
}
return winlogonPid;
}
private static uint GetDwSessionId(int targetSessionId,bool forceConsoleSession)
{
uint dwSessionId = WTSGetActiveConsoleSessionId();
if (forceConsoleSession == false)
{
List<WindowsSession> activeSessions = GetActiveSessions();
if (activeSessions.Any(x => x.Id == targetSessionId))
{
dwSessionId = (uint)targetSessionId;
}
else
{
dwSessionId = activeSessions.Last().Id;
}
}
return dwSessionId;
}
private static STARTUPINFO GetStartUpInfo(bool hiddenWindow, string desktopName, out uint dwCreationFlags)
{
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = @"winsta0\" + desktopName;
if (hiddenWindow)
{
dwCreationFlags = 0x20| 0x00000400 | 0x08000000;
si.dwFlags = 0x00000001;
si.wShowWindow = 0;
}
else
{
dwCreationFlags = 0x20| 0x00000400 | 0x00000010;
}
return si;
}
public static bool CreateInteractiveSystemProcess(string commandLine, int targetSessionId, bool forceConsoleSession, string desktopName, bool hiddenWindow, out PROCESS_INFORMATION procInfo)
{
nint hPToken = nint.Zero;
procInfo = new PROCESS_INFORMATION();
uint dwSessionId = GetDwSessionId(targetSessionId, forceConsoleSession);
uint winlogonPid = GetWinLogonPid(dwSessionId);
nint hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
if (OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken) == false)
{
Kernel32.CloseHandle(hProcess);
return false;
}
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
if (DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, out nint hUserTokenDup) == false)
{
Kernel32.CloseHandle(hProcess);
Kernel32.CloseHandle(hPToken);
return false;
}
STARTUPINFO si = GetStartUpInfo(hiddenWindow, desktopName,out uint dwCreationFlags);
bool result = CreateProcessAsUser(hUserTokenDup, null, commandLine, ref sa, ref sa, false, dwCreationFlags, nint.Zero, null, ref si, out procInfo);
Kernel32.CloseHandle(hProcess);
Kernel32.CloseHandle(hPToken);
Kernel32.CloseHandle(hUserTokenDup);
return result;
}
3、使用提权
调用 RelaunchElevated() 将会以SYSTEM权限重启程序,并添加 –elevated 表示已提权,用以判断状态
C#
public static void RelaunchElevated()
{
if (OperatingSystem.IsWindows() == false) return;
try
{
AddTokenPrivilege();
}
catch
{
}
try
{
string commandLine = GetCommandLine();
bool result = CreateInteractiveSystemProcess($"{commandLine} --elevated", -1, false, "default", true, out PROCESS_INFORMATION procInfo);
uint code = Kernel32.GetLastError();
//提权成功则关闭本程序
if (result)
{
Environment.Exit(0);
}
}
catch
{
}
}