From fe89a1c8741f5b676cb5df96647986070473a9ff Mon Sep 17 00:00:00 2001 From: Katie Strader Date: Tue, 3 Dec 2024 16:03:03 -0700 Subject: [PATCH] Added more test coverage for LdapPropertyProcessor --- test/unit/LdapPropertyTests.cs | 324 ++++++++++++++++++++++++++------- 1 file changed, 258 insertions(+), 66 deletions(-) diff --git a/test/unit/LdapPropertyTests.cs b/test/unit/LdapPropertyTests.cs index b764407e..eb4e048c 100644 --- a/test/unit/LdapPropertyTests.cs +++ b/test/unit/LdapPropertyTests.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; +using System.ComponentModel; +using System.DirectoryServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Principal; using System.Threading.Tasks; using CommonLibTest.Facades; +using Moq; using SharpHoundCommonLib; using SharpHoundCommonLib.Enums; using SharpHoundCommonLib.OutputTypes; @@ -990,6 +993,41 @@ public void LDAPPropertyProcessor_ParseAllProperties_GUID() { Assert.Equal(guidExpected.ToString(), guidActual); } + [Fact] + public void LDAPPropertyProcessor_ReadACAProperties() { + var ecdsa = ECDsa.Create(); + var req = new CertificateRequest("cn=foobar", ecdsa, HashAlgorithmName.SHA256); + var cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(5)); + + var bytes = cert.Export(X509ContentType.Cert, "abc"); + var mock = new MockDirectoryObject( + "CN\u003dDUMPSTER-DC01-CA,CN\u003dAIA,CN\u003dPUBLIC KEY SERVICES,CN\u003dSERVICES,CN\u003dCONFIGURATION,DC\u003dDUMPSTER,DC\u003dFIRE", + new Dictionary + { + {"description", null}, + {"domain", "DUMPSTER.FIRE"}, + {"name", "DUMPSTER-DC01-CA@DUMPSTER.FIRE"}, + {"domainsid", "S-1-5-21-2697957641-2271029196-387917394"}, + {"whencreated", 1683986131}, + {LDAPProperties.CACertificate, bytes} + }, "","2F9F3630-F46A-49BF-B186-6629994EBCF9"); + + var test = LdapPropertyProcessor.ReadRootCAProperties(mock); + var keys = test.Keys; + + //These are not common properties + Assert.DoesNotContain("domain", keys); + Assert.DoesNotContain("name", keys); + Assert.DoesNotContain("domainsid", keys); + + Assert.Contains("whencreated", keys); + Assert.Contains("certthumbprint", keys); + Assert.Contains("certname", keys); + Assert.Contains("certchain", keys); + Assert.Contains("hasbasicconstraints", keys); + Assert.Contains("basicconstraintpathlength", keys); + } + [Fact] public async void LDAPPropertyProcessor_ReadDomainProperties_TestExpirePassword() { @@ -1167,6 +1205,33 @@ public async Task LDAPPropertyProcessor_ReadUserProperties_TestLastLogonNull() } + [Fact] + public async void LDAPPropertyProcessor_ReadDomainProperties_ConvertNanoDuration_TestReadableString() + { + var mock = new MockDirectoryObject("DC\u003dtestlab,DC\u003dlocal", new Dictionary + { + {LDAPProperties.MaxPwdAge, -11211100000000} + }, "S-1-5-21-3130019616-2776909439-2417379446",""); + + var processor = new LdapPropertyProcessor(new MockLdapUtils()); + var test = await processor.ReadDomainProperties(mock,"testlab.local"); + Assert.Contains("maxpwdage", test.Keys); + Assert.Equal("12 days, 23 hours, 25 minutes, 10 seconds", test["maxpwdage"] as string); + } + + [Fact] + public async void LDAPPropertyProcessor_ReadDomainProperties_ConvertNanoDuration_TestNull() + { + var mock = new MockDirectoryObject("DC\u003dtestlab,DC\u003dlocal", new Dictionary + { + {LDAPProperties.MaxPwdAge, 100} + }, "S-1-5-21-3130019616-2776909439-2417379446",""); + + var processor = new LdapPropertyProcessor(new MockLdapUtils()); + var test = await processor.ReadDomainProperties(mock,"testlab.local"); + Assert.DoesNotContain("maxpwdage", test.Keys); + } + [WindowsOnlyFact] public async Task LDAPPropertyProcessor_ReadUserProperties_TestLastLogonTimeStampNull() { @@ -1358,6 +1423,12 @@ public async Task LDAPPropertyProcessor_ReadComputerProperties_TestDelegatesNull [WindowsOnlyFact] public async Task LDAPPropertyProcessor_ReadComputerProperties_AllowedToActOnBehalfOfOtherIdentity() { + var mockUtils = new Mock(); + var mockSecurityDescriptor = new Mock(MockBehavior.Loose, null); + var mockRule = new Mock(MockBehavior.Loose, null); + var collection = new List(); + var expectedPrincipalSID = "S-1-5-21-3130019616-2776909439-2417379446-512"; + var expectedPrincipalType = Label.CertTemplate; var mock = new MockDirectoryObject("CN\u003dWIN10,OU\u003dTestOU,DC\u003dtestlab,DC\u003dlocal", new Dictionary { @@ -1370,30 +1441,81 @@ public async Task LDAPPropertyProcessor_ReadComputerProperties_AllowedToActOnBeh {"mail", "test@testdomain.com"}, {"admincount", "c"}, { - "sidhistory", new[] - { + "msds-allowedtoactonbehalfofotheridentity", + Utils.B64ToBytes("AQUAAAAAAAUVAAAAIE+Qun9GhKV2SBaQUQQAAA==") - } - }, + + } + }, "S-1-5-21-3130019616-2776909439-2417379446-1101",""); + + var sd = new ActiveDirectorySecurityDescriptor(new ActiveDirectorySecurity()); + mockUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(sd); + mockSecurityDescriptor.Setup(m => m.SetSecurityDescriptorBinaryForm(It.IsAny())).Throws(new OverflowException()); + mockUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(mockSecurityDescriptor.Object); + collection.Add(mockRule.Object); + mockSecurityDescriptor.Setup(m => m.GetAccessRules(It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(collection); + mockUtils.Setup(x => x.ResolveIDAndType(It.IsAny(), It.IsAny())) + .ReturnsAsync((true, new TypedPrincipal(expectedPrincipalSID, expectedPrincipalType))); + + + var processor = new LdapPropertyProcessor(mockUtils.Object); + var test = await processor.ReadComputerProperties(mock, "testlab.local"); + + //AllowedToAct + Assert.Single(test.AllowedToAct); + Assert.Contains(new TypedPrincipal + { + ObjectIdentifier = expectedPrincipalSID, + ObjectType = expectedPrincipalType + }, test.AllowedToAct); + } + + [WindowsOnlyFact] + public async Task LDAPPropertyProcessor_ConvertEncryptionTypes_SupportedEncrypTionTypes_0() + { + var mock = new MockDirectoryObject("CN\u003dWIN10,OU\u003dTestOU,DC\u003dtestlab,DC\u003dlocal", + new Dictionary + { + {"description", "Test"}, + {"useraccountcontrol", 0x1001000.ToString()}, + {"lastlogon", "132673011142753043"}, + {"lastlogontimestamp", "132670318095676525"}, + {"operatingsystem", "Windows 10 Enterprise"}, + {"operatingsystemservicepack", "1607"}, + {"mail", "test@testdomain.com"}, + {"admincount", "c"}, { - "msds-allowedtodelegateto", new[] - { - "ldap/PRIMARY.testlab.local/testlab.local", - "ldap/PRIMARY.testlab.local", - "ldap/PRIMARY" - } - }, - {"pwdlastset", "132131667346106691"}, + "msds-supportedencryptiontypes", "0" + } + }, "S-1-5-21-3130019616-2776909439-2417379446-1101",""); + + var processor = new LdapPropertyProcessor(new MockLdapUtils()); + var test = await processor.ReadComputerProperties(mock, "testlab.local"); + var props = test.Props; + var keys = props.Keys; + + Assert.Contains("supportedencryptiontypes", keys); + + Assert.Equal(new List(["Not defined"]), (List)props["supportedencryptiontypes"]); + } + + [WindowsOnlyFact] + public async Task LDAPPropertyProcessor_ReadComputerProperties_ConvertEncryptionTypes_DES_CBC_CRC() + { + var mock = new MockDirectoryObject("CN\u003dWIN10,OU\u003dTestOU,DC\u003dtestlab,DC\u003dlocal", + new Dictionary + { + {"description", "Test"}, + {"useraccountcontrol", 0x1001000.ToString()}, + {"lastlogon", "132673011142753043"}, + {"lastlogontimestamp", "132670318095676525"}, + {"operatingsystem", "Windows 10 Enterprise"}, + {"operatingsystemservicepack", "1607"}, + {"mail", "test@testdomain.com"}, + {"admincount", "c"}, { - "serviceprincipalname", new[] - { - "WSMAN/WIN10", - "WSMAN/WIN10.testlab.local", - "RestrictedKrbHost/WIN10", - "HOST/WIN10", - "RestrictedKrbHost/WIN10.testlab.local", - "HOST/WIN10.testlab.local" - } + "msds-supportedencryptiontypes", "1" } }, "S-1-5-21-3130019616-2776909439-2417379446-1101",""); @@ -1402,55 +1524,125 @@ public async Task LDAPPropertyProcessor_ReadComputerProperties_AllowedToActOnBeh var props = test.Props; var keys = props.Keys; - //UAC - Assert.Contains("enabled", keys); - Assert.Contains("unconstraineddelegation", keys); - Assert.Contains("trustedtoauth", keys); - Assert.Contains("isdc", keys); - Assert.Contains("lastlogon", keys); - Assert.Contains("lastlogontimestamp", keys); - Assert.Contains("pwdlastset", keys); - Assert.True((bool)props["enabled"]); - Assert.False((bool)props["unconstraineddelegation"]); - Assert.True((bool)props["trustedtoauth"]); - Assert.False((bool)props["isdc"]); + Assert.Contains("supportedencryptiontypes", keys); - Assert.Contains("lastlogon", keys); - Assert.Equal(1622827514, (long)props["lastlogon"]); - Assert.Contains("lastlogontimestamp", keys); - Assert.Equal(1622558209, (long)props["lastlogontimestamp"]); - Assert.Contains("pwdlastset", keys); - Assert.Equal(1568693134, (long)props["pwdlastset"]); + Assert.Equal(new List(["DES-CBC-CRC"]), (List)props["supportedencryptiontypes"]); + } + + [WindowsOnlyFact] + public async Task LDAPPropertyProcessor_ReadComputerProperties_ConvertEncryptionTypes_DES_CBC_MD5() + { + var mock = new MockDirectoryObject("CN\u003dWIN10,OU\u003dTestOU,DC\u003dtestlab,DC\u003dlocal", + new Dictionary + { + {"description", "Test"}, + {"useraccountcontrol", 0x1001000.ToString()}, + {"lastlogon", "132673011142753043"}, + {"lastlogontimestamp", "132670318095676525"}, + {"operatingsystem", "Windows 10 Enterprise"}, + {"operatingsystemservicepack", "1607"}, + {"mail", "test@testdomain.com"}, + {"admincount", "c"}, + { + "msds-supportedencryptiontypes", "2" + } + }, "S-1-5-21-3130019616-2776909439-2417379446-1101",""); - //AllowedToDelegate - Assert.Single(test.AllowedToDelegate); - Assert.Contains(new TypedPrincipal - { - ObjectIdentifier = "S-1-5-21-3130019616-2776909439-2417379446-1001", - ObjectType = Label.Computer - }, test.AllowedToDelegate); + var processor = new LdapPropertyProcessor(new MockLdapUtils()); + var test = await processor.ReadComputerProperties(mock, "testlab.local"); + var props = test.Props; + var keys = props.Keys; - //Other Stuff - Assert.Contains("serviceprincipalnames", keys); - Assert.Equal(6, (props["serviceprincipalnames"] as string[]).Length); - Assert.Contains("operatingsystem", keys); - Assert.Equal("Windows 10 Enterprise 1607", props["operatingsystem"] as string); - Assert.Contains("description", keys); - Assert.Equal("Test", props["description"] as string); - Assert.Contains("email", keys); - Assert.Equal("test@testdomain.com", props["email"] as string); + Assert.Contains("supportedencryptiontypes", keys); - //SidHistory - Assert.Contains("sidhistory", keys); - var sh = props["sidhistory"] as string[]; - Assert.Single(sh); - Assert.Contains("S-1-5-21-3130019616-2776909439-2417379446-1105", sh); - Assert.Single(test.SidHistory); - Assert.Contains(new TypedPrincipal - { - ObjectIdentifier = "S-1-5-21-3130019616-2776909439-2417379446-1105", - ObjectType = Label.User - }, test.SidHistory); + Assert.Equal(new List(["DES-CBC-MD5"]), (List)props["supportedencryptiontypes"]); + } + + [WindowsOnlyFact] + public async Task LDAPPropertyProcessor_ReadComputerProperties_ConvertEncryptionTypes_RC4_HMAC_MD5() + { + var mock = new MockDirectoryObject("CN\u003dWIN10,OU\u003dTestOU,DC\u003dtestlab,DC\u003dlocal", + new Dictionary + { + {"description", "Test"}, + {"useraccountcontrol", 0x1001000.ToString()}, + {"lastlogon", "132673011142753043"}, + {"lastlogontimestamp", "132670318095676525"}, + {"operatingsystem", "Windows 10 Enterprise"}, + {"operatingsystemservicepack", "1607"}, + {"mail", "test@testdomain.com"}, + {"admincount", "c"}, + { + "msds-supportedencryptiontypes", "4" + } + }, "S-1-5-21-3130019616-2776909439-2417379446-1101",""); + + var processor = new LdapPropertyProcessor(new MockLdapUtils()); + var test = await processor.ReadComputerProperties(mock, "testlab.local"); + var props = test.Props; + var keys = props.Keys; + + Assert.Contains("supportedencryptiontypes", keys); + + Assert.Equal(new List(["RC4-HMAC-MD5"]), (List)props["supportedencryptiontypes"]); + } + + [WindowsOnlyFact] + public async Task LDAPPropertyProcessor_ReadComputerProperties_ConvertEncryptionTypes_AES128_CTS_HMAC_SHA1_96() + { + var mock = new MockDirectoryObject("CN\u003dWIN10,OU\u003dTestOU,DC\u003dtestlab,DC\u003dlocal", + new Dictionary + { + {"description", "Test"}, + {"useraccountcontrol", 0x1001000.ToString()}, + {"lastlogon", "132673011142753043"}, + {"lastlogontimestamp", "132670318095676525"}, + {"operatingsystem", "Windows 10 Enterprise"}, + {"operatingsystemservicepack", "1607"}, + {"mail", "test@testdomain.com"}, + {"admincount", "c"}, + { + "msds-supportedencryptiontypes", "8" + } + }, "S-1-5-21-3130019616-2776909439-2417379446-1101",""); + + var processor = new LdapPropertyProcessor(new MockLdapUtils()); + var test = await processor.ReadComputerProperties(mock, "testlab.local"); + var props = test.Props; + var keys = props.Keys; + + Assert.Contains("supportedencryptiontypes", keys); + + Assert.Equal(new List(["AES128-CTS-HMAC-SHA1-96"]), (List)props["supportedencryptiontypes"]); + } + + [WindowsOnlyFact] + public async Task LDAPPropertyProcessor_ReadComputerProperties_ConvertEncryptionTypes_AES256_CTS_HMAC_SHA1_96() + { + var mock = new MockDirectoryObject("CN\u003dWIN10,OU\u003dTestOU,DC\u003dtestlab,DC\u003dlocal", + new Dictionary + { + {"description", "Test"}, + {"useraccountcontrol", 0x1001000.ToString()}, + {"lastlogon", "132673011142753043"}, + {"lastlogontimestamp", "132670318095676525"}, + {"operatingsystem", "Windows 10 Enterprise"}, + {"operatingsystemservicepack", "1607"}, + {"mail", "test@testdomain.com"}, + {"admincount", "c"}, + { + "msds-supportedencryptiontypes", "16" + } + }, "S-1-5-21-3130019616-2776909439-2417379446-1101",""); + + var processor = new LdapPropertyProcessor(new MockLdapUtils()); + var test = await processor.ReadComputerProperties(mock, "testlab.local"); + var props = test.Props; + var keys = props.Keys; + + Assert.Contains("supportedencryptiontypes", keys); + + Assert.Equal(new List(["AES256-CTS-HMAC-SHA1-96"]), (List)props["supportedencryptiontypes"]); } } }