Query Local Computer Policy

  • Thread starter Thread starter wilshire059
  • Start date Start date
W

wilshire059

Guest
Hi all, this is actually piggybacking off of a post in the scripting guy's forum from a few years ago. The script below seems to solve the problem, but someone replied that they needed to replace the 'elemOffs' variable with 'buffer' to solve an overflow. I have tried moving things around, but I do not have any experience in C# and I am really a novice in general. Do you have any suggestions on where to start, or am I missing a simple fix?

All of this C# code is used to call the Win32 API function we need, and deal with its output.

$csharp = @'
using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Principal;
using System.ComponentModel;

namespace LsaSecurity
{
using LSA_HANDLE = IntPtr;

[StructLayout(LayoutKind.Sequential)]
public struct LSA_OBJECT_ATTRIBUTES
{
public int Length;
public IntPtr RootDirectory;
public IntPtr ObjectName;
public int Attributes;
public IntPtr SecurityDescriptor;
public IntPtr SecurityQualityOfService;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct LSA_UNICODE_STRING
{
public ushort Length;
public ushort MaximumLength;
[MarshalAs(UnmanagedType.LPWStr)]
public string Buffer;
}

[StructLayout(LayoutKind.Sequential)]
public struct LSA_ENUMERATION_INFORMATION
{
public IntPtr PSid;
}

sealed public class Win32Sec
{
[DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true),
SuppressUnmanagedCodeSecurityAttribute]
public 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]
public static extern uint LsaEnumerateAccountsWithUserRight(LSA_HANDLE PolicyHandle,
LSA_UNICODE_STRING[] UserRights,
out IntPtr EnumerationBuffer,
out int CountReturned);

[DllImport("advapi32")]
public static extern int LsaNtStatusToWinError(int NTSTATUS);

[DllImport("advapi32")]
public static extern int LsaClose(IntPtr PolicyHandle);

[DllImport("advapi32")]
public static extern int LsaFreeMemory(IntPtr Buffer);
}

public class LsaWrapper : IDisposable
{
public 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;
const uint STATUS_NO_MORE_ENTRIES = 0xc000001A;

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 SecurityIdentifier[] ReadPrivilege(string privilege)
{
LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1];
privileges[0] = InitLsaString(privilege);
IntPtr buffer;
int count = 0;
uint ret = Win32Sec.LsaEnumerateAccountsWithUserRight(lsaHandle, privileges, out buffer, out count);

if (ret == 0)
{
SecurityIdentifier[] sids = new SecurityIdentifier[count];

for (int i = 0, elemOffs = (int)buffer; i < count; i++)
{
LSA_ENUMERATION_INFORMATION lsaInfo = (LSA_ENUMERATION_INFORMATION)Marshal.PtrToStructure(
(IntPtr)elemOffs, typeof(LSA_ENUMERATION_INFORMATION));

sids = new SecurityIdentifier(lsaInfo.PSid);

elemOffs += Marshal.SizeOf(typeof(LSA_ENUMERATION_INFORMATION));
}

return sids;
}

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

public 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;
}
}
}
'@

Add-Type -TypeDefinition $csharp

# Here's the code that uses the C# classes we've added.

$lsa = New-Object LsaSecurity.LsaWrapper
$sids = $lsa.ReadPrivilege('SeInteractiveLogonRight')

# ReadPrivilege() returns an array of [SecurityIdentifier] objects. We'll try to translate them into a more human-friendly
# NTAccount object here (which will give us a Domain\User string), and output the value whether the translation succeeds or not.

foreach ($sid in $sids)
{
try
{
$sid.Translate([System.Security.Principal.NTAccount]).Value
}
catch
{
$sid.Value
}
}



The exception:

Exception calling "ReadPrivilege" with "1" argument(s): "Arithmetic operation resulted in an overflow."
At line:232 char:1
+ $blah = $lsa.ReadPrivilege("SeInteractiveLogonRight")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : OverflowException

Continue reading...
 
Back
Top