From 55b1b57f0c11bb2a95f383f276f0fbc8e5442c1c Mon Sep 17 00:00:00 2001 From: Wes Date: Mon, 21 Oct 2024 11:05:06 -0400 Subject: [PATCH 1/2] BED-4428: Refactor RemoteInteractiveLogonPrivilege to RemoteInteractiveLogonRight --- .../src/analysis/analysis_integration_test.go | 8 +- cmd/api/src/daemons/datapipe/convertors.go | 2 +- cmd/api/src/migrations/manifest.go | 2 +- cmd/api/src/test/integration/harnesses.go | 34 ++-- .../integration/harnesses/rdpharnessb.json | 2 +- .../integration/harnesses/rdpharnessb.svg | 2 +- cmd/ui/src/ducks/explore/saga.ts | 2 +- packages/cue/bh/ad/ad.cue | 6 +- packages/go/analysis/ad/post.go | 12 +- packages/go/graphschema/ad/ad.go | 173 +++++++++--------- packages/go/graphschema/azure/azure.go | 1 - packages/go/graphschema/common/common.go | 1 - .../bh-shared-ui/src/graphSchema.ts | 6 +- 13 files changed, 124 insertions(+), 127 deletions(-) diff --git a/cmd/api/src/analysis/analysis_integration_test.go b/cmd/api/src/analysis/analysis_integration_test.go index e1f7d3a7fa..4baaeb9c18 100644 --- a/cmd/api/src/analysis/analysis_integration_test.go +++ b/cmd/api/src/analysis/analysis_integration_test.go @@ -115,9 +115,9 @@ func TestFetchRemoteDesktopUsersBitmapForComputer(t *testing.T) { return nil })) - // Create a RemoteInteractiveLogonPrivilege relationship from the RDP local group to the computer to test our most common case + // Create a RemoteInteractiveLogonRight relationship from the RDP local group to the computer to test our most common case require.Nil(t, db.WriteTransaction(context.Background(), func(tx graph.Transaction) error { - _, err := tx.CreateRelationshipByIDs(harness.RDP.RDPLocalGroup.ID, harness.RDP.Computer.ID, ad.RemoteInteractiveLogonPrivilege, graph.NewProperties()) + _, err := tx.CreateRelationshipByIDs(harness.RDP.RDPLocalGroup.ID, harness.RDP.Computer.ID, ad.RemoteInteractiveLogonRight, graph.NewProperties()) return err })) @@ -169,9 +169,9 @@ func TestFetchRDPEntityBitmapForComputer(t *testing.T) { return nil })) - // Create a RemoteInteractiveLogonPrivilege relationship from the RDP local group to the computer to test our most common case + // Create a RemoteInteractiveLogonRight relationship from the RDP local group to the computer to test our most common case require.Nil(t, db.WriteTransaction(context.Background(), func(tx graph.Transaction) error { - _, err := tx.CreateRelationshipByIDs(harness.RDPHarnessWithCitrix.RDPLocalGroup.ID, harness.RDPHarnessWithCitrix.Computer.ID, ad.RemoteInteractiveLogonPrivilege, graph.NewProperties()) + _, err := tx.CreateRelationshipByIDs(harness.RDPHarnessWithCitrix.RDPLocalGroup.ID, harness.RDPHarnessWithCitrix.Computer.ID, ad.RemoteInteractiveLogonRight, graph.NewProperties()) return err })) diff --git a/cmd/api/src/daemons/datapipe/convertors.go b/cmd/api/src/daemons/datapipe/convertors.go index 949056d465..472c7be6be 100644 --- a/cmd/api/src/daemons/datapipe/convertors.go +++ b/cmd/api/src/daemons/datapipe/convertors.go @@ -49,7 +49,7 @@ func convertComputerData(computer ein.Computer, converted *ConvertedData) { } if userRight.Privilege == ein.UserRightRemoteInteractiveLogon { - converted.RelProps = append(converted.RelProps, ein.ParseUserRightData(userRight, computer, ad.RemoteInteractiveLogonPrivilege)...) + converted.RelProps = append(converted.RelProps, ein.ParseUserRightData(userRight, computer, ad.RemoteInteractiveLogonRight)...) baseNodeProp.PropertyMap[ad.HasURA.String()] = true } } diff --git a/cmd/api/src/migrations/manifest.go b/cmd/api/src/migrations/manifest.go index cbf5a33607..b2d5f3317a 100644 --- a/cmd/api/src/migrations/manifest.go +++ b/cmd/api/src/migrations/manifest.go @@ -259,7 +259,7 @@ var Manifest = []Migration{ if err := tx.Relationships().Filterf(func() graph.Criteria { return query.And( query.Or( - query.Kind(query.Relationship(), ad.RemoteInteractiveLogonPrivilege), + query.Kind(query.Relationship(), ad.RemoteInteractiveLogonRight), query.Kind(query.Relationship(), ad.LocalToComputer), query.Kind(query.Relationship(), ad.MemberOfLocalGroup), ), diff --git a/cmd/api/src/test/integration/harnesses.go b/cmd/api/src/test/integration/harnesses.go index 5614511aa5..637aebc7c0 100644 --- a/cmd/api/src/test/integration/harnesses.go +++ b/cmd/api/src/test/integration/harnesses.go @@ -531,7 +531,7 @@ func (s *RDPHarness2) Setup(testCtx *GraphTestContext) { s.UserB = testCtx.NewActiveDirectoryUser("UserB", testCtx.Harness.RootADHarness.ActiveDirectoryDomainSID) s.UserC = testCtx.NewActiveDirectoryUser("UserC", testCtx.Harness.RootADHarness.ActiveDirectoryDomainSID) - testCtx.NewRelationship(s.RDPLocalGroup, s.Computer, ad.RemoteInteractiveLogonPrivilege) + testCtx.NewRelationship(s.RDPLocalGroup, s.Computer, ad.RemoteInteractiveLogonRight) testCtx.NewRelationship(s.RDPLocalGroup, s.Computer, ad.LocalToComputer) testCtx.NewRelationship(s.RDPDomainUsersGroup, s.RDPLocalGroup, ad.MemberOfLocalGroup) testCtx.NewRelationship(s.UserA, s.RDPDomainUsersGroup, ad.MemberOf) @@ -593,40 +593,40 @@ func (s *RDPHarness) Setup(testCtx *GraphTestContext) { s.DomainGroupF = testCtx.NewActiveDirectoryGroup("Domain Group F", testCtx.Harness.RootADHarness.ActiveDirectoryDomainSID) testCtx.NewRelationship(s.EliUser, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) - testCtx.NewRelationship(s.EliUser, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.EliUser, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.DomainGroupA, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) - testCtx.NewRelationship(s.DomainGroupA, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.DomainGroupA, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.JohnUser, s.DomainGroupA, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.RDPDomainUsersGroup, s.DomainGroupA, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.JohnUser, s.RDPDomainUsersGroup, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.RohanUser, s.RDPDomainUsersGroup, ad.MemberOf, DefaultRelProperties) - testCtx.NewRelationship(s.DomainGroupF, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.DomainGroupF, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.RohanUser, s.DomainGroupF, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.AndyUser, s.DomainGroupB, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.DomainGroupB, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) - testCtx.NewRelationship(s.DomainGroupB, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.DomainGroupB, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.IrshadUser, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) testCtx.NewRelationship(s.IrshadUser, s.DomainGroupD, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.DomainGroupD, s.DomainGroupE, ad.MemberOf, DefaultRelProperties) - testCtx.NewRelationship(s.DomainGroupE, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.DomainGroupE, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.DomainGroupC, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) testCtx.NewRelationship(s.DillonUser, s.DomainGroupC, ad.MemberOf, DefaultRelProperties) - testCtx.NewRelationship(s.DillonUser, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.DillonUser, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.UliUser, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) testCtx.NewRelationship(s.UliUser, s.LocalGroupA, ad.MemberOfLocalGroup, DefaultRelProperties) testCtx.NewRelationship(s.LocalGroupA, s.Computer, ad.LocalToComputer, DefaultRelProperties) - testCtx.NewRelationship(s.LocalGroupA, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.LocalGroupA, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) - testCtx.NewRelationship(s.AlyxUser, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.AlyxUser, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.RDPLocalGroup, s.Computer, ad.LocalToComputer, DefaultRelProperties) } @@ -689,40 +689,40 @@ func (s *RDPHarnessWithCitrix) Setup(testCtx *GraphTestContext) { s.DomainGroupF = testCtx.NewActiveDirectoryGroup("Domain Group F", testCtx.Harness.RootADHarness.ActiveDirectoryDomainSID) testCtx.NewRelationship(s.EliUser, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) - testCtx.NewRelationship(s.EliUser, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.EliUser, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.DomainGroupA, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) - testCtx.NewRelationship(s.DomainGroupA, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.DomainGroupA, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.JohnUser, s.DomainGroupA, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.DomainUsersGroup, s.DomainGroupA, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.JohnUser, s.DomainUsersGroup, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.RohanUser, s.DomainUsersGroup, ad.MemberOf, DefaultRelProperties) - testCtx.NewRelationship(s.DomainGroupF, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.DomainGroupF, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.RohanUser, s.DomainGroupF, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.AndyUser, s.DomainGroupB, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.DomainGroupB, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) - testCtx.NewRelationship(s.DomainGroupB, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.DomainGroupB, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.IrshadUser, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) testCtx.NewRelationship(s.IrshadUser, s.DomainGroupD, ad.MemberOf, DefaultRelProperties) testCtx.NewRelationship(s.DomainGroupD, s.DomainGroupE, ad.MemberOf, DefaultRelProperties) - testCtx.NewRelationship(s.DomainGroupE, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.DomainGroupE, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.DomainGroupC, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) testCtx.NewRelationship(s.DillonUser, s.DomainGroupC, ad.MemberOf, DefaultRelProperties) - testCtx.NewRelationship(s.DillonUser, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.DillonUser, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.UliUser, s.RDPLocalGroup, ad.MemberOfLocalGroup, DefaultRelProperties) testCtx.NewRelationship(s.UliUser, s.LocalGroupA, ad.MemberOfLocalGroup, DefaultRelProperties) testCtx.NewRelationship(s.LocalGroupA, s.Computer, ad.LocalToComputer, DefaultRelProperties) - testCtx.NewRelationship(s.LocalGroupA, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.LocalGroupA, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) - testCtx.NewRelationship(s.AlyxUser, s.Computer, ad.RemoteInteractiveLogonPrivilege, DefaultRelProperties) + testCtx.NewRelationship(s.AlyxUser, s.Computer, ad.RemoteInteractiveLogonRight, DefaultRelProperties) testCtx.NewRelationship(s.RDPLocalGroup, s.Computer, ad.LocalToComputer, DefaultRelProperties) diff --git a/cmd/api/src/test/integration/harnesses/rdpharnessb.json b/cmd/api/src/test/integration/harnesses/rdpharnessb.json index a9744650b5..1f284a3621 100644 --- a/cmd/api/src/test/integration/harnesses/rdpharnessb.json +++ b/cmd/api/src/test/integration/harnesses/rdpharnessb.json @@ -139,7 +139,7 @@ }, { "id": "n2", - "type": "RemoteInteractiveLogonPrivilege", + "type": "RemoteInteractiveLogonRight", "style": {}, "properties": {}, "fromId": "n1", diff --git a/cmd/api/src/test/integration/harnesses/rdpharnessb.svg b/cmd/api/src/test/integration/harnesses/rdpharnessb.svg index e7c6fa01dc..380a2d47ec 100644 --- a/cmd/api/src/test/integration/harnesses/rdpharnessb.svg +++ b/cmd/api/src/test/integration/harnesses/rdpharnessb.svg @@ -15,4 +15,4 @@ limitations under the License. SPDX-License-Identifier: Apache-2.0 --> -LocalToComputerRemoteInteractiveLogonPrivilegeMemberOfLocalGroupMemberOfMemberOfMemberOfCanRDPComputerRDPLocalGroupDomainUsersUserAUserBUserC +LocalToComputerRemoteInteractiveLogonRightMemberOfLocalGroupMemberOfMemberOfMemberOfCanRDPComputerRDPLocalGroupDomainUsersUserAUserBUserC diff --git a/cmd/ui/src/ducks/explore/saga.ts b/cmd/ui/src/ducks/explore/saga.ts index 9b885d72c3..35387ffdf6 100644 --- a/cmd/ui/src/ducks/explore/saga.ts +++ b/cmd/ui/src/ducks/explore/saga.ts @@ -112,7 +112,7 @@ function* runSearchQuery(payload: SearchRequest): SagaIterator { function* runPathfindingQuery(payload: PathfindingRequest): SagaIterator { const standardExclusions = [ ActiveDirectoryRelationshipKind.LocalToComputer, - ActiveDirectoryRelationshipKind.RemoteInteractiveLogonPrivilege, + ActiveDirectoryRelationshipKind.RemoteInteractiveLogonRight, ActiveDirectoryRelationshipKind.MemberOfLocalGroup, ActiveDirectoryRelationshipKind.GetChanges, ActiveDirectoryRelationshipKind.GetChangesAll, diff --git a/packages/cue/bh/ad/ad.cue b/packages/cue/bh/ad/ad.cue index 4ba6091a29..2e6e70f7a8 100644 --- a/packages/cue/bh/ad/ad.cue +++ b/packages/cue/bh/ad/ad.cue @@ -1108,8 +1108,8 @@ AddKeyCredentialLink: types.#Kind & { schema: "active_directory" } -RemoteInteractiveLogonPrivilege: types.#Kind & { - symbol: "RemoteInteractiveLogonPrivilege" +RemoteInteractiveLogonRight: types.#Kind & { + symbol: "RemoteInteractiveLogonRight" schema: "active_directory" } @@ -1329,7 +1329,7 @@ RelationshipKinds: [ AddKeyCredentialLink, LocalToComputer, MemberOfLocalGroup, - RemoteInteractiveLogonPrivilege, + RemoteInteractiveLogonRight, SyncLAPSPassword, WriteAccountRestrictions, WriteGPLink, diff --git a/packages/go/analysis/ad/post.go b/packages/go/analysis/ad/post.go index 64edf74f27..e78c3b4076 100644 --- a/packages/go/analysis/ad/post.go +++ b/packages/go/analysis/ad/post.go @@ -446,21 +446,21 @@ func FetchLocalGroupMembership(tx graph.Transaction, computer graph.ID, groupSuf } } -func FetchRemoteInteractiveLogonPrivilegedEntities(tx graph.Transaction, computerId graph.ID) (graph.NodeSet, error) { +func FetchRemoteInteractiveLogonRightEntities(tx graph.Transaction, computerId graph.ID) (graph.NodeSet, error) { return ops.FetchStartNodes(tx.Relationships().Filterf(func() graph.Criteria { return query.And( - query.Kind(query.Relationship(), ad.RemoteInteractiveLogonPrivilege), + query.Kind(query.Relationship(), ad.RemoteInteractiveLogonRight), query.Equals(query.EndID(), computerId), ) })) } -func HasRemoteInteractiveLogonPrivilege(tx graph.Transaction, groupId, computerId graph.ID) bool { +func HasRemoteInteractiveLogonRight(tx graph.Transaction, groupId, computerId graph.ID) bool { if _, err := tx.Relationships().Filterf(func() graph.Criteria { return query.And( query.Equals(query.StartID(), groupId), query.Equals(query.EndID(), computerId), - query.Kind(query.Relationship(), ad.RemoteInteractiveLogonPrivilege), + query.Kind(query.Relationship(), ad.RemoteInteractiveLogonRight), ) }).First(); err != nil { return false @@ -550,7 +550,7 @@ func ComputerHasURACollection(tx graph.Transaction, computerID graph.ID) bool { func ProcessRDPWithUra(tx graph.Transaction, rdpLocalGroup *graph.Node, computer graph.ID, localGroupExpansions impact.PathAggregator) (cardinality.Duplex[uint32], error) { rdpLocalGroupMembers := localGroupExpansions.Cardinality(rdpLocalGroup.ID.Uint32()).(cardinality.Duplex[uint32]) // Shortcut opportunity: see if the RDP group has RIL privilege. If it does, get the first degree members and return those ids, since everything in RDP group has CanRDP privs. No reason to look any further - if HasRemoteInteractiveLogonPrivilege(tx, rdpLocalGroup.ID, computer) { + if HasRemoteInteractiveLogonRight(tx, rdpLocalGroup.ID, computer) { firstDegreeMembers := cardinality.NewBitmap32() return firstDegreeMembers, tx.Relationships().Filter( @@ -565,7 +565,7 @@ func ProcessRDPWithUra(tx graph.Transaction, rdpLocalGroup *graph.Node, computer } return cursor.Error() }) - } else if baseRilEntities, err := FetchRemoteInteractiveLogonPrivilegedEntities(tx, computer); err != nil { + } else if baseRilEntities, err := FetchRemoteInteractiveLogonRightEntities(tx, computer); err != nil { return nil, err } else { var ( diff --git a/packages/go/graphschema/ad/ad.go b/packages/go/graphschema/ad/ad.go index cef7bba525..ae56f9a542 100644 --- a/packages/go/graphschema/ad/ad.go +++ b/packages/go/graphschema/ad/ad.go @@ -21,96 +21,95 @@ package ad import ( "errors" - graph "github.com/specterops/bloodhound/dawgs/graph" ) var ( - Entity = graph.StringKind("Base") - User = graph.StringKind("User") - Computer = graph.StringKind("Computer") - Group = graph.StringKind("Group") - GPO = graph.StringKind("GPO") - OU = graph.StringKind("OU") - Container = graph.StringKind("Container") - Domain = graph.StringKind("Domain") - LocalGroup = graph.StringKind("ADLocalGroup") - LocalUser = graph.StringKind("ADLocalUser") - AIACA = graph.StringKind("AIACA") - RootCA = graph.StringKind("RootCA") - EnterpriseCA = graph.StringKind("EnterpriseCA") - NTAuthStore = graph.StringKind("NTAuthStore") - CertTemplate = graph.StringKind("CertTemplate") - IssuancePolicy = graph.StringKind("IssuancePolicy") - Owns = graph.StringKind("Owns") - GenericAll = graph.StringKind("GenericAll") - GenericWrite = graph.StringKind("GenericWrite") - WriteOwner = graph.StringKind("WriteOwner") - WriteDACL = graph.StringKind("WriteDacl") - MemberOf = graph.StringKind("MemberOf") - ForceChangePassword = graph.StringKind("ForceChangePassword") - AllExtendedRights = graph.StringKind("AllExtendedRights") - AddMember = graph.StringKind("AddMember") - HasSession = graph.StringKind("HasSession") - Contains = graph.StringKind("Contains") - GPLink = graph.StringKind("GPLink") - AllowedToDelegate = graph.StringKind("AllowedToDelegate") - GetChanges = graph.StringKind("GetChanges") - GetChangesAll = graph.StringKind("GetChangesAll") - GetChangesInFilteredSet = graph.StringKind("GetChangesInFilteredSet") - TrustedBy = graph.StringKind("TrustedBy") - AllowedToAct = graph.StringKind("AllowedToAct") - AdminTo = graph.StringKind("AdminTo") - CanPSRemote = graph.StringKind("CanPSRemote") - CanRDP = graph.StringKind("CanRDP") - ExecuteDCOM = graph.StringKind("ExecuteDCOM") - HasSIDHistory = graph.StringKind("HasSIDHistory") - AddSelf = graph.StringKind("AddSelf") - DCSync = graph.StringKind("DCSync") - ReadLAPSPassword = graph.StringKind("ReadLAPSPassword") - ReadGMSAPassword = graph.StringKind("ReadGMSAPassword") - DumpSMSAPassword = graph.StringKind("DumpSMSAPassword") - SQLAdmin = graph.StringKind("SQLAdmin") - AddAllowedToAct = graph.StringKind("AddAllowedToAct") - WriteSPN = graph.StringKind("WriteSPN") - AddKeyCredentialLink = graph.StringKind("AddKeyCredentialLink") - LocalToComputer = graph.StringKind("LocalToComputer") - MemberOfLocalGroup = graph.StringKind("MemberOfLocalGroup") - RemoteInteractiveLogonPrivilege = graph.StringKind("RemoteInteractiveLogonPrivilege") - SyncLAPSPassword = graph.StringKind("SyncLAPSPassword") - WriteAccountRestrictions = graph.StringKind("WriteAccountRestrictions") - WriteGPLink = graph.StringKind("WriteGPLink") - RootCAFor = graph.StringKind("RootCAFor") - DCFor = graph.StringKind("DCFor") - PublishedTo = graph.StringKind("PublishedTo") - ManageCertificates = graph.StringKind("ManageCertificates") - ManageCA = graph.StringKind("ManageCA") - DelegatedEnrollmentAgent = graph.StringKind("DelegatedEnrollmentAgent") - Enroll = graph.StringKind("Enroll") - HostsCAService = graph.StringKind("HostsCAService") - WritePKIEnrollmentFlag = graph.StringKind("WritePKIEnrollmentFlag") - WritePKINameFlag = graph.StringKind("WritePKINameFlag") - NTAuthStoreFor = graph.StringKind("NTAuthStoreFor") - TrustedForNTAuth = graph.StringKind("TrustedForNTAuth") - EnterpriseCAFor = graph.StringKind("EnterpriseCAFor") - IssuedSignedBy = graph.StringKind("IssuedSignedBy") - GoldenCert = graph.StringKind("GoldenCert") - EnrollOnBehalfOf = graph.StringKind("EnrollOnBehalfOf") - OIDGroupLink = graph.StringKind("OIDGroupLink") - ExtendedByPolicy = graph.StringKind("ExtendedByPolicy") - ADCSESC1 = graph.StringKind("ADCSESC1") - ADCSESC3 = graph.StringKind("ADCSESC3") - ADCSESC4 = graph.StringKind("ADCSESC4") - ADCSESC5 = graph.StringKind("ADCSESC5") - ADCSESC6a = graph.StringKind("ADCSESC6a") - ADCSESC6b = graph.StringKind("ADCSESC6b") - ADCSESC7 = graph.StringKind("ADCSESC7") - ADCSESC9a = graph.StringKind("ADCSESC9a") - ADCSESC9b = graph.StringKind("ADCSESC9b") - ADCSESC10a = graph.StringKind("ADCSESC10a") - ADCSESC10b = graph.StringKind("ADCSESC10b") - ADCSESC13 = graph.StringKind("ADCSESC13") - SyncedToEntraUser = graph.StringKind("SyncedToEntraUser") + Entity = graph.StringKind("Base") + User = graph.StringKind("User") + Computer = graph.StringKind("Computer") + Group = graph.StringKind("Group") + GPO = graph.StringKind("GPO") + OU = graph.StringKind("OU") + Container = graph.StringKind("Container") + Domain = graph.StringKind("Domain") + LocalGroup = graph.StringKind("ADLocalGroup") + LocalUser = graph.StringKind("ADLocalUser") + AIACA = graph.StringKind("AIACA") + RootCA = graph.StringKind("RootCA") + EnterpriseCA = graph.StringKind("EnterpriseCA") + NTAuthStore = graph.StringKind("NTAuthStore") + CertTemplate = graph.StringKind("CertTemplate") + IssuancePolicy = graph.StringKind("IssuancePolicy") + Owns = graph.StringKind("Owns") + GenericAll = graph.StringKind("GenericAll") + GenericWrite = graph.StringKind("GenericWrite") + WriteOwner = graph.StringKind("WriteOwner") + WriteDACL = graph.StringKind("WriteDacl") + MemberOf = graph.StringKind("MemberOf") + ForceChangePassword = graph.StringKind("ForceChangePassword") + AllExtendedRights = graph.StringKind("AllExtendedRights") + AddMember = graph.StringKind("AddMember") + HasSession = graph.StringKind("HasSession") + Contains = graph.StringKind("Contains") + GPLink = graph.StringKind("GPLink") + AllowedToDelegate = graph.StringKind("AllowedToDelegate") + GetChanges = graph.StringKind("GetChanges") + GetChangesAll = graph.StringKind("GetChangesAll") + GetChangesInFilteredSet = graph.StringKind("GetChangesInFilteredSet") + TrustedBy = graph.StringKind("TrustedBy") + AllowedToAct = graph.StringKind("AllowedToAct") + AdminTo = graph.StringKind("AdminTo") + CanPSRemote = graph.StringKind("CanPSRemote") + CanRDP = graph.StringKind("CanRDP") + ExecuteDCOM = graph.StringKind("ExecuteDCOM") + HasSIDHistory = graph.StringKind("HasSIDHistory") + AddSelf = graph.StringKind("AddSelf") + DCSync = graph.StringKind("DCSync") + ReadLAPSPassword = graph.StringKind("ReadLAPSPassword") + ReadGMSAPassword = graph.StringKind("ReadGMSAPassword") + DumpSMSAPassword = graph.StringKind("DumpSMSAPassword") + SQLAdmin = graph.StringKind("SQLAdmin") + AddAllowedToAct = graph.StringKind("AddAllowedToAct") + WriteSPN = graph.StringKind("WriteSPN") + AddKeyCredentialLink = graph.StringKind("AddKeyCredentialLink") + LocalToComputer = graph.StringKind("LocalToComputer") + MemberOfLocalGroup = graph.StringKind("MemberOfLocalGroup") + RemoteInteractiveLogonRight = graph.StringKind("RemoteInteractiveLogonRight") + SyncLAPSPassword = graph.StringKind("SyncLAPSPassword") + WriteAccountRestrictions = graph.StringKind("WriteAccountRestrictions") + WriteGPLink = graph.StringKind("WriteGPLink") + RootCAFor = graph.StringKind("RootCAFor") + DCFor = graph.StringKind("DCFor") + PublishedTo = graph.StringKind("PublishedTo") + ManageCertificates = graph.StringKind("ManageCertificates") + ManageCA = graph.StringKind("ManageCA") + DelegatedEnrollmentAgent = graph.StringKind("DelegatedEnrollmentAgent") + Enroll = graph.StringKind("Enroll") + HostsCAService = graph.StringKind("HostsCAService") + WritePKIEnrollmentFlag = graph.StringKind("WritePKIEnrollmentFlag") + WritePKINameFlag = graph.StringKind("WritePKINameFlag") + NTAuthStoreFor = graph.StringKind("NTAuthStoreFor") + TrustedForNTAuth = graph.StringKind("TrustedForNTAuth") + EnterpriseCAFor = graph.StringKind("EnterpriseCAFor") + IssuedSignedBy = graph.StringKind("IssuedSignedBy") + GoldenCert = graph.StringKind("GoldenCert") + EnrollOnBehalfOf = graph.StringKind("EnrollOnBehalfOf") + OIDGroupLink = graph.StringKind("OIDGroupLink") + ExtendedByPolicy = graph.StringKind("ExtendedByPolicy") + ADCSESC1 = graph.StringKind("ADCSESC1") + ADCSESC3 = graph.StringKind("ADCSESC3") + ADCSESC4 = graph.StringKind("ADCSESC4") + ADCSESC5 = graph.StringKind("ADCSESC5") + ADCSESC6a = graph.StringKind("ADCSESC6a") + ADCSESC6b = graph.StringKind("ADCSESC6b") + ADCSESC7 = graph.StringKind("ADCSESC7") + ADCSESC9a = graph.StringKind("ADCSESC9a") + ADCSESC9b = graph.StringKind("ADCSESC9b") + ADCSESC10a = graph.StringKind("ADCSESC10a") + ADCSESC10b = graph.StringKind("ADCSESC10b") + ADCSESC13 = graph.StringKind("ADCSESC13") + SyncedToEntraUser = graph.StringKind("SyncedToEntraUser") ) type Property string @@ -858,7 +857,7 @@ func Nodes() []graph.Kind { return []graph.Kind{Entity, User, Computer, Group, GPO, OU, Container, Domain, LocalGroup, LocalUser, AIACA, RootCA, EnterpriseCA, NTAuthStore, CertTemplate, IssuancePolicy} } func Relationships() []graph.Kind { - return []graph.Kind{Owns, GenericAll, GenericWrite, WriteOwner, WriteDACL, MemberOf, ForceChangePassword, AllExtendedRights, AddMember, HasSession, Contains, GPLink, AllowedToDelegate, GetChanges, GetChangesAll, GetChangesInFilteredSet, TrustedBy, AllowedToAct, AdminTo, CanPSRemote, CanRDP, ExecuteDCOM, HasSIDHistory, AddSelf, DCSync, ReadLAPSPassword, ReadGMSAPassword, DumpSMSAPassword, SQLAdmin, AddAllowedToAct, WriteSPN, AddKeyCredentialLink, LocalToComputer, MemberOfLocalGroup, RemoteInteractiveLogonPrivilege, SyncLAPSPassword, WriteAccountRestrictions, WriteGPLink, RootCAFor, DCFor, PublishedTo, ManageCertificates, ManageCA, DelegatedEnrollmentAgent, Enroll, HostsCAService, WritePKIEnrollmentFlag, WritePKINameFlag, NTAuthStoreFor, TrustedForNTAuth, EnterpriseCAFor, IssuedSignedBy, GoldenCert, EnrollOnBehalfOf, OIDGroupLink, ExtendedByPolicy, ADCSESC1, ADCSESC3, ADCSESC4, ADCSESC5, ADCSESC6a, ADCSESC6b, ADCSESC7, ADCSESC9a, ADCSESC9b, ADCSESC10a, ADCSESC10b, ADCSESC13, SyncedToEntraUser} + return []graph.Kind{Owns, GenericAll, GenericWrite, WriteOwner, WriteDACL, MemberOf, ForceChangePassword, AllExtendedRights, AddMember, HasSession, Contains, GPLink, AllowedToDelegate, GetChanges, GetChangesAll, GetChangesInFilteredSet, TrustedBy, AllowedToAct, AdminTo, CanPSRemote, CanRDP, ExecuteDCOM, HasSIDHistory, AddSelf, DCSync, ReadLAPSPassword, ReadGMSAPassword, DumpSMSAPassword, SQLAdmin, AddAllowedToAct, WriteSPN, AddKeyCredentialLink, LocalToComputer, MemberOfLocalGroup, RemoteInteractiveLogonRight, SyncLAPSPassword, WriteAccountRestrictions, WriteGPLink, RootCAFor, DCFor, PublishedTo, ManageCertificates, ManageCA, DelegatedEnrollmentAgent, Enroll, HostsCAService, WritePKIEnrollmentFlag, WritePKINameFlag, NTAuthStoreFor, TrustedForNTAuth, EnterpriseCAFor, IssuedSignedBy, GoldenCert, EnrollOnBehalfOf, OIDGroupLink, ExtendedByPolicy, ADCSESC1, ADCSESC3, ADCSESC4, ADCSESC5, ADCSESC6a, ADCSESC6b, ADCSESC7, ADCSESC9a, ADCSESC9b, ADCSESC10a, ADCSESC10b, ADCSESC13, SyncedToEntraUser} } func ACLRelationships() []graph.Kind { return []graph.Kind{AllExtendedRights, ForceChangePassword, AddMember, AddAllowedToAct, GenericAll, WriteDACL, WriteOwner, GenericWrite, ReadLAPSPassword, ReadGMSAPassword, Owns, AddSelf, WriteSPN, AddKeyCredentialLink, GetChanges, GetChangesAll, GetChangesInFilteredSet, WriteAccountRestrictions, WriteGPLink, SyncLAPSPassword, DCSync, ManageCertificates, ManageCA, Enroll, WritePKIEnrollmentFlag, WritePKINameFlag} diff --git a/packages/go/graphschema/azure/azure.go b/packages/go/graphschema/azure/azure.go index 787ee392e6..00b20f190f 100644 --- a/packages/go/graphschema/azure/azure.go +++ b/packages/go/graphschema/azure/azure.go @@ -21,7 +21,6 @@ package azure import ( "errors" - graph "github.com/specterops/bloodhound/dawgs/graph" ) diff --git a/packages/go/graphschema/common/common.go b/packages/go/graphschema/common/common.go index 9320bb8d29..6fd161585e 100644 --- a/packages/go/graphschema/common/common.go +++ b/packages/go/graphschema/common/common.go @@ -21,7 +21,6 @@ package common import ( "errors" - graph "github.com/specterops/bloodhound/dawgs/graph" ) diff --git a/packages/javascript/bh-shared-ui/src/graphSchema.ts b/packages/javascript/bh-shared-ui/src/graphSchema.ts index ec571e5225..b7e491cac7 100644 --- a/packages/javascript/bh-shared-ui/src/graphSchema.ts +++ b/packages/javascript/bh-shared-ui/src/graphSchema.ts @@ -105,7 +105,7 @@ export enum ActiveDirectoryRelationshipKind { AddKeyCredentialLink = 'AddKeyCredentialLink', LocalToComputer = 'LocalToComputer', MemberOfLocalGroup = 'MemberOfLocalGroup', - RemoteInteractiveLogonPrivilege = 'RemoteInteractiveLogonPrivilege', + RemoteInteractiveLogonRight = 'RemoteInteractiveLogonRight', SyncLAPSPassword = 'SyncLAPSPassword', WriteAccountRestrictions = 'WriteAccountRestrictions', WriteGPLink = 'WriteGPLink', @@ -211,8 +211,8 @@ export function ActiveDirectoryRelationshipKindToDisplay(value: ActiveDirectoryR return 'LocalToComputer'; case ActiveDirectoryRelationshipKind.MemberOfLocalGroup: return 'MemberOfLocalGroup'; - case ActiveDirectoryRelationshipKind.RemoteInteractiveLogonPrivilege: - return 'RemoteInteractiveLogonPrivilege'; + case ActiveDirectoryRelationshipKind.RemoteInteractiveLogonRight: + return 'RemoteInteractiveLogonRight'; case ActiveDirectoryRelationshipKind.SyncLAPSPassword: return 'SyncLAPSPassword'; case ActiveDirectoryRelationshipKind.WriteAccountRestrictions: From fd7992e7c2dc381f0884faddcf5cfbcb8554fbd0 Mon Sep 17 00:00:00 2001 From: Wes Date: Tue, 22 Oct 2024 16:33:36 -0400 Subject: [PATCH 2/2] BED-4428: Add Neo4j migration to rename edges --- cmd/api/src/migrations/manifest.go | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/cmd/api/src/migrations/manifest.go b/cmd/api/src/migrations/manifest.go index b2d5f3317a..4a8218cebb 100644 --- a/cmd/api/src/migrations/manifest.go +++ b/cmd/api/src/migrations/manifest.go @@ -47,6 +47,40 @@ func RequiresMigration(ctx context.Context, db graph.Database) (bool, error) { } } +// Version_620_Migration is intended to rename the RemoteInteractiveLogonPrivilege edge to RemoteInteractiveLogonRight +// See: https://specterops.atlassian.net/browse/BED-4428 +func Version_620_Migration(db graph.Database) error { + defer log.LogAndMeasure(log.LevelInfo, "Migration to rename RemoteInteractiveLogonPrivilege edges")() + + // MATCH p=(n:Base)-[:RemoteInteractiveLogonPrivilege]->(m:Base) RETURN p + targetCriteria := query.And( + query.Kind(query.Start(), ad.Entity), + query.Kind(query.Relationship(), graph.StringKind("RemoteInteractiveLogonPrivilege")), + query.Kind(query.End(), ad.Entity), + ) + + edgeProperties := graph.NewProperties() + edgeProperties.Set(common.LastSeen.String(), time.Now().UTC()) + + //Get all RemoteInteractiveLogonPrivilege edges, use the start/end ids to insert new edges, and delete the old ones + return db.BatchOperation(context.Background(), func(batch graph.Batch) error { + rels, err := ops.FetchRelationships(batch.Relationships().Filter(targetCriteria)) + if err != nil { + return err + } + + for _, rel := range rels { + if err := batch.CreateRelationshipByIDs(rel.StartID, rel.EndID, ad.RemoteInteractiveLogonRight, edgeProperties); err != nil { + return err + } else if err := batch.DeleteRelationship(rel.ID); err != nil { + return err + } + } + + return nil + }) +} + // Version_513_Migration covers a bug discovered in ingest that would result in nodes containing more than one valid // kind. For example, the following query should return no results: (n:Base) where (n:User and n:Computer) return n // but, at time of writing, due to the ingest defect several environments will return results for this query. @@ -285,6 +319,10 @@ var Manifest = []Migration{ Version: version.Version{Major: 5, Minor: 13, Patch: 0}, Execute: Version_513_Migration, }, + { + Version: version.Version{Major: 6, Minor: 2, Patch: 0}, + Execute: Version_620_Migration, + }, } func LatestGraphMigrationVersion() version.Version {