Skip to content

Commit

Permalink
Merge branch 'main' of github.com:SpecterOps/BloodHound into BED-5133
Browse files Browse the repository at this point in the history
  • Loading branch information
benwaples committed Jan 14, 2025
2 parents 05e779c + 70a8c2d commit c306f25
Show file tree
Hide file tree
Showing 23 changed files with 224 additions and 58 deletions.
3 changes: 0 additions & 3 deletions .github/config/integration.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
"database": {
"connection": "user=bloodhound password=bloodhoundcommunityedition dbname=bloodhound host=localhost port=65432"
},
"neo4j": {
"connection": "neo4j://neo4j:bloodhoundcommunityedition@localhost:37687/"
},
"default_admin": {
"principal_name": "admin",
"password": "admin",
Expand Down
4 changes: 2 additions & 2 deletions cmd/api/src/api/tools/pg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
//
// SPDX-License-Identifier: Apache-2.0

//go:build integration
// +build integration
//go:build disabled
// +build disabled

package tools_test

Expand Down
4 changes: 2 additions & 2 deletions cmd/api/src/config/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ package config

import (
"fmt"
"github.com/specterops/bloodhound/dawgs/drivers/pg"

"github.com/specterops/bloodhound/dawgs/drivers/neo4j"
"github.com/specterops/bloodhound/src/serde"
)

Expand Down Expand Up @@ -58,7 +58,7 @@ func NewDefaultConfiguration() (Configuration, error) {
EnableTextLogger: false, // Default to JSON logging
TLS: TLSConfiguration{},
SAML: SAMLConfiguration{},
GraphDriver: neo4j.DriverName, // Default to Neo4j as the graph driver
GraphDriver: pg.DriverName, // Default to PG as the graph driver
Database: DatabaseConfiguration{
MaxConcurrentSessions: 10,
},
Expand Down
4 changes: 2 additions & 2 deletions cmd/api/src/migrations/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (

type Migration struct {
Version version.Version
Execute func(db graph.Database) error
Execute func(ctx context.Context, db graph.Database) error
}

func UpdateMigrationData(ctx context.Context, db graph.Database, target version.Version) error {
Expand Down Expand Up @@ -146,7 +146,7 @@ func (s *GraphMigrator) executeMigrations(ctx context.Context, originalVersion v
if nextMigration.Version.GreaterThan(mostRecentVersion) {
slog.InfoContext(ctx, fmt.Sprintf("Graph migration version %s is greater than current version %s", nextMigration.Version, mostRecentVersion))

if err := nextMigration.Execute(s.db); err != nil {
if err := nextMigration.Execute(ctx, s.db); err != nil {
return fmt.Errorf("migration version %s failed: %w", nextMigration.Version.String(), err)
}

Expand Down
40 changes: 26 additions & 14 deletions cmd/api/src/migrations/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ 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 {
func Version_620_Migration(ctx context.Context, db graph.Database) error {
defer measure.LogAndMeasure(slog.LevelInfo, "Migration to rename RemoteInteractiveLogonPrivilege edges")()

// MATCH p=(n:Base)-[:RemoteInteractiveLogonPrivilege]->(m:Base) RETURN p
Expand All @@ -63,7 +63,7 @@ func Version_620_Migration(db graph.Database) error {
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 {
return db.BatchOperation(ctx, func(batch graph.Batch) error {
rels, err := ops.FetchRelationships(batch.Relationships().Filter(targetCriteria))
if err != nil {
return err
Expand All @@ -90,7 +90,7 @@ func Version_620_Migration(db graph.Database) error {
//
// node.Kinds = Kinds{ad.Entity, ad.User, ad.Computer} must be reset to:
// node.Kinds = Kinds{ad.Entity}
func Version_513_Migration(db graph.Database) error {
func Version_513_Migration(ctx context.Context, db graph.Database) error {
defer measure.LogAndMeasure(slog.LevelInfo, "Migration to remove incorrectly ingested labels")()

// Cypher for the below filter is: size(labels(n)) > 2 and not (n:Group and n:ADLocalGroup) or size(labels(n)) > 3 and (n:Group and n:ADLocalGroup)
Expand All @@ -105,9 +105,9 @@ func Version_513_Migration(db graph.Database) error {
),
)

if nodes, err := ops.ParallelFetchNodes(context.Background(), db, targetCriteria, analysis.MaximumDatabaseParallelWorkers); err != nil {
if nodes, err := ops.ParallelFetchNodes(ctx, db, targetCriteria, analysis.MaximumDatabaseParallelWorkers); err != nil {
return err
} else if err := db.BatchOperation(context.Background(), func(batch graph.Batch) error {
} else if err := db.BatchOperation(ctx, func(batch graph.Batch) error {
for _, node := range nodes {
if node.Kinds.ContainsOneOf(ad.Entity) {
// Nodes are designed to track additions and deletions. By making this assignment, the update logic
Expand Down Expand Up @@ -147,10 +147,10 @@ func Version_513_Migration(db graph.Database) error {
return nil
}

func Version_508_Migration(db graph.Database) error {
func Version_508_Migration(ctx context.Context, db graph.Database) error {
defer measure.Measure(slog.LevelInfo, "Migrating Azure Owns to Owner")()

return db.BatchOperation(context.Background(), func(batch graph.Batch) error {
return db.BatchOperation(ctx, func(batch graph.Batch) error {
return batch.Relationships().Filterf(func() graph.Criteria {
return query.And(
query.Kind(query.Start(), azure.Entity),
Expand Down Expand Up @@ -180,10 +180,10 @@ func Version_508_Migration(db graph.Database) error {
})
}

func Version_277_Migration(db graph.Database) error {
func Version_277_Migration(ctx context.Context, db graph.Database) error {
defer measure.Measure(slog.LevelInfo, "Migrating node property casing")()

return db.BatchOperation(context.Background(), func(batch graph.Batch) error {
return db.BatchOperation(ctx, func(batch graph.Batch) error {
if err := batch.Nodes().Filterf(func() graph.Criteria {
return query.KindIn(query.Node(), ad.Entity, azure.Entity)
}).Fetch(func(cursor graph.Cursor[*graph.Node]) error {
Expand Down Expand Up @@ -256,10 +256,10 @@ func Version_277_Migration(db graph.Database) error {
var Manifest = []Migration{
{
Version: version.Version{Major: 2, Minor: 3, Patch: 0},
Execute: func(db graph.Database) error {
Execute: func(ctx context.Context, db graph.Database) error {
defer measure.Measure(slog.LevelInfo, "Deleting all existing role nodes")()

return db.WriteTransaction(context.Background(), func(tx graph.Transaction) error {
return db.WriteTransaction(ctx, func(tx graph.Transaction) error {
return tx.Nodes().Filterf(func() graph.Criteria {
return query.Kind(query.Node(), azure.Role)
}).Delete()
Expand All @@ -268,10 +268,22 @@ var Manifest = []Migration{
},
{
Version: version.Version{Major: 2, Minor: 6, Patch: 3},
Execute: func(db graph.Database) error {
Execute: func(ctx context.Context, db graph.Database) error {
defer measure.Measure(slog.LevelInfo, "Deleting all LocalToComputer/RemoteInteractiveLogin edges and ADLocalGroup labels")()

return db.WriteTransaction(context.Background(), func(tx graph.Transaction) error {
// This kind has long since gone missing from our schemas but the assert below reintroduces it for the
// purposes of running this migration
rilpKind := graph.StringKind("RemoteInteractiveLogonPrivilege")

if err := db.AssertSchema(ctx, graph.Schema{
Graphs: []graph.Graph{{
Edges: graph.Kinds{rilpKind},
}},
}); err != nil {
return err
}

return db.WriteTransaction(ctx, func(tx graph.Transaction) error {
//Remove ADLocalGroup label from all nodes that also have the group label
if nodes, err := ops.FetchNodes(tx.Nodes().Filterf(func() graph.Criteria {
return query.And(
Expand All @@ -293,7 +305,7 @@ var Manifest = []Migration{
if err := tx.Relationships().Filterf(func() graph.Criteria {
return query.And(
query.Or(
query.Kind(query.Relationship(), graph.StringKind("RemoteInteractiveLogonPrivilege")),
query.Kind(query.Relationship(), rilpKind),
query.Kind(query.Relationship(), ad.LocalToComputer),
query.Kind(query.Relationship(), ad.MemberOfLocalGroup),
),
Expand Down
3 changes: 0 additions & 3 deletions cmd/api/src/test/integration/utils/integration-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
"database": {
"connection": "user=bhe dbname=bhe host=/run/postgresql"
},
"neo4j": {
"connection": "neo4j://neo4j:supersecretpassword@localhost:7687/"
},
"collectors_base_path": "work/collectors",
"crypto": {
"jwt": {
Expand Down
2 changes: 1 addition & 1 deletion go.work
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
//
// SPDX-License-Identifier: Apache-2.0

go 1.23
go 1.23.0

use (
./cmd/api/src
Expand Down
3 changes: 0 additions & 3 deletions local-harnesses/integration.config.json.template
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
"database": {
"connection": "user=bloodhound password=bloodhoundcommunityedition dbname=bloodhound host=localhost port=65432"
},
"neo4j": {
"connection": "neo4j://neo4j:bloodhoundcommunityedition@localhost:37687/"
},
"default_admin": {
"principal_name": "admin",
"password": "admin",
Expand Down
23 changes: 17 additions & 6 deletions packages/cue/bh/ad/ad.cue
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@

package ad

import "pkg.specterops.io/schemas/bh/types:types"
import (
"list"
"pkg.specterops.io/schemas/bh/types:types"
)

// Exported requirements
Properties: [...types.#StringEnum]
NodeKinds: [...types.#Kind]
RelationshipKinds: [...types.#Kind]
ACLRelationships: [...types.#Kind]
PathfindingRelationships: [...types.#Kind]
InboundRelationshipKinds: [...types.#Kind]
OutboundRelationshipKinds: [...types.#Kind]
EdgeCompositionRelationships: [...types.#Kind]

// Property name enumerations
Expand Down Expand Up @@ -1412,8 +1417,8 @@ ACLRelationships: [
WritePKINameFlag,
]

// Edges that are used in pathfinding
PathfindingRelationships: [
// these edges are common to inbound/outbound/pathfinding
SharedRelationshipKinds: [
Owns,
GenericAll,
GenericWrite,
Expand All @@ -1424,11 +1429,9 @@ PathfindingRelationships: [
AllExtendedRights,
AddMember,
HasSession,
Contains,
GPLink,
AllowedToDelegate,
CoerceToTGT,
TrustedBy,
AllowedToAct,
AdminTo,
CanPSRemote,
Expand Down Expand Up @@ -1458,11 +1461,19 @@ PathfindingRelationships: [
ADCSESC10a,
ADCSESC10b,
ADCSESC13,
DCFor,
SyncedToEntraUser,
CoerceAndRelayNTLMToSMB,
]

// Edges that are used during inbound traversal
InboundRelationshipKinds: list.Concat([SharedRelationshipKinds,[Contains]])

// Edges that are used during outbound traversal
OutboundRelationshipKinds: list.Concat([SharedRelationshipKinds,[Contains, DCFor]])

// Edges that are used in pathfinding
PathfindingRelationships: list.Concat([SharedRelationshipKinds,[Contains, DCFor, TrustedBy]])

EdgeCompositionRelationships: [
GoldenCert,
ADCSESC1,
Expand Down
12 changes: 9 additions & 3 deletions packages/cue/bh/azure/azure.cue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

package azure

import "pkg.specterops.io/schemas/bh/types:types"
import (
"list"
"pkg.specterops.io/schemas/bh/types:types"
)

// Exported requirements
Properties: [...types.#StringEnum]
Expand All @@ -27,6 +30,7 @@ AbusableAppRoleRelationshipKinds: [... types.#Kind]
ControlRelationshipKinds: [...types.#Kind]
ExecutionPrivilegeKinds: [...types.#Kind]
PathfindingRelationships: [...types.#Kind]
InboundOutboundRelationshipKinds: [...types.#Kind]

// Property name enumerations
AppOwnerOrganizationID: types.#StringEnum & {
Expand Down Expand Up @@ -831,9 +835,9 @@ ExecutionPrivilegeKinds: [
ExecuteCommand,
]

PathfindingRelationships: [
// Edges that are used during inbound and outbound traversals
InboundOutboundRelationshipKinds: [
AvereContributor,
Contains,
Contributor,
GetCertificates,
GetKeys,
Expand Down Expand Up @@ -872,3 +876,5 @@ PathfindingRelationships: [
AZMGGrantRole,
SyncedToADUser,
]

PathfindingRelationships: list.Concat([InboundOutboundRelationshipKinds, [Contains]])
11 changes: 10 additions & 1 deletion packages/cue/bh/bh.cue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import (
Properties: [...types.#StringEnum]
NodeKinds: [...types.#Kind]
RelationshipKinds: [...types.#Kind]
InboundRelationshipKinds: [...types.#Kind]
OutboundRelationshipKinds: [...types.#Kind]
}

#Azure: {
Expand All @@ -39,6 +41,7 @@ import (
ControlRelationshipKinds: [...types.#Kind]
ExecutionPrivilegeKinds: [...types.#Kind]
PathfindingRelationships: [...types.#Kind]
InboundOutboundRelationshipKinds: [...types.#Kind]
}

#ActiveDirectory: {
Expand All @@ -47,6 +50,8 @@ import (
RelationshipKinds: [...types.#Kind]
ACLRelationships: [...types.#Kind]
PathfindingRelationships: [...types.#Kind]
InboundRelationshipKinds: [...types.#Kind]
OutboundRelationshipKinds: [...types.#Kind]
EdgeCompositionRelationships: [...types.#Kind]
}

Expand All @@ -55,6 +60,8 @@ Common: #Common & {
Properties: common.Properties
NodeKinds: common.NodeKinds
RelationshipKinds: common.RelationshipKinds
InboundRelationshipKinds: common.InboundRelationshipKinds
OutboundRelationshipKinds: common.OutboundRelationshipKinds
}

Azure: #Azure & {
Expand All @@ -66,6 +73,7 @@ Azure: #Azure & {
ControlRelationshipKinds: azure.ControlRelationshipKinds
ExecutionPrivilegeKinds: azure.ExecutionPrivilegeKinds
PathfindingRelationships: azure.PathfindingRelationships
InboundOutboundRelationshipKinds: azure.InboundOutboundRelationshipKinds
}

ActiveDirectory: #ActiveDirectory & {
Expand All @@ -74,6 +82,7 @@ ActiveDirectory: #ActiveDirectory & {
RelationshipKinds: ad.RelationshipKinds
ACLRelationships: ad.ACLRelationships
PathfindingRelationships: ad.PathfindingRelationships
InboundRelationshipKinds: ad.InboundRelationshipKinds
OutboundRelationshipKinds: ad.OutboundRelationshipKinds
EdgeCompositionRelationships: ad.EdgeCompositionRelationships

}
12 changes: 11 additions & 1 deletion packages/cue/bh/common/common.cue
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,19 @@

package common

import "pkg.specterops.io/schemas/bh/types:types"
import (
"pkg.specterops.io/schemas/bh/types:types"
"pkg.specterops.io/schemas/bh/ad:ad"
"pkg.specterops.io/schemas/bh/azure:azure"
"list"
)

// Exported requirements
Properties: [...types.#StringEnum]
NodeKinds: [...types.#Kind]
RelationshipKinds: [...types.#Kind]
InboundRelationshipKinds: [...types.#Kind]
OutboundRelationshipKinds: [...types.#Kind]

// Property name enumerations
ObjectID: types.#StringEnum & {
Expand Down Expand Up @@ -168,3 +175,6 @@ NodeKinds: [

RelationshipKinds: [
]

InboundRelationshipKinds: list.Concat([ad.InboundRelationshipKinds, azure.InboundOutboundRelationshipKinds])
OutboundRelationshipKinds: list.Concat([ad.OutboundRelationshipKinds, azure.InboundOutboundRelationshipKinds])
Loading

0 comments on commit c306f25

Please sign in to comment.