|
|
- using System;
- using System.Diagnostics;
- using System.IO;
- using System.Runtime.ConstrainedExecution;
- using System.Runtime.InteropServices;
- using System.Security;
- using System.Security.Principal;
- using System.Threading;
- using System.Threading.Tasks;
- using Microsoft.Win32.SafeHandles;
-
- namespace amecs
- {
- [StructLayout(LayoutKind.Sequential)]
-
- public class NSudo
- {
- private struct SECURITY_ATTRIBUTES
- {
- public int nLength;
- public unsafe byte* lpSecurityDescriptor;
- public int bInheritHandle;
- }
- private enum SECURITY_IMPERSONATION_LEVEL
- {
- SecurityAnonymous,
- SecurityIdentification,
- SecurityImpersonation,
- SecurityDelegation
- }
- private enum TOKEN_TYPE {
- TokenPrimary = 1,
- TokenImpersonation
- }
-
- [StructLayout(LayoutKind.Sequential)]
- private struct LUID {
- public uint LowPart;
- public uint HighPart;
- }
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- private struct LUID_AND_ATTRIBUTES {
- public LUID Luid;
- public UInt32 Attributes;
- }
-
- private struct TOKEN_PRIVILEGES {
- public int PrivilegeCount;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst=1)]
- public LUID_AND_ATTRIBUTES[] Privileges;
- }
-
-
- private static UInt32 MAXIMUM_ALLOWED = (UInt32)TokenAccessLevels.MaximumAllowed;
-
- [DllImport("advapi32.dll", SetLastError=true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool OpenProcessToken(IntPtr ProcessHandle,
- UInt32 DesiredAccess, out IntPtr TokenHandle);
-
- [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
- private static extern bool DuplicateTokenEx(
- IntPtr hExistingToken,
- uint dwDesiredAccess,
- IntPtr lpTokenAttributes,
- SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
- TOKEN_TYPE TokenType,
- out IntPtr phNewToken );
- [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
- private static extern bool DuplicateTokenEx(
- IntPtr hExistingToken,
- uint dwDesiredAccess,
- ref SECURITY_ATTRIBUTES lpTokenAttributes,
- SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
- TOKEN_TYPE TokenType,
- out IntPtr phNewToken );
- [DllImport("advapi32.dll")]
- static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpName,
- ref LUID lpLuid);
- internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
-
- // Use this signature if you do not want the previous state
- [DllImport("advapi32.dll", SetLastError=true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
- [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
- ref TOKEN_PRIVILEGES NewState,
- UInt32 Zero,
- IntPtr Null1,
- IntPtr Null2);
-
- [System.Runtime.InteropServices.DllImport("advapi32.dll", SetLastError = true)]
- private static extern bool SetThreadToken(IntPtr pHandle,
- IntPtr hToken);
-
-
-
-
- [DllImport("wtsapi32.dll", SetLastError=true)]
- static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
-
- [DllImport("advapi32.dll", SetLastError = true)]
- static extern Boolean SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
- ref UInt32 TokenInformation, UInt32 TokenInformationLength);
-
-
- [DllImport("userenv.dll", SetLastError=true)]
- static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit );
- public static bool GetUserPrivilege(IntPtr Token)
- {
- IntPtr NewToken;
- DuplicateTokenEx(Token, MAXIMUM_ALLOWED, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenImpersonation, out NewToken);
- SetThreadToken(IntPtr.Zero, NewToken);
- return true;
- }
-
- [DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
- static extern bool CreateProcessAsUser(
- IntPtr hToken,
- string lpApplicationName,
- string lpCommandLine,
- ref SECURITY_ATTRIBUTES lpProcessAttributes,
- ref SECURITY_ATTRIBUTES lpThreadAttributes,
- bool bInheritHandles,
- uint dwCreationFlags,
- IntPtr lpEnvironment,
- string lpCurrentDirectory,
- ref STARTUPINFO lpStartupInfo,
- out PROCESS_INFORMATION lpProcessInformation);
-
- [Flags]
- enum CreationFlags
- {
- CREATE_SUSPENDED = 0x00000004,
- CREATE_UNICODE_ENVIRONMENT = 0x00000400,
- CREATE_NO_WINDOW = 0x08000000,
- CREATE_NEW_CONSOLE = 0x00000010
- }
- [DllImport("advapi32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool LogonUser(
- [MarshalAs(UnmanagedType.LPStr)] string pszUserName,
- [MarshalAs(UnmanagedType.LPStr)] string pszDomain,
- [MarshalAs(UnmanagedType.LPStr)] string pszPassword,
- int dwLogonType,
- int dwLogonProvider,
- ref IntPtr phToken);
-
- public static int? RunProcessAsUser(IntPtr Token, string Executable, string Arguments, uint timeout = 0xFFFFFFFF)
- {
- GetAssignPrivilege();
- GetQuotaPrivilege();
-
- var startupInfo = new STARTUPINFO();
- startupInfo.cb = Marshal.SizeOf(startupInfo);
- startupInfo.dwFlags = 0x00000001;
- startupInfo.wShowWindow = 1;
-
-
- var procAttrs = new SECURITY_ATTRIBUTES();
- var threadAttrs = new SECURITY_ATTRIBUTES();
- procAttrs.nLength = Marshal.SizeOf(procAttrs);
- threadAttrs.nLength = Marshal.SizeOf(threadAttrs);
-
- // Log on user temporarily in order to start console process in its security context.
- var hUserTokenDuplicate = IntPtr.Zero;
- var pEnvironmentBlock = IntPtr.Zero;
-
- DuplicateTokenEx(Token, MAXIMUM_ALLOWED, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, out hUserTokenDuplicate);
-
- CreateEnvironmentBlock(out pEnvironmentBlock, Token, false);
-
- PROCESS_INFORMATION _processInfo;
- if (!CreateProcessAsUser(hUserTokenDuplicate, null, String.IsNullOrEmpty(Arguments) ? $"\"{Executable}\"" : $"\"{Executable}\" {Arguments}",
- ref procAttrs, ref threadAttrs, false, (uint)CreationFlags.CREATE_NO_WINDOW |
- (uint)CreationFlags.CREATE_UNICODE_ENVIRONMENT,
- pEnvironmentBlock, null, ref startupInfo, out _processInfo)) return null;
-
- uint exitCode;
- WaitForSingleObject(_processInfo.hProcess, timeout);
- GetExitCodeProcess(_processInfo.hProcess, out exitCode);
-
- return (int)exitCode;
- /*
- uint dwCreationFlags = (uint)CreationFlags.CREATE_UNICODE_ENVIRONMENT;
-
-
- startupInfo.cb = Marshal.SizeOf(startupInfo);
-
-
-
- SECURITY_ATTRIBUTES throwaway = new SECURITY_ATTRIBUTES();
- SECURITY_ATTRIBUTES throwaway2 = new SECURITY_ATTRIBUTES();
- Console.WriteLine(Marshal.GetLastWin32Error() + "-3");
-
- Console.WriteLine(CreateProcessAsUser(hUserToken, String.Empty, "\"C:\\Windows\\notepad.exe\"", ref throwaway, ref throwaway2, false, 0, IntPtr.Zero, String.Empty, ref StartupInfo, out ProcessInfo));
- Console.WriteLine(Marshal.GetLastWin32Error() + "-4");
-
- return Process.GetProcessById(ProcessInfo.dwProcessId);
- */
- }
- [DllImport("kernel32.dll", SetLastError = true)]
- [return: MarshalAs(UnmanagedType.Bool)]
- static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode);
- [DllImport("kernel32.dll", SetLastError=true)]
- static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
- struct STARTUPINFO
- {
- public Int32 cb;
- public IntPtr lpReserved;
-
- public IntPtr lpDesktop;
- public IntPtr lpTitle;
- public Int32 dwX;
- public Int32 dwY;
- public Int32 dwXSize;
- public Int32 dwYSize;
- public Int32 dwXCountChars;
- public Int32 dwYCountChars;
- public Int32 dwFillAttribute;
- public Int32 dwFlags;
- public Int16 wShowWindow;
- public Int16 cbReserved2;
- public IntPtr lpReserved2;
- public IntPtr hStdInput;
- public IntPtr hStdOutput;
- public IntPtr hStdError;
- }
- [StructLayout(LayoutKind.Sequential)]
- internal struct PROCESS_INFORMATION
- {
- public IntPtr hProcess;
- public IntPtr hThread;
- public int dwProcessId;
- public int dwThreadId;
- }
- public static IntPtr GetUserToken()
- {
- IntPtr Token;
-
- WTSQueryUserToken((uint)SessionID, out Token);
- return Token;
- }
-
- private static int SessionID = -1;
- public static bool GetSystemPrivilege()
- {
- IntPtr CurrentProcessToken;
- OpenProcessToken(Process.GetCurrentProcess().Handle, MAXIMUM_ALLOWED, out CurrentProcessToken);
- IntPtr DuplicatedCurrentProcessToken;
- DuplicateTokenEx(CurrentProcessToken, MAXIMUM_ALLOWED, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenImpersonation, out DuplicatedCurrentProcessToken);
- LUID_AND_ATTRIBUTES RawPrivilege = new LUID_AND_ATTRIBUTES();
- LookupPrivilegeValue(IntPtr.Zero, "SeDebugPrivilege", ref RawPrivilege.Luid);
- RawPrivilege.Attributes = SE_PRIVILEGE_ENABLED;
-
- TOKEN_PRIVILEGES TokenPrivilege = new TOKEN_PRIVILEGES();
- TokenPrivilege.Privileges = new LUID_AND_ATTRIBUTES[] { RawPrivilege };
- TokenPrivilege.PrivilegeCount = 1;
- AdjustTokenPrivileges(DuplicatedCurrentProcessToken, false, ref TokenPrivilege, 0, IntPtr.Zero, IntPtr.Zero);
-
- SetThreadToken(IntPtr.Zero, DuplicatedCurrentProcessToken);
-
- SessionID = GetActiveSession();
-
- IntPtr OriginalProcessToken = new IntPtr(-1);
- CreateSystemToken((int)MAXIMUM_ALLOWED, SessionID, ref OriginalProcessToken);
-
- IntPtr SystemToken;
- DuplicateTokenEx(OriginalProcessToken, MAXIMUM_ALLOWED, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenImpersonation, out SystemToken);
-
- SetThreadToken(IntPtr.Zero, SystemToken);
-
- return true;
- }
-
- [DllImport("advapi32.dll", SetLastError=true)]
- static extern bool GetTokenInformation(
- IntPtr TokenHandle,
- TOKEN_INFORMATION_CLASS TokenInformationClass,
- IntPtr TokenInformation,
- int TokenInformationLength,
- out int ReturnLength);
-
- enum TOKEN_INFORMATION_CLASS
- {
- TokenUser = 1,
- TokenGroups,
- TokenPrivileges,
- TokenOwner,
- TokenPrimaryGroup,
- TokenDefaultDacl,
- TokenSource,
- TokenType,
- TokenImpersonationLevel,
- TokenStatistics,
- TokenRestrictedSids,
- TokenSessionId,
- TokenGroupsAndPrivileges,
- TokenSessionReference,
- TokenSandBoxInert,
- TokenAuditPolicy,
- TokenOrigin
- }
-
- private static int GetActiveSession()
- {
- IntPtr pSessionInfo = IntPtr.Zero;
- Int32 Count = 0;
- var retval = WTSEnumerateSessions((IntPtr)null, 0, 1, ref pSessionInfo, ref Count);
- Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
-
- Int64 current = (Int64)pSessionInfo;
-
- int result = -1;
- if (retval != 0)
- {
- for (int i = 0; i < Count; i++)
- {
- WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO));
- current += dataSize;
-
- if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive)
- {
- result = si.SessionID;
- break;
- }
- }
- WTSFreeMemory(pSessionInfo);
- }
-
- return result;
- }
-
- private static void CreateSystemToken(int DesiredAccess, int dwSessionID, ref IntPtr TokenHandle)
- {
- int dwLsassPID = -1;
- int dwWinLogonPID = -1;
- WTS_PROCESS_INFO[] pProcesses;
- IntPtr pProcessInfo = IntPtr.Zero;
-
- int dwProcessCount = 0;
-
- if (WTSEnumerateProcesses((IntPtr)null, 0, 1, ref pProcessInfo, ref dwProcessCount))
- {
- IntPtr pMemory = pProcessInfo;
- pProcesses = new WTS_PROCESS_INFO[dwProcessCount];
-
- for (int i = 0; i < dwProcessCount; i++)
- {
- pProcesses[i] = (WTS_PROCESS_INFO)Marshal.PtrToStructure(pProcessInfo, typeof(WTS_PROCESS_INFO));
- pProcessInfo = (IntPtr)((long)pProcessInfo + Marshal.SizeOf(pProcesses[i]));
-
- var processName = Marshal.PtrToStringAnsi(pProcesses[i].ProcessName);
- ConvertSidToStringSid(pProcesses[i].UserSid, out string sid);
-
- string strSid;
-
- if (processName == null || pProcesses[i].UserSid == default || sid != "S-1-5-18")
- continue;
-
- if ((-1 == dwLsassPID) && (0 == pProcesses[i].SessionID) && (processName == "lsass.exe"))
- {
- dwLsassPID = pProcesses[i].ProcessID;
- continue;
- }
-
- if ((-1 == dwWinLogonPID) && (dwSessionID == pProcesses[i].SessionID) && (processName == "winlogon.exe"))
- {
- dwWinLogonPID = pProcesses[i].ProcessID;
- continue;
- }
- }
-
- WTSFreeMemory(pMemory);
- }
-
- bool Result = false;
-
- IntPtr SystemProcessHandle = IntPtr.Zero;
-
-
- try
- {
- SystemProcessHandle = Process.GetProcessById(dwLsassPID).Handle;
- } catch
- {
- SystemProcessHandle = Process.GetProcessById(dwWinLogonPID).Handle;
- }
- IntPtr SystemTokenHandle = IntPtr.Zero;
- if (OpenProcessToken(SystemProcessHandle, TOKEN_DUPLICATE, out SystemTokenHandle))
- {
- Result = DuplicateTokenEx(SystemTokenHandle, (uint)DesiredAccess, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, out TokenHandle);
- CloseHandle(SystemTokenHandle);
- }
-
- CloseHandle(SystemProcessHandle);
-
- // return Result;
- return;
- }
-
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern IntPtr OpenProcess(
- uint processAccess,
- bool bInheritHandle,
- uint processId
- );
- public const UInt32 TOKEN_DUPLICATE = 0x0002;
-
- [DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
- static extern bool ConvertSidToStringSid(IntPtr pSid, out string strSid);
-
-
- [DllImport("kernel32.dll", SetLastError=true)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
- [SuppressUnmanagedCodeSecurity]
- [return: MarshalAs(UnmanagedType.Bool)]
- static extern bool CloseHandle(IntPtr hObject);
-
- [DllImport("wtsapi32.dll", SetLastError=true)]
- static extern int WTSEnumerateSessions(
- System.IntPtr hServer,
- int Reserved,
- int Version,
- ref System.IntPtr ppSessionInfo,
- ref int pCount);
-
-
- [StructLayout(LayoutKind.Sequential)]
- private struct WTS_SESSION_INFO
- {
- public Int32 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
- }
- [DllImport("wtsapi32.dll")]
- static extern void WTSFreeMemory(IntPtr pMemory);
-
- [DllImport("wtsapi32.dll", SetLastError=true)]
- static extern bool WTSEnumerateProcesses(
- IntPtr serverHandle, // Handle to a terminal server.
- Int32 reserved, // must be 0
- Int32 version, // must be 1
- ref IntPtr ppProcessInfo, // pointer to array of WTS_PROCESS_INFO
- ref Int32 pCount // pointer to number of processes
- );
- struct WTS_PROCESS_INFO
- {
- public int SessionID;
- public int ProcessID;
- //This is a pointer to string...
- public IntPtr ProcessName;
- public IntPtr UserSid;
- }
-
-
-
- [DllImport("ntdll.dll", SetLastError = true)]
- static extern IntPtr RtlAdjustPrivilege(int Privilege, bool bEnablePrivilege, bool IsThreadPrivilege, out bool PreviousValue);
- [DllImport("advapi32.dll")]
- static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpName, ref UInt64 lpLuid);
- public static void GetOwnershipPrivilege()
- {
- ulong luid = 0;
- bool throwaway;
- LookupPrivilegeValue(IntPtr.Zero, "SeTakeOwnershipPrivilege", ref luid);
- RtlAdjustPrivilege((int)luid, true, true, out throwaway);
- }
- public static void GetAssignPrivilege()
- {
- ulong luid = 0;
- bool throwaway;
- LookupPrivilegeValue(IntPtr.Zero, "SeAssignPrimaryTokenPrivilege", ref luid);
- RtlAdjustPrivilege((int)luid, true, true, out throwaway);
- }
- public static void GetQuotaPrivilege()
- {
- ulong luid = 0;
- bool throwaway;
- LookupPrivilegeValue(IntPtr.Zero, "SeIncreaseQuotaPrivilege", ref luid);
- RtlAdjustPrivilege((int)luid, true, true, out throwaway);
- }
-
- public static void GetShutdownPrivilege()
- {
- ulong luid = 0;
- bool throwaway;
- LookupPrivilegeValue(IntPtr.Zero, "SeShutdownPrivilege", ref luid);
- RtlAdjustPrivilege((int)luid, true, true, out throwaway);
- }
-
- public static void RunAsUser(Action action)
- {
- var token = NSudo.GetUserToken();
- Task.Run((Action)Delegate.Combine((Action)(() => { NSudo.GetUserPrivilege(token); }),
- action)).Wait();
- Marshal.FreeHGlobal(token);
- }
-
- private static async Task RunAsUserAsync(Action action)
- {
- var token = NSudo.GetUserToken();
- await Task.Run((Action)Delegate.Combine((Action)(() => { NSudo.GetUserPrivilege(token); }),
- action));
- Marshal.FreeHGlobal(token);
- }
- }
- }
|