You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
253 lines
7.9 KiB
PowerShell
253 lines
7.9 KiB
PowerShell
param (
|
|
[Parameter(Mandatory=$true)][string]$Runner = $(
|
|
Read-Host "Runner name (e.g. pEpSecRunner)" )
|
|
)
|
|
|
|
if ( -not $Runner.endswith("Runner") ) { $Runner = $Runner + "Runner" }
|
|
|
|
Add-Type @'
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace MyLsaWrapper
|
|
{
|
|
using System.Runtime.InteropServices;
|
|
using System.Security;
|
|
using System.Management;
|
|
using System.Runtime.CompilerServices;
|
|
using System.ComponentModel;
|
|
|
|
using LSA_HANDLE = IntPtr;
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
struct LSA_OBJECT_ATTRIBUTES
|
|
{
|
|
internal int Length;
|
|
internal IntPtr RootDirectory;
|
|
internal IntPtr ObjectName;
|
|
internal int Attributes;
|
|
internal IntPtr SecurityDescriptor;
|
|
internal IntPtr SecurityQualityOfService;
|
|
}
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
struct LSA_UNICODE_STRING
|
|
{
|
|
internal ushort Length;
|
|
internal ushort MaximumLength;
|
|
[MarshalAs(UnmanagedType.LPWStr)]
|
|
internal string Buffer;
|
|
}
|
|
sealed class Win32Sec
|
|
{
|
|
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
|
|
SuppressUnmanagedCodeSecurityAttribute]
|
|
internal static extern uint LsaOpenPolicy(
|
|
LSA_UNICODE_STRING[] SystemName,
|
|
ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
|
|
int AccessMask,
|
|
out IntPtr PolicyHandle
|
|
);
|
|
|
|
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
|
|
SuppressUnmanagedCodeSecurityAttribute]
|
|
internal static extern uint LsaAddAccountRights(
|
|
LSA_HANDLE PolicyHandle,
|
|
IntPtr pSID,
|
|
LSA_UNICODE_STRING[] UserRights,
|
|
int CountOfRights
|
|
);
|
|
|
|
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
|
|
SuppressUnmanagedCodeSecurityAttribute]
|
|
internal static extern int LsaLookupNames2(
|
|
LSA_HANDLE PolicyHandle,
|
|
uint Flags,
|
|
uint Count,
|
|
LSA_UNICODE_STRING[] Names,
|
|
ref IntPtr ReferencedDomains,
|
|
ref IntPtr Sids
|
|
);
|
|
|
|
[DllImport("advapi32")]
|
|
internal static extern int LsaNtStatusToWinError(int NTSTATUS);
|
|
|
|
[DllImport("advapi32")]
|
|
internal static extern int LsaClose(IntPtr PolicyHandle);
|
|
|
|
[DllImport("advapi32")]
|
|
internal static extern int LsaFreeMemory(IntPtr Buffer);
|
|
|
|
}
|
|
/// <summary>
|
|
/// This class is used to grant "Log on as a service", "Log on as a batchjob", "Log on localy" etc.
|
|
/// to a user.
|
|
/// </summary>
|
|
public sealed class LsaWrapper : IDisposable
|
|
{
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
struct LSA_TRUST_INFORMATION
|
|
{
|
|
internal LSA_UNICODE_STRING Name;
|
|
internal IntPtr Sid;
|
|
}
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
struct LSA_TRANSLATED_SID2
|
|
{
|
|
internal SidNameUse Use;
|
|
internal IntPtr Sid;
|
|
internal int DomainIndex;
|
|
uint Flags;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
struct LSA_REFERENCED_DOMAIN_LIST
|
|
{
|
|
internal uint Entries;
|
|
internal LSA_TRUST_INFORMATION Domains;
|
|
}
|
|
|
|
enum SidNameUse : int
|
|
{
|
|
User = 1,
|
|
Group = 2,
|
|
Domain = 3,
|
|
Alias = 4,
|
|
KnownGroup = 5,
|
|
DeletedAccount = 6,
|
|
Invalid = 7,
|
|
Unknown = 8,
|
|
Computer = 9
|
|
}
|
|
|
|
enum Access : int
|
|
{
|
|
POLICY_READ = 0x20006,
|
|
POLICY_ALL_ACCESS = 0x00F0FFF,
|
|
POLICY_EXECUTE = 0X20801,
|
|
POLICY_WRITE = 0X207F8
|
|
}
|
|
const uint STATUS_ACCESS_DENIED = 0xc0000022;
|
|
const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a;
|
|
const uint STATUS_NO_MEMORY = 0xc0000017;
|
|
|
|
IntPtr lsaHandle;
|
|
|
|
public LsaWrapper()
|
|
: this(null)
|
|
{ }
|
|
// // local system if systemName is null
|
|
public LsaWrapper(string systemName)
|
|
{
|
|
LSA_OBJECT_ATTRIBUTES lsaAttr;
|
|
lsaAttr.RootDirectory = IntPtr.Zero;
|
|
lsaAttr.ObjectName = IntPtr.Zero;
|
|
lsaAttr.Attributes = 0;
|
|
lsaAttr.SecurityDescriptor = IntPtr.Zero;
|
|
lsaAttr.SecurityQualityOfService = IntPtr.Zero;
|
|
lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES));
|
|
lsaHandle = IntPtr.Zero;
|
|
LSA_UNICODE_STRING[] system = null;
|
|
if (systemName != null)
|
|
{
|
|
system = new LSA_UNICODE_STRING[1];
|
|
system[0] = InitLsaString(systemName);
|
|
}
|
|
|
|
uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr,
|
|
(int)Access.POLICY_ALL_ACCESS, out lsaHandle);
|
|
if (ret == 0)
|
|
return;
|
|
if (ret == STATUS_ACCESS_DENIED)
|
|
{
|
|
throw new UnauthorizedAccessException();
|
|
}
|
|
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
|
|
{
|
|
throw new OutOfMemoryException();
|
|
}
|
|
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
|
|
}
|
|
|
|
public void AddPrivileges(string account, string privilege)
|
|
{
|
|
IntPtr pSid = GetSIDInformation(account);
|
|
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
|
|
privileges[0] = InitLsaString(privilege);
|
|
uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1);
|
|
if (ret == 0)
|
|
return;
|
|
if (ret == STATUS_ACCESS_DENIED)
|
|
{
|
|
throw new UnauthorizedAccessException();
|
|
}
|
|
if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY))
|
|
{
|
|
throw new OutOfMemoryException();
|
|
}
|
|
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret));
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (lsaHandle != IntPtr.Zero)
|
|
{
|
|
Win32Sec.LsaClose(lsaHandle);
|
|
lsaHandle = IntPtr.Zero;
|
|
}
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
~LsaWrapper()
|
|
{
|
|
Dispose();
|
|
}
|
|
// helper functions
|
|
|
|
IntPtr GetSIDInformation(string account)
|
|
{
|
|
LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1];
|
|
LSA_TRANSLATED_SID2 lts;
|
|
IntPtr tsids = IntPtr.Zero;
|
|
IntPtr tdom = IntPtr.Zero;
|
|
names[0] = InitLsaString(account);
|
|
lts.Sid = IntPtr.Zero;
|
|
Console.WriteLine("String account: {0}", names[0].Length);
|
|
int ret = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids);
|
|
if (ret != 0)
|
|
throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret));
|
|
lts = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(tsids,
|
|
typeof(LSA_TRANSLATED_SID2));
|
|
Win32Sec.LsaFreeMemory(tsids);
|
|
Win32Sec.LsaFreeMemory(tdom);
|
|
return lts.Sid;
|
|
}
|
|
|
|
static LSA_UNICODE_STRING InitLsaString(string s)
|
|
{
|
|
// Unicode strings max. 32KB
|
|
if (s.Length > 0x7ffe)
|
|
throw new ArgumentException("String too long");
|
|
LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING();
|
|
lus.Buffer = s;
|
|
lus.Length = (ushort)(s.Length * sizeof(char));
|
|
lus.MaximumLength = (ushort)(lus.Length + sizeof(char));
|
|
return lus;
|
|
}
|
|
}
|
|
public class LsaWrapperCaller
|
|
{
|
|
public static void AddPrivileges(string account, string privilege)
|
|
{
|
|
using (LsaWrapper lsaWrapper = new LsaWrapper())
|
|
{
|
|
lsaWrapper.AddPrivileges(account, privilege);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'@
|
|
|
|
[MyLsaWrapper.LsaWrapperCaller]::AddPrivileges("GitLab$Runner", "SeServiceLogonRight")
|
|
|
|
|