diff --git a/test/unit/CertAbuseProcessorTest.cs b/test/unit/CertAbuseProcessorTest.cs index 3a5ce818..fe54e783 100644 --- a/test/unit/CertAbuseProcessorTest.cs +++ b/test/unit/CertAbuseProcessorTest.cs @@ -1,4 +1,12 @@ using System; +using System.DirectoryServices; +using System.Threading.Tasks; +using CommonLibTest.Facades; +using Moq; +using Newtonsoft.Json; +using SharpHoundCommonLib; +using SharpHoundCommonLib.Processors; +using Xunit; using Xunit.Abstractions; namespace CommonLibTest { @@ -77,26 +85,27 @@ public void Dispose() { // Assert.Empty(results); // } - // [Fact] - // public void CertAbuseProcessor_ProcessCAPermissions_NullSecurity_ReturnsNull() - // { - // var mockUtils = new Mock(); - // var processor = new CertAbuseProcessor(mockUtils.Object); + [Fact] + public async Task CertAbuseProcessor_ProcessCAPermissions_NullSecurity_ReturnsNull() + { + var processor = new CertAbuseProcessor(new MockLdapUtils()); - // var results = processor.ProcessRegistryEnrollmentPermissions(null, null, "test"); + var results = await processor.ProcessRegistryEnrollmentPermissions(null, "DUMPSTER.FIRE", null, "test"); - // Assert.Empty(results); - // } + Assert.Equal("Value cannot be null. (Parameter 'machineName')", results.FailureReason); + Assert.False(results.Collected); + Assert.Empty(results.Data); + } // [WindowsOnlyFact] // public void CertAbuseProcessor_ProcessCAPermissions_ReturnsCorrectValues() // { - // var mockUtils = new Mock(); + // var mockUtils = new Mock(); // var sd = new ActiveDirectorySecurityDescriptor(new ActiveDirectorySecurity()); // mockUtils.Setup(x => x.MakeSecurityDescriptor()).Returns(sd); // var processor = new CertAbuseProcessor(mockUtils.Object); // var bytes = Helpers.B64ToBytes(CASecurityFixture); - + // // var results = processor.ProcessCAPermissions(bytes, "TESTLAB.LOCAL", "test", false); // _testOutputHelper.WriteLine(JsonConvert.SerializeObject(results, Formatting.Indented)); // Assert.Contains(results, diff --git a/test/unit/Facades/LSAMocks/ErrorCaseMocks/MockFailLSAPolicy_GetLocalDomainInformation.cs b/test/unit/Facades/LSAMocks/ErrorCaseMocks/MockFailLSAPolicy_GetLocalDomainInformation.cs new file mode 100644 index 00000000..03441e0b --- /dev/null +++ b/test/unit/Facades/LSAMocks/ErrorCaseMocks/MockFailLSAPolicy_GetLocalDomainInformation.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Security.Principal; +using SharpHoundRPC; +using SharpHoundRPC.Shared; +using SharpHoundRPC.Wrappers; + +namespace CommonLibTest.Facades.LSAMocks.WorkstationMocks +{ + [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] + public class MockFailLSAPolicy_GetLocalDomainInformation : ILSAPolicy + { + public Result<(string Name, string Sid)> GetLocalDomainInformation() + { + return NtStatus.StatusAccessDenied; + } + + public Result> GetPrincipalsWithPrivilege(string userRight) + { + throw new NotImplementedException(); + } + + public Result> + GetResolvedPrincipalsWithPrivilege(string userRight) + { + return new List<(SecurityIdentifier sid, string Name, SharedEnums.SidNameUse Use, string Domain)> + { + (new SecurityIdentifier("S-1-5-32-555"), "Remote Desktop Users", SharedEnums.SidNameUse.Alias, "abc"), + (new SecurityIdentifier("S-1-5-32-544"), "Administrators", SharedEnums.SidNameUse.Alias, "abc"), + (new SecurityIdentifier($"{Consts.MockWorkstationMachineSid}-1000"), "John", SharedEnums.SidNameUse.User, "abc"), + (new SecurityIdentifier($"{Consts.MockWorkstationMachineSid}-1001"), "TestGroup", SharedEnums.SidNameUse.Alias, "abc"), + }; + } + + public Result<(string Name, SharedEnums.SidNameUse Use, string Domains)> LookupSid(SecurityIdentifier sid) + { + throw new NotImplementedException(); + } + + public Result> + LookupSids(SecurityIdentifier[] sids) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/test/unit/Facades/LSAMocks/ErrorCaseMocks/MockFailLSAPolicy_GetResolvedPrincipalsWithPrivilege.cs b/test/unit/Facades/LSAMocks/ErrorCaseMocks/MockFailLSAPolicy_GetResolvedPrincipalsWithPrivilege.cs new file mode 100644 index 00000000..0ba1dfa5 --- /dev/null +++ b/test/unit/Facades/LSAMocks/ErrorCaseMocks/MockFailLSAPolicy_GetResolvedPrincipalsWithPrivilege.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Security.Principal; +using SharpHoundRPC; +using SharpHoundRPC.Shared; +using SharpHoundRPC.Wrappers; + +namespace CommonLibTest.Facades.LSAMocks.WorkstationMocks +{ + [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] + public class MockFailLSAPolicy_GetResolvedPrincipalsWithPrivilege : ILSAPolicy + { + public Result<(string Name, string Sid)> GetLocalDomainInformation() + { + return ("WIN10", Consts.MockWorkstationMachineSid); + } + + public Result> GetPrincipalsWithPrivilege(string userRight) + { + throw new NotImplementedException(); + } + + public Result> + GetResolvedPrincipalsWithPrivilege(string userRight) + { + return NtStatus.StatusAccessDenied; + } + + public Result<(string Name, SharedEnums.SidNameUse Use, string Domains)> LookupSid(SecurityIdentifier sid) + { + throw new NotImplementedException(); + } + + public Result> + LookupSids(SecurityIdentifier[] sids) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/test/unit/LocalGroupProcessorTest.cs b/test/unit/LocalGroupProcessorTest.cs index 28d2d84a..fcdf95e3 100644 --- a/test/unit/LocalGroupProcessorTest.cs +++ b/test/unit/LocalGroupProcessorTest.cs @@ -210,6 +210,7 @@ public async Task LocalGroupProcessor_GetLocalGroups_GetMachineSidResultFailed() Assert.Single(receivedStatus); var status = receivedStatus[0]; Assert.Equal("StatusAccessDenied", status.Status); + Assert.Equal("GetMachineSid", status.Task); } [Fact] @@ -229,6 +230,7 @@ public async Task LocalGroupProcessor_GetLocalGroups_GetDomainsResultFailed() { Assert.Single(receivedStatus); var status = receivedStatus[0]; Assert.Equal("StatusAccessDenied", status.Status); + Assert.Equal("GetDomains", status.Task); } [Fact] @@ -249,6 +251,7 @@ public async Task LocalGroupProcessor_GetLocalGroups_OpenDomainResultFailed() Assert.Single(receivedStatus); var status = receivedStatus[0]; Assert.Equal("StatusAccessDenied", status.Status); + Assert.Equal("OpenDomain - BUILTIN", status.Task); } [Fact] @@ -269,6 +272,7 @@ public async Task LocalGroupProcessor_GetLocalGroups_GetAliasesFailed() Assert.Single(receivedStatus); var status = receivedStatus[0]; Assert.Equal("StatusAccessDenied", status.Status); + Assert.Equal("GetAliases - BUILTIN", status.Task); } [Fact] @@ -291,6 +295,7 @@ public async Task LocalGroupProcessor_GetLocalGroups_OpenAliasFailed() Assert.Single(receivedStatus); var status = receivedStatus[0]; Assert.Equal("StatusAccessDenied", status.Status); + Assert.Equal("OpenAlias - Administrators", status.Task); } [Fact] @@ -313,6 +318,7 @@ public async Task LocalGroupProcessor_GetLocalGroups_GetMembersFailed() Assert.Single(receivedStatus); var status = receivedStatus[0]; Assert.Equal("StatusAccessDenied", status.Status); + Assert.Equal("GetMembersInAlias - Users", status.Task); } [Fact] diff --git a/test/unit/UserRightsAssignmentProcessorTest.cs b/test/unit/UserRightsAssignmentProcessorTest.cs index 90a5a352..0f4f80cf 100644 --- a/test/unit/UserRightsAssignmentProcessorTest.cs +++ b/test/unit/UserRightsAssignmentProcessorTest.cs @@ -88,5 +88,57 @@ public async Task UserRightsAssignmentProcessor_TestTimeout() { var status = receivedStatus[0]; Assert.Equal("Timeout", status.Status); } + + [WindowsOnlyFact] + public async Task UserRightsAssignmentProcessor_TestGetLocalDomainInformationFail() + { + var mockProcessor = new Mock(new MockLdapUtils(), null); + var mockLSAPolicy = new MockFailLSAPolicy_GetLocalDomainInformation(); + mockProcessor.Setup(x => x.OpenLSAPolicy(It.IsAny())).Returns(()=> { + Task.Delay(100).Wait(); + return NtStatus.StatusAccessDenied; + }); + mockProcessor.Setup(x => x.OpenLSAPolicy(It.IsAny())).Returns(mockLSAPolicy); + var processor = mockProcessor.Object; + var machineDomainSid = $"{Consts.MockDomainSid}-1001"; + var receivedStatus = new List(); + processor.ComputerStatusEvent += async status => { + receivedStatus.Add(status); + }; + var results = await processor.GetUserRightsAssignments("win10.testlab.local", machineDomainSid, "testlab.local", false) + .ToArrayAsync(); + + Assert.Empty(results); + Assert.Single(receivedStatus); + var status = receivedStatus[0]; + Assert.Equal("StatusAccessDenied", status.Status); + Assert.Equal("LSAGetMachineSID", status.Task); + } + + [WindowsOnlyFact] + public async Task UserRightsAssignmentProcessor_TestGetResolvedPrincipalsWithPrivilegeFail() + { + var mockProcessor = new Mock(new MockLdapUtils(), null); + var mockLSAPolicy = new MockFailLSAPolicy_GetResolvedPrincipalsWithPrivilege(); + mockProcessor.Setup(x => x.OpenLSAPolicy(It.IsAny())).Returns(mockLSAPolicy); + var processor = mockProcessor.Object; + var machineDomainSid = $"{Consts.MockDomainSid}-1001"; + var receivedStatus = new List(); + processor.ComputerStatusEvent += async status => { + receivedStatus.Add(status); + }; + var results = await processor.GetUserRightsAssignments("win10.testlab.local", machineDomainSid, "testlab.local", false) + .ToArrayAsync(); + + Assert.Single(results); + + var result = results[0]; + Assert.False(result.Collected); + Assert.Equal("LSAEnumerateAccountsWithUserRights returned StatusAccessDenied", result.FailureReason); + Assert.Single(receivedStatus); + var status = receivedStatus[0]; + Assert.Equal("StatusAccessDenied", status.Status); + Assert.Equal("LSAEnumerateAccountsWithUserRight", status.Task); + } } } \ No newline at end of file