Script for automating a large assortment of AME related actions
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

525 lines
20 KiB

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);
}
}
}