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.

252 lines
7.9 KiB

  1. param (
  2. [Parameter(Mandatory=$true)][string]$Runner = $(
  3. Read-Host "Runner name (e.g. pEpSecRunner)" )
  4. )
  5. if ( -not $Runner.endswith("Runner") ) { $Runner = $Runner + "Runner" }
  6. Add-Type @'
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Text;
  10. namespace MyLsaWrapper
  11. {
  12. using System.Runtime.InteropServices;
  13. using System.Security;
  14. using System.Management;
  15. using System.Runtime.CompilerServices;
  16. using System.ComponentModel;
  17. using LSA_HANDLE = IntPtr;
  18. [StructLayout(LayoutKind.Sequential)]
  19. struct LSA_OBJECT_ATTRIBUTES
  20. {
  21. internal int Length;
  22. internal IntPtr RootDirectory;
  23. internal IntPtr ObjectName;
  24. internal int Attributes;
  25. internal IntPtr SecurityDescriptor;
  26. internal IntPtr SecurityQualityOfService;
  27. }
  28. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  29. struct LSA_UNICODE_STRING
  30. {
  31. internal ushort Length;
  32. internal ushort MaximumLength;
  33. [MarshalAs(UnmanagedType.LPWStr)]
  34. internal string Buffer;
  35. }
  36. sealed class Win32Sec
  37. {
  38. [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
  39. SuppressUnmanagedCodeSecurityAttribute]
  40. internal static extern uint LsaOpenPolicy(
  41. LSA_UNICODE_STRING[] SystemName,
  42. ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
  43. int AccessMask,
  44. out IntPtr PolicyHandle
  45. );
  46. [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
  47. SuppressUnmanagedCodeSecurityAttribute]
  48. internal static extern uint LsaAddAccountRights(
  49. LSA_HANDLE PolicyHandle,
  50. IntPtr pSID,
  51. LSA_UNICODE_STRING[] UserRights,
  52. int CountOfRights
  53. );
  54. [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
  55. SuppressUnmanagedCodeSecurityAttribute]
  56. internal static extern int LsaLookupNames2(
  57. LSA_HANDLE PolicyHandle,
  58. uint Flags,
  59. uint Count,
  60. LSA_UNICODE_STRING[] Names,
  61. ref IntPtr ReferencedDomains,
  62. ref IntPtr Sids
  63. );
  64. [DllImport("advapi32")]
  65. internal static extern int LsaNtStatusToWinError(int NTSTATUS);
  66. [DllImport("advapi32")]
  67. internal static extern int LsaClose(IntPtr PolicyHandle);
  68. [DllImport("advapi32")]
  69. internal static extern int LsaFreeMemory(IntPtr Buffer);
  70. }
  71. /// <summary>
  72. /// This class is used to grant "Log on as a service", "Log on as a batchjob", "Log on localy" etc.
  73. /// to a user.
  74. /// </summary>
  75. public sealed class LsaWrapper : IDisposable
  76. {
  77. [StructLayout(LayoutKind.Sequential)]
  78. struct LSA_TRUST_INFORMATION
  79. {
  80. internal LSA_UNICODE_STRING Name;
  81. internal IntPtr Sid;
  82. }
  83. [StructLayout(LayoutKind.Sequential)]
  84. struct LSA_TRANSLATED_SID2
  85. {
  86. internal SidNameUse Use;
  87. internal IntPtr Sid;
  88. internal int DomainIndex;
  89. uint Flags;
  90. }
  91. [StructLayout(LayoutKind.Sequential)]
  92. struct LSA_REFERENCED_DOMAIN_LIST
  93. {
  94. internal uint Entries;
  95. internal LSA_TRUST_INFORMATION Domains;
  96. }
  97. enum SidNameUse : int
  98. {
  99. User = 1,
  100. Group = 2,
  101. Domain = 3,
  102. Alias = 4,
  103. KnownGroup = 5,
  104. DeletedAccount = 6,
  105. Invalid = 7,
  106. Unknown = 8,
  107. Computer = 9
  108. }
  109. enum Access : int
  110. {
  111. POLICY_READ = 0x20006,
  112. POLICY_ALL_ACCESS = 0x00F0FFF,
  113. POLICY_EXECUTE = 0X20801,
  114. POLICY_WRITE = 0X207F8
  115. }
  116. const uint STATUS_ACCESS_DENIED = 0xc0000022;
  117. const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a;
  118. const uint STATUS_NO_MEMORY = 0xc0000017;
  119. IntPtr lsaHandle;
  120. public LsaWrapper()
  121. : this(null)
  122. { }
  123. // // local system if systemName is null
  124. public LsaWrapper(string systemName)
  125. {
  126. LSA_OBJECT_ATTRIBUTES lsaAttr;
  127. lsaAttr.RootDirectory = IntPtr.Zero;
  128. lsaAttr.ObjectName = IntPtr.Zero;
  129. lsaAttr.Attributes = 0;
  130. lsaAttr.SecurityDescriptor = IntPtr.Zero;
  131. lsaAttr.SecurityQualityOfService = IntPtr.Zero;
  132. lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
  133. lsaHandle = IntPtr.Zero;
  134. LSA_UNICODE_STRING[] system = null;
  135. if (systemName != null)
  136. {
  137. system = new LSA_UNICODE_STRING[1];
  138. system[0] = InitLsaString(systemName);
  139. }
  140. uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr,
  141. (int)Access.POLICY_ALL_ACCESS, out lsaHandle);
  142. if (ret == 0)
  143. return;
  144. if (ret == STATUS_ACCESS_DENIED)
  145. {
  146. throw new UnauthorizedAccessException();
  147. }
  148. if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
  149. {
  150. throw new OutOfMemoryException();
  151. }
  152. throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
  153. }
  154. public void AddPrivileges(string account, string privilege)
  155. {
  156. IntPtr pSid = GetSIDInformation(account);
  157. LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
  158. privileges[0] = InitLsaString(privilege);
  159. uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1);
  160. if (ret == 0)
  161. return;
  162. if (ret == STATUS_ACCESS_DENIED)
  163. {
  164. throw new UnauthorizedAccessException();
  165. }
  166. if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
  167. {
  168. throw new OutOfMemoryException();
  169. }
  170. throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
  171. }
  172. public void Dispose()
  173. {
  174. if (lsaHandle != IntPtr.Zero)
  175. {
  176. Win32Sec.LsaClose(lsaHandle);
  177. lsaHandle = IntPtr.Zero;
  178. }
  179. GC.SuppressFinalize(this);
  180. }
  181. ~LsaWrapper()
  182. {
  183. Dispose();
  184. }
  185. // helper functions
  186. IntPtr GetSIDInformation(string account)
  187. {
  188. LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
  189. LSA_TRANSLATED_SID2 lts;
  190. IntPtr tsids = IntPtr.Zero;
  191. IntPtr tdom = IntPtr.Zero;
  192. names[0] = InitLsaString(account);
  193. lts.Sid = IntPtr.Zero;
  194. Console.WriteLine("String account: {0}", names[0].Length);
  195. int ret = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids);
  196. if (ret != 0)
  197. throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret));
  198. lts = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(tsids,
  199. typeof(LSA_TRANSLATED_SID2));
  200. Win32Sec.LsaFreeMemory(tsids);
  201. Win32Sec.LsaFreeMemory(tdom);
  202. return lts.Sid;
  203. }
  204. static LSA_UNICODE_STRING InitLsaString(string s)
  205. {
  206. // Unicode strings max. 32KB
  207. if (s.Length > 0x7ffe)
  208. throw new ArgumentException("String too long");
  209. LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
  210. lus.Buffer = s;
  211. lus.Length = (ushort)(s.Length * sizeof(char));
  212. lus.MaximumLength = (ushort)(lus.Length + sizeof(char));
  213. return lus;
  214. }
  215. }
  216. public class LsaWrapperCaller
  217. {
  218. public static void AddPrivileges(string account, string privilege)
  219. {
  220. using (LsaWrapper lsaWrapper = new LsaWrapper())
  221. {
  222. lsaWrapper.AddPrivileges(account, privilege);
  223. }
  224. }
  225. }
  226. }
  227. '@
  228. [MyLsaWrapper.LsaWrapperCaller]::AddPrivileges("GitLab$Runner", "SeServiceLogonRight")