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.

524 lines
20 KiB

9 months ago
9 months ago
9 months ago
  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.Runtime.ConstrainedExecution;
  5. using System.Runtime.InteropServices;
  6. using System.Security;
  7. using System.Security.Principal;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using Microsoft.Win32.SafeHandles;
  11. namespace amecs
  12. {
  13. [StructLayout(LayoutKind.Sequential)]
  14. public class NSudo
  15. {
  16. private struct SECURITY_ATTRIBUTES
  17. {
  18. public int nLength;
  19. public unsafe byte* lpSecurityDescriptor;
  20. public int bInheritHandle;
  21. }
  22. private enum SECURITY_IMPERSONATION_LEVEL
  23. {
  24. SecurityAnonymous,
  25. SecurityIdentification,
  26. SecurityImpersonation,
  27. SecurityDelegation
  28. }
  29. private enum TOKEN_TYPE {
  30. TokenPrimary = 1,
  31. TokenImpersonation
  32. }
  33. [StructLayout(LayoutKind.Sequential)]
  34. private struct LUID {
  35. public uint LowPart;
  36. public uint HighPart;
  37. }
  38. [StructLayout(LayoutKind.Sequential, Pack = 4)]
  39. private struct LUID_AND_ATTRIBUTES {
  40. public LUID Luid;
  41. public UInt32 Attributes;
  42. }
  43. private struct TOKEN_PRIVILEGES {
  44. public int PrivilegeCount;
  45. [MarshalAs(UnmanagedType.ByValArray, SizeConst=1)]
  46. public LUID_AND_ATTRIBUTES[] Privileges;
  47. }
  48. private static UInt32 MAXIMUM_ALLOWED = (UInt32)TokenAccessLevels.MaximumAllowed;
  49. [DllImport("advapi32.dll", SetLastError=true)]
  50. [return: MarshalAs(UnmanagedType.Bool)]
  51. private static extern bool OpenProcessToken(IntPtr ProcessHandle,
  52. UInt32 DesiredAccess, out IntPtr TokenHandle);
  53. [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
  54. private static extern bool DuplicateTokenEx(
  55. IntPtr hExistingToken,
  56. uint dwDesiredAccess,
  57. IntPtr lpTokenAttributes,
  58. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
  59. TOKEN_TYPE TokenType,
  60. out IntPtr phNewToken );
  61. [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
  62. private static extern bool DuplicateTokenEx(
  63. IntPtr hExistingToken,
  64. uint dwDesiredAccess,
  65. ref SECURITY_ATTRIBUTES lpTokenAttributes,
  66. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
  67. TOKEN_TYPE TokenType,
  68. out IntPtr phNewToken );
  69. [DllImport("advapi32.dll")]
  70. static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpName,
  71. ref LUID lpLuid);
  72. internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
  73. // Use this signature if you do not want the previous state
  74. [DllImport("advapi32.dll", SetLastError=true)]
  75. [return: MarshalAs(UnmanagedType.Bool)]
  76. static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
  77. [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
  78. ref TOKEN_PRIVILEGES NewState,
  79. UInt32 Zero,
  80. IntPtr Null1,
  81. IntPtr Null2);
  82. [System.Runtime.InteropServices.DllImport("advapi32.dll", SetLastError = true)]
  83. private static extern bool SetThreadToken(IntPtr pHandle,
  84. IntPtr hToken);
  85. [DllImport("wtsapi32.dll", SetLastError=true)]
  86. static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
  87. [DllImport("advapi32.dll", SetLastError = true)]
  88. static extern Boolean SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
  89. ref UInt32 TokenInformation, UInt32 TokenInformationLength);
  90. [DllImport("userenv.dll", SetLastError=true)]
  91. static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit );
  92. public static bool GetUserPrivilege(IntPtr Token)
  93. {
  94. IntPtr NewToken;
  95. DuplicateTokenEx(Token, MAXIMUM_ALLOWED, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenImpersonation, out NewToken);
  96. SetThreadToken(IntPtr.Zero, NewToken);
  97. return true;
  98. }
  99. [DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
  100. static extern bool CreateProcessAsUser(
  101. IntPtr hToken,
  102. string lpApplicationName,
  103. string lpCommandLine,
  104. ref SECURITY_ATTRIBUTES lpProcessAttributes,
  105. ref SECURITY_ATTRIBUTES lpThreadAttributes,
  106. bool bInheritHandles,
  107. uint dwCreationFlags,
  108. IntPtr lpEnvironment,
  109. string lpCurrentDirectory,
  110. ref STARTUPINFO lpStartupInfo,
  111. out PROCESS_INFORMATION lpProcessInformation);
  112. [Flags]
  113. enum CreationFlags
  114. {
  115. CREATE_SUSPENDED = 0x00000004,
  116. CREATE_UNICODE_ENVIRONMENT = 0x00000400,
  117. CREATE_NO_WINDOW = 0x08000000,
  118. CREATE_NEW_CONSOLE = 0x00000010
  119. }
  120. [DllImport("advapi32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
  121. [return: MarshalAs(UnmanagedType.Bool)]
  122. internal static extern bool LogonUser(
  123. [MarshalAs(UnmanagedType.LPStr)] string pszUserName,
  124. [MarshalAs(UnmanagedType.LPStr)] string pszDomain,
  125. [MarshalAs(UnmanagedType.LPStr)] string pszPassword,
  126. int dwLogonType,
  127. int dwLogonProvider,
  128. ref IntPtr phToken);
  129. public static int? RunProcessAsUser(IntPtr Token, string Executable, string Arguments, uint timeout = 0xFFFFFFFF)
  130. {
  131. GetAssignPrivilege();
  132. GetQuotaPrivilege();
  133. var startupInfo = new STARTUPINFO();
  134. startupInfo.cb = Marshal.SizeOf(startupInfo);
  135. startupInfo.dwFlags = 0x00000001;
  136. startupInfo.wShowWindow = 1;
  137. var procAttrs = new SECURITY_ATTRIBUTES();
  138. var threadAttrs = new SECURITY_ATTRIBUTES();
  139. procAttrs.nLength = Marshal.SizeOf(procAttrs);
  140. threadAttrs.nLength = Marshal.SizeOf(threadAttrs);
  141. // Log on user temporarily in order to start console process in its security context.
  142. var hUserTokenDuplicate = IntPtr.Zero;
  143. var pEnvironmentBlock = IntPtr.Zero;
  144. DuplicateTokenEx(Token, MAXIMUM_ALLOWED, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, out hUserTokenDuplicate);
  145. CreateEnvironmentBlock(out pEnvironmentBlock, Token, false);
  146. PROCESS_INFORMATION _processInfo;
  147. if (!CreateProcessAsUser(hUserTokenDuplicate, null, String.IsNullOrEmpty(Arguments) ? $"\"{Executable}\"" : $"\"{Executable}\" {Arguments}",
  148. ref procAttrs, ref threadAttrs, false, (uint)CreationFlags.CREATE_NO_WINDOW |
  149. (uint)CreationFlags.CREATE_UNICODE_ENVIRONMENT,
  150. pEnvironmentBlock, null, ref startupInfo, out _processInfo)) return null;
  151. uint exitCode;
  152. WaitForSingleObject(_processInfo.hProcess, timeout);
  153. GetExitCodeProcess(_processInfo.hProcess, out exitCode);
  154. return (int)exitCode;
  155. /*
  156. uint dwCreationFlags = (uint)CreationFlags.CREATE_UNICODE_ENVIRONMENT;
  157. startupInfo.cb = Marshal.SizeOf(startupInfo);
  158. SECURITY_ATTRIBUTES throwaway = new SECURITY_ATTRIBUTES();
  159. SECURITY_ATTRIBUTES throwaway2 = new SECURITY_ATTRIBUTES();
  160. Console.WriteLine(Marshal.GetLastWin32Error() + "-3");
  161. Console.WriteLine(CreateProcessAsUser(hUserToken, String.Empty, "\"C:\\Windows\\notepad.exe\"", ref throwaway, ref throwaway2, false, 0, IntPtr.Zero, String.Empty, ref StartupInfo, out ProcessInfo));
  162. Console.WriteLine(Marshal.GetLastWin32Error() + "-4");
  163. return Process.GetProcessById(ProcessInfo.dwProcessId);
  164. */
  165. }
  166. [DllImport("kernel32.dll", SetLastError = true)]
  167. [return: MarshalAs(UnmanagedType.Bool)]
  168. static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode);
  169. [DllImport("kernel32.dll", SetLastError=true)]
  170. static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);
  171. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  172. struct STARTUPINFO
  173. {
  174. public Int32 cb;
  175. public IntPtr lpReserved;
  176. public IntPtr lpDesktop;
  177. public IntPtr lpTitle;
  178. public Int32 dwX;
  179. public Int32 dwY;
  180. public Int32 dwXSize;
  181. public Int32 dwYSize;
  182. public Int32 dwXCountChars;
  183. public Int32 dwYCountChars;
  184. public Int32 dwFillAttribute;
  185. public Int32 dwFlags;
  186. public Int16 wShowWindow;
  187. public Int16 cbReserved2;
  188. public IntPtr lpReserved2;
  189. public IntPtr hStdInput;
  190. public IntPtr hStdOutput;
  191. public IntPtr hStdError;
  192. }
  193. [StructLayout(LayoutKind.Sequential)]
  194. internal struct PROCESS_INFORMATION
  195. {
  196. public IntPtr hProcess;
  197. public IntPtr hThread;
  198. public int dwProcessId;
  199. public int dwThreadId;
  200. }
  201. public static IntPtr GetUserToken()
  202. {
  203. IntPtr Token;
  204. WTSQueryUserToken((uint)SessionID, out Token);
  205. return Token;
  206. }
  207. private static int SessionID = -1;
  208. public static bool GetSystemPrivilege()
  209. {
  210. IntPtr CurrentProcessToken;
  211. OpenProcessToken(Process.GetCurrentProcess().Handle, MAXIMUM_ALLOWED, out CurrentProcessToken);
  212. IntPtr DuplicatedCurrentProcessToken;
  213. DuplicateTokenEx(CurrentProcessToken, MAXIMUM_ALLOWED, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenImpersonation, out DuplicatedCurrentProcessToken);
  214. LUID_AND_ATTRIBUTES RawPrivilege = new LUID_AND_ATTRIBUTES();
  215. LookupPrivilegeValue(IntPtr.Zero, "SeDebugPrivilege", ref RawPrivilege.Luid);
  216. RawPrivilege.Attributes = SE_PRIVILEGE_ENABLED;
  217. TOKEN_PRIVILEGES TokenPrivilege = new TOKEN_PRIVILEGES();
  218. TokenPrivilege.Privileges = new LUID_AND_ATTRIBUTES[] { RawPrivilege };
  219. TokenPrivilege.PrivilegeCount = 1;
  220. AdjustTokenPrivileges(DuplicatedCurrentProcessToken, false, ref TokenPrivilege, 0, IntPtr.Zero, IntPtr.Zero);
  221. SetThreadToken(IntPtr.Zero, DuplicatedCurrentProcessToken);
  222. SessionID = GetActiveSession();
  223. IntPtr OriginalProcessToken = new IntPtr(-1);
  224. CreateSystemToken((int)MAXIMUM_ALLOWED, SessionID, ref OriginalProcessToken);
  225. IntPtr SystemToken;
  226. DuplicateTokenEx(OriginalProcessToken, MAXIMUM_ALLOWED, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenImpersonation, out SystemToken);
  227. SetThreadToken(IntPtr.Zero, SystemToken);
  228. return true;
  229. }
  230. [DllImport("advapi32.dll", SetLastError=true)]
  231. static extern bool GetTokenInformation(
  232. IntPtr TokenHandle,
  233. TOKEN_INFORMATION_CLASS TokenInformationClass,
  234. IntPtr TokenInformation,
  235. int TokenInformationLength,
  236. out int ReturnLength);
  237. enum TOKEN_INFORMATION_CLASS
  238. {
  239. TokenUser = 1,
  240. TokenGroups,
  241. TokenPrivileges,
  242. TokenOwner,
  243. TokenPrimaryGroup,
  244. TokenDefaultDacl,
  245. TokenSource,
  246. TokenType,
  247. TokenImpersonationLevel,
  248. TokenStatistics,
  249. TokenRestrictedSids,
  250. TokenSessionId,
  251. TokenGroupsAndPrivileges,
  252. TokenSessionReference,
  253. TokenSandBoxInert,
  254. TokenAuditPolicy,
  255. TokenOrigin
  256. }
  257. private static int GetActiveSession()
  258. {
  259. IntPtr pSessionInfo = IntPtr.Zero;
  260. Int32 Count = 0;
  261. var retval = WTSEnumerateSessions((IntPtr)null, 0, 1, ref pSessionInfo, ref Count);
  262. Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
  263. Int64 current = (Int64)pSessionInfo;
  264. int result = -1;
  265. if (retval != 0)
  266. {
  267. for (int i = 0; i < Count; i++)
  268. {
  269. WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO));
  270. current += dataSize;
  271. if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive)
  272. {
  273. result = si.SessionID;
  274. break;
  275. }
  276. }
  277. WTSFreeMemory(pSessionInfo);
  278. }
  279. return result;
  280. }
  281. private static void CreateSystemToken(int DesiredAccess, int dwSessionID, ref IntPtr TokenHandle)
  282. {
  283. int dwLsassPID = -1;
  284. int dwWinLogonPID = -1;
  285. WTS_PROCESS_INFO[] pProcesses;
  286. IntPtr pProcessInfo = IntPtr.Zero;
  287. int dwProcessCount = 0;
  288. if (WTSEnumerateProcesses((IntPtr)null, 0, 1, ref pProcessInfo, ref dwProcessCount))
  289. {
  290. IntPtr pMemory = pProcessInfo;
  291. pProcesses = new WTS_PROCESS_INFO[dwProcessCount];
  292. for (int i = 0; i < dwProcessCount; i++)
  293. {
  294. pProcesses[i] = (WTS_PROCESS_INFO)Marshal.PtrToStructure(pProcessInfo, typeof(WTS_PROCESS_INFO));
  295. pProcessInfo = (IntPtr)((long)pProcessInfo + Marshal.SizeOf(pProcesses[i]));
  296. var processName = Marshal.PtrToStringAnsi(pProcesses[i].ProcessName);
  297. ConvertSidToStringSid(pProcesses[i].UserSid, out string sid);
  298. string strSid;
  299. if (processName == null || pProcesses[i].UserSid == default || sid != "S-1-5-18")
  300. continue;
  301. if ((-1 == dwLsassPID) && (0 == pProcesses[i].SessionID) && (processName == "lsass.exe"))
  302. {
  303. dwLsassPID = pProcesses[i].ProcessID;
  304. continue;
  305. }
  306. if ((-1 == dwWinLogonPID) && (dwSessionID == pProcesses[i].SessionID) && (processName == "winlogon.exe"))
  307. {
  308. dwWinLogonPID = pProcesses[i].ProcessID;
  309. continue;
  310. }
  311. }
  312. WTSFreeMemory(pMemory);
  313. }
  314. bool Result = false;
  315. IntPtr SystemProcessHandle = IntPtr.Zero;
  316. try
  317. {
  318. SystemProcessHandle = Process.GetProcessById(dwLsassPID).Handle;
  319. } catch
  320. {
  321. SystemProcessHandle = Process.GetProcessById(dwWinLogonPID).Handle;
  322. }
  323. IntPtr SystemTokenHandle = IntPtr.Zero;
  324. if (OpenProcessToken(SystemProcessHandle, TOKEN_DUPLICATE, out SystemTokenHandle))
  325. {
  326. Result = DuplicateTokenEx(SystemTokenHandle, (uint)DesiredAccess, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, out TokenHandle);
  327. CloseHandle(SystemTokenHandle);
  328. }
  329. CloseHandle(SystemProcessHandle);
  330. // return Result;
  331. return;
  332. }
  333. [DllImport("kernel32.dll", SetLastError = true)]
  334. public static extern IntPtr OpenProcess(
  335. uint processAccess,
  336. bool bInheritHandle,
  337. uint processId
  338. );
  339. public const UInt32 TOKEN_DUPLICATE = 0x0002;
  340. [DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
  341. static extern bool ConvertSidToStringSid(IntPtr pSid, out string strSid);
  342. [DllImport("kernel32.dll", SetLastError=true)]
  343. [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  344. [SuppressUnmanagedCodeSecurity]
  345. [return: MarshalAs(UnmanagedType.Bool)]
  346. static extern bool CloseHandle(IntPtr hObject);
  347. [DllImport("wtsapi32.dll", SetLastError=true)]
  348. static extern int WTSEnumerateSessions(
  349. System.IntPtr hServer,
  350. int Reserved,
  351. int Version,
  352. ref System.IntPtr ppSessionInfo,
  353. ref int pCount);
  354. [StructLayout(LayoutKind.Sequential)]
  355. private struct WTS_SESSION_INFO
  356. {
  357. public Int32 SessionID;
  358. [MarshalAs(UnmanagedType.LPStr)]
  359. public String pWinStationName;
  360. public WTS_CONNECTSTATE_CLASS State;
  361. }
  362. public enum WTS_CONNECTSTATE_CLASS
  363. {
  364. WTSActive,
  365. WTSConnected,
  366. WTSConnectQuery,
  367. WTSShadow,
  368. WTSDisconnected,
  369. WTSIdle,
  370. WTSListen,
  371. WTSReset,
  372. WTSDown,
  373. WTSInit
  374. }
  375. [DllImport("wtsapi32.dll")]
  376. static extern void WTSFreeMemory(IntPtr pMemory);
  377. [DllImport("wtsapi32.dll", SetLastError=true)]
  378. static extern bool WTSEnumerateProcesses(
  379. IntPtr serverHandle, // Handle to a terminal server.
  380. Int32 reserved, // must be 0
  381. Int32 version, // must be 1
  382. ref IntPtr ppProcessInfo, // pointer to array of WTS_PROCESS_INFO
  383. ref Int32 pCount // pointer to number of processes
  384. );
  385. struct WTS_PROCESS_INFO
  386. {
  387. public int SessionID;
  388. public int ProcessID;
  389. //This is a pointer to string...
  390. public IntPtr ProcessName;
  391. public IntPtr UserSid;
  392. }
  393. [DllImport("ntdll.dll", SetLastError = true)]
  394. static extern IntPtr RtlAdjustPrivilege(int Privilege, bool bEnablePrivilege, bool IsThreadPrivilege, out bool PreviousValue);
  395. [DllImport("advapi32.dll")]
  396. static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpName, ref UInt64 lpLuid);
  397. public static void GetOwnershipPrivilege()
  398. {
  399. ulong luid = 0;
  400. bool throwaway;
  401. LookupPrivilegeValue(IntPtr.Zero, "SeTakeOwnershipPrivilege", ref luid);
  402. RtlAdjustPrivilege((int)luid, true, true, out throwaway);
  403. }
  404. public static void GetAssignPrivilege()
  405. {
  406. ulong luid = 0;
  407. bool throwaway;
  408. LookupPrivilegeValue(IntPtr.Zero, "SeAssignPrimaryTokenPrivilege", ref luid);
  409. RtlAdjustPrivilege((int)luid, true, true, out throwaway);
  410. }
  411. public static void GetQuotaPrivilege()
  412. {
  413. ulong luid = 0;
  414. bool throwaway;
  415. LookupPrivilegeValue(IntPtr.Zero, "SeIncreaseQuotaPrivilege", ref luid);
  416. RtlAdjustPrivilege((int)luid, true, true, out throwaway);
  417. }
  418. public static void GetShutdownPrivilege()
  419. {
  420. ulong luid = 0;
  421. bool throwaway;
  422. LookupPrivilegeValue(IntPtr.Zero, "SeShutdownPrivilege", ref luid);
  423. RtlAdjustPrivilege((int)luid, true, true, out throwaway);
  424. }
  425. public static void RunAsUser(Action action)
  426. {
  427. var token = NSudo.GetUserToken();
  428. Task.Run((Action)Delegate.Combine((Action)(() => { NSudo.GetUserPrivilege(token); }),
  429. action)).Wait();
  430. Marshal.FreeHGlobal(token);
  431. }
  432. private static async Task RunAsUserAsync(Action action)
  433. {
  434. var token = NSudo.GetUserToken();
  435. await Task.Run((Action)Delegate.Combine((Action)(() => { NSudo.GetUserPrivilege(token); }),
  436. action));
  437. Marshal.FreeHGlobal(token);
  438. }
  439. }
  440. }