none
Query Local Computer Policy RRS feed

  • Question

  • 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[i] = 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

    Thursday, October 24, 2019 1:18 PM

All replies