< Summary

Class:SharpHoundCommonLib.Processors.ContainerProcessor
Assembly:SharpHoundCommonLib
File(s):D:\a\SharpHoundCommon\SharpHoundCommon\src\CommonLib\Processors\ContainerProcessor.cs
Covered lines:69
Uncovered lines:12
Coverable lines:81
Total lines:167
Line coverage:85.1% (69 of 81)
Covered branches:24
Total branches:24
Branch coverage:100% (24 of 24)

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%20100%
IsDistinguishedNameFiltered(...)100%40100%
GetContainingObject(...)100%100%
GetContainingObject(...)100%40100%
GetContainerChildObjects(...)100%100%
GetContainerChildObjects()100%80100%
ReadContainerGPLinks(...)100%100%
ReadContainerGPLinks()100%60100%
ReadBlocksInheritance(...)100%10100%

File(s)

D:\a\SharpHoundCommon\SharpHoundCommon\src\CommonLib\Processors\ContainerProcessor.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.DirectoryServices.Protocols;
 4using Microsoft.Extensions.Logging;
 5using SharpHoundCommonLib.Enums;
 6using SharpHoundCommonLib.LDAPQueries;
 7using SharpHoundCommonLib.OutputTypes;
 8
 9namespace SharpHoundCommonLib.Processors
 10{
 11    public class ContainerProcessor
 12    {
 13        private readonly ILogger _log;
 14        private readonly ILDAPUtils _utils;
 15
 616        public ContainerProcessor(ILDAPUtils utils, ILogger log = null)
 617        {
 618            _utils = utils;
 619            _log = log ?? Logging.LogProvider.CreateLogger("ContainerProc");
 620        }
 21
 22        private static bool IsDistinguishedNameFiltered(string distinguishedName)
 723        {
 724            var dn = distinguishedName.ToUpper();
 825            if (dn.Contains("CN=PROGRAM DATA,DC=")) return true;
 26
 927            if (dn.Contains("CN=SYSTEM,DC=")) return true;
 28
 329            return false;
 730        }
 31
 32        /// <summary>
 33        /// Helper function to pass commonlib types to GetContainingObject
 34        /// </summary>
 35        /// <param name="entry"></param>
 36        /// <returns></returns>
 37        public TypedPrincipal GetContainingObject(ISearchResultEntry entry)
 038        {
 039            return GetContainingObject(entry.DistinguishedName);
 040        }
 41
 42        /// <summary>
 43        /// Uses the distinguishedname of an object to get its containing object by stripping the first part and using t
 44        /// Saves lots of LDAP calls compared to enumerating container info directly
 45        /// </summary>
 46        /// <param name="distinguishedName"></param>
 47        /// <returns></returns>
 48        public TypedPrincipal GetContainingObject(string distinguishedName)
 449        {
 450            var containerDn = Helpers.RemoveDistinguishedNamePrefix(distinguishedName);
 51
 452            if (containerDn.StartsWith("CN=BUILTIN", StringComparison.OrdinalIgnoreCase))
 153            {
 154                var domain = Helpers.DistinguishedNameToDomain(distinguishedName);
 155                var domainSid = _utils.GetSidFromDomainName(domain);
 156                return new TypedPrincipal(domainSid, Label.Domain);
 57            }
 58
 359            if (string.IsNullOrEmpty(containerDn))
 160                return null;
 61
 262            return _utils.ResolveDistinguishedName(containerDn);
 463        }
 64
 65        /// <summary>
 66        ///     Helper function using commonlib types to pass to GetContainerChildObjects
 67        /// </summary>
 68        /// <param name="result"></param>
 69        /// <param name="entry"></param>
 70        /// <returns></returns>
 71        public IEnumerable<TypedPrincipal> GetContainerChildObjects(ResolvedSearchResult result,
 72            ISearchResultEntry entry)
 073        {
 074            var name = result.DisplayName;
 075            var dn = entry.DistinguishedName;
 76
 077            return GetContainerChildObjects(dn, name);
 078        }
 79
 80        /// <summary>
 81        ///     Finds all immediate child objects of a container.
 82        /// </summary>
 83        /// <param name="distinguishedName"></param>
 84        /// <param name="containerName"></param>
 85        /// <returns></returns>
 86        public IEnumerable<TypedPrincipal> GetContainerChildObjects(string distinguishedName, string containerName = "")
 187        {
 188            var filter = new LDAPFilter().AddComputers().AddUsers().AddGroups().AddOUs().AddContainers();
 189            filter.AddCertificateAuthorities().AddCertificateTemplates().AddEnterpriseCertificationAuthorities();
 1790            foreach (var childEntry in _utils.QueryLDAP(filter.GetFilter(), SearchScope.OneLevel,
 191                         CommonProperties.ObjectID, Helpers.DistinguishedNameToDomain(distinguishedName),
 192                         adsPath: distinguishedName))
 793            {
 794                var dn = childEntry.DistinguishedName;
 795                if (IsDistinguishedNameFiltered(dn))
 496                {
 497                    _log.LogTrace("Skipping filtered child {Child} for {Container}", dn, containerName);
 498                    continue;
 99                }
 100
 3101                var id = childEntry.GetObjectIdentifier();
 3102                if (id == null)
 1103                {
 1104                    _log.LogTrace("Got null ID for {ChildDN} under {Container}", childEntry.DistinguishedName,
 1105                        containerName);
 1106                    continue;
 107                }
 108
 2109                var res = _utils.ResolveIDAndType(id, Helpers.DistinguishedNameToDomain(dn));
 2110                if (res == null)
 1111                {
 1112                    _log.LogTrace("Failed to resolve principal for {ID}", id);
 1113                    continue;
 114                }
 115
 1116                yield return res;
 1117            }
 1118        }
 119
 120        public IEnumerable<GPLink> ReadContainerGPLinks(ResolvedSearchResult result, ISearchResultEntry entry)
 0121        {
 0122            var links = entry.GetProperty(LDAPProperties.GPLink);
 123
 0124            return ReadContainerGPLinks(links);
 0125        }
 126
 127        /// <summary>
 128        ///     Reads the "gplink" property from a SearchResult and converts the links into the acceptable SharpHound fo
 129        /// </summary>
 130        /// <param name="gpLink"></param>
 131        /// <returns></returns>
 132        public IEnumerable<GPLink> ReadContainerGPLinks(string gpLink)
 3133        {
 3134            if (gpLink == null)
 1135                yield break;
 136
 14137            foreach (var link in Helpers.SplitGPLinkProperty(gpLink))
 4138            {
 4139                var enforced = link.Status.Equals("2");
 140
 4141                var res = _utils.ResolveDistinguishedName(link.DistinguishedName);
 142
 4143                if (res == null)
 1144                {
 1145                    _log.LogTrace("Failed to resolve DN {DN}", link.DistinguishedName);
 1146                    continue;
 147                }
 148
 3149                yield return new GPLink
 3150                {
 3151                    GUID = res.ObjectIdentifier,
 3152                    IsEnforced = enforced
 3153                };
 3154            }
 2155        }
 156
 157        /// <summary>
 158        ///     Checks if a container blocks privilege inheritance
 159        /// </summary>
 160        /// <param name="gpOptions"></param>
 161        /// <returns></returns>
 162        public static bool ReadBlocksInheritance(string gpOptions)
 3163        {
 3164            return gpOptions is "1";
 3165        }
 166    }
 167}