< Summary

Class:SharpHoundRPC.Wrappers.LSAPolicy
Assembly:SharpHoundRPC
File(s):D:\a\SharpHoundCommon\SharpHoundCommon\src\SharpHoundRPC\Wrappers\LSAPolicy.cs
Covered lines:0
Uncovered lines:107
Coverable lines:107
Total lines:171
Line coverage:0% (0 of 107)
Covered branches:0
Total branches:32
Branch coverage:0% (0 of 32)

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%100%
GetLocalDomainInformation()0%200%
GetPrincipalsWithPrivilege(...)0%200%
GetResolvedPrincipalsWithPrivilege(...)0%1600%
LookupSid(...)0%400%
LookupSids(...)0%600%
OpenPolicy(...)0%200%

File(s)

D:\a\SharpHoundCommon\SharpHoundCommon\src\SharpHoundRPC\Wrappers\LSAPolicy.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Security.Principal;
 5using SharpHoundRPC.Handles;
 6using SharpHoundRPC.LSANative;
 7using SharpHoundRPC.Shared;
 8
 9namespace SharpHoundRPC.Wrappers
 10{
 11    public class LSAPolicy : LSABase, ILSAPolicy
 12    {
 13        private string _computerName;
 14
 015        public LSAPolicy(string computerName, LSAHandle handle) : base(handle)
 016        {
 017            _computerName = computerName;
 018        }
 19
 20        public Result<(string Name, string Sid)> GetLocalDomainInformation()
 021        {
 022            var result = LSAMethods.LsaQueryInformationPolicy(Handle,
 023                LSAEnums.LSAPolicyInformation.PolicyAccountDomainInformation);
 24
 025            if (result.status.IsError()) return result.status;
 26
 027            var domainInfo = result.pointer.GetData<LSAStructs.PolicyAccountDomainInfo>();
 28            try
 029            {
 030                var domainSid = new SecurityIdentifier(domainInfo.DomainSid);
 031                return (domainInfo.DomainName.ToString(), domainSid.Value.ToUpper());
 32            }
 033            catch (ArgumentException)
 034            {
 035                return "Invalid DomainSID returned by LSA";
 36            }
 037        }
 38
 39        public Result<IEnumerable<SecurityIdentifier>> GetPrincipalsWithPrivilege(string userRight)
 040        {
 041            var (status, sids, count) = LSAMethods.LsaEnumerateAccountsWithUserRight(Handle, userRight);
 42
 043            if (status.IsError()) return status;
 44
 045            return Result<IEnumerable<SecurityIdentifier>>.Ok(sids.GetEnumerable<SecurityIdentifier>(count));
 046        }
 47
 48        public Result<IEnumerable<(SecurityIdentifier sid, string Name, SharedEnums.SidNameUse Use, string Domain)>>
 49            GetResolvedPrincipalsWithPrivilege(string userRight)
 050        {
 051            var (status, sids, count) = LSAMethods.LsaEnumerateAccountsWithUserRight(Handle, userRight);
 052            using (sids)
 053            {
 054                if (status.IsError()) return status;
 55
 056                var (lookupStatus, referencedDomains, names, lookupCount) =
 057                    LSAMethods.LsaLookupSids(Handle, sids, count);
 058                if (lookupStatus.IsError())
 059                {
 060                    referencedDomains.Dispose();
 061                    names.Dispose();
 062                    return lookupStatus;
 63                }
 64
 065                var translatedNames = names.GetEnumerable<LSAStructs.LSATranslatedNames>(count).ToArray();
 066                var domainList = referencedDomains.GetData<LSAStructs.LSAReferencedDomains>();
 067                var safeDomains = new LSAPointer(domainList.Domains);
 068                var domains = safeDomains.GetEnumerable<LSAStructs.LSATrustInformation>(domainList.Entries).ToArray();
 069                var convertedSids = sids.GetEnumerable<SecurityIdentifier>(lookupCount).ToArray();
 70
 071                var ret = new List<(SecurityIdentifier sid, string Name, SharedEnums.SidNameUse Use, string Domain)>();
 72
 073                for (var i = 0; i < count; i++)
 074                {
 075                    var use = translatedNames[i].Use;
 076                    var sid = convertedSids[i];
 77                    //Special LSALookupSids cases. If we hit any of these cases, we're missing important data, so dont r
 78                    //If use is Domain, The DomainIndex member is valid, but the Name member is not valid and must be ig
 79                    //If use is Unknown or Invalid, Both DomainIndex and Name are not valid and must be ignored.
 080                    if (use is SharedEnums.SidNameUse.Domain or SharedEnums.SidNameUse.Invalid
 081                        or SharedEnums.SidNameUse.Unknown)
 082                    {
 083                        ret.Add((sid, null, use, null));
 084                        continue;
 85                    }
 86
 087                    var translatedName = translatedNames[i].Name.ToString();
 088                    var domainIndex = translatedNames[i].DomainIndex;
 89                    //If use is WellKnownGroup, Name is valid, but domainindex is not
 90                    //If there is no corresponding domain for an account, domainindex contains a negative value.
 091                    var domain = use == SharedEnums.SidNameUse.WellKnownGroup || domainIndex < 0
 092                        ? null
 093                        : domains[translatedNames[i].DomainIndex].Name.ToString();
 094                    ret.Add((sid, translatedName, use, domain));
 095                }
 96
 097                referencedDomains.Dispose();
 098                names.Dispose();
 099                safeDomains.Dispose();
 100
 0101                return ret;
 102            }
 0103        }
 104
 105        public Result<(string Name, SharedEnums.SidNameUse Use, string Domains)> LookupSid(SecurityIdentifier sid)
 0106        {
 0107            if (sid == null)
 0108                return "SID cannot be null";
 109
 0110            var (status, referencedDomains, names, count) = LSAMethods.LsaLookupSids(Handle, new[] {sid});
 0111            if (status.IsError())
 0112            {
 0113                names.Dispose();
 0114                referencedDomains.Dispose();
 0115                return status;
 116            }
 117
 0118            var translatedNames = names.GetEnumerable<LSAStructs.LSATranslatedNames>(count).ToArray();
 0119            var domainList = referencedDomains.GetData<LSAStructs.LSAReferencedDomains>();
 0120            var safeDomains = new LSAPointer(domainList.Domains);
 0121            var domains = safeDomains.GetEnumerable<LSAStructs.LSATrustInformation>(domainList.Entries).ToArray();
 0122            names.Dispose();
 0123            referencedDomains.Dispose();
 0124            safeDomains.Dispose();
 0125            return (translatedNames[0].Name.ToString(), translatedNames[0].Use,
 0126                domains[translatedNames[0].DomainIndex].Name.ToString());
 0127        }
 128
 129        public Result<IEnumerable<(SecurityIdentifier Sid, string Name, SharedEnums.SidNameUse Use, string Domain)>>
 130            LookupSids(
 131                SecurityIdentifier[] sids)
 0132        {
 0133            sids = sids.Where(x => x != null).ToArray();
 0134            if (sids.Length == 0)
 0135                return "No non-null SIDs specified";
 136
 0137            var (status, referencedDomains, names, count) = LSAMethods.LsaLookupSids(Handle, sids);
 0138            if (status.IsError())
 0139            {
 0140                referencedDomains.Dispose();
 0141                names.Dispose();
 0142                return status;
 143            }
 144
 0145            var translatedNames = names.GetEnumerable<LSAStructs.LSATranslatedNames>(count).ToArray();
 0146            var domainList = referencedDomains.GetData<LSAStructs.LSAReferencedDomains>();
 0147            var safeDomains = new LSAPointer(domainList.Domains);
 0148            var domains = safeDomains.GetEnumerable<LSAStructs.LSATrustInformation>(domainList.Entries).ToArray();
 149
 0150            var ret = new List<(SecurityIdentifier Sid, string Name, SharedEnums.SidNameUse Use, string Domain)>();
 0151            for (var i = 0; i < count; i++)
 0152                ret.Add((sids[i], translatedNames[i].Name.ToString(), translatedNames[i].Use,
 0153                    domains[translatedNames[i].DomainIndex].Name.ToString()));
 154
 0155            referencedDomains.Dispose();
 0156            names.Dispose();
 0157            safeDomains.Dispose();
 158
 0159            return ret.ToArray();
 0160        }
 161
 162        public static Result<LSAPolicy> OpenPolicy(string computerName, LSAEnums.LsaOpenMask desiredAccess =
 163            LSAEnums.LsaOpenMask.LookupNames | LSAEnums.LsaOpenMask.ViewLocalInfo)
 0164        {
 0165            var (status, handle) = LSAMethods.LsaOpenPolicy(computerName, desiredAccess);
 0166            if (status.IsError()) return status;
 167
 0168            return new LSAPolicy(computerName, handle);
 0169        }
 170    }
 171}