Skip to content

Commit

Permalink
Merge branch 'main' into adcs-cypher-queries
Browse files Browse the repository at this point in the history
  • Loading branch information
JonasBK authored Jan 30, 2024
2 parents 6ee47c3 + 712e035 commit d1c804a
Show file tree
Hide file tree
Showing 25 changed files with 868 additions and 160 deletions.
27 changes: 27 additions & 0 deletions cmd/api/src/analysis/ad/adcs_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,33 @@ func TestADCSESC9a(t *testing.T) {
}
return nil
})

db.ReadTransaction(context.Background(), func(tx graph.Transaction) error {
if results, err := ops.FetchRelationships(tx.Relationships().Filterf(func() graph.Criteria {
return query.Kind(query.Relationship(), ad.ADCSESC9a)
})); err != nil {
t.Fatalf("error fetching esc9a edges in integration test; %v", err)
} else {
assert.Equal(t, 1, len(results))
edge := results[0]

if edgeComp, err := ad2.GetEdgeCompositionPath(context.Background(), db, edge); err != nil {
t.Fatalf("error getting edge composition for esc9: %v", err)
} else {
nodes := edgeComp.AllNodes().Slice()
assert.Contains(t, nodes, harness.ESC9AHarness.Attacker)
assert.Contains(t, nodes, harness.ESC9AHarness.Victim)
assert.Contains(t, nodes, harness.ESC9AHarness.Domain)
assert.Contains(t, nodes, harness.ESC9AHarness.NTAuthStore)
assert.Contains(t, nodes, harness.ESC9AHarness.RootCA)
assert.Contains(t, nodes, harness.ESC9AHarness.DC)
assert.Contains(t, nodes, harness.ESC9AHarness.EnterpriseCA)
assert.Contains(t, nodes, harness.ESC9AHarness.CertTemplate)
}
}

return nil
})
})

}
Expand Down
16 changes: 10 additions & 6 deletions cmd/api/src/analysis/azure/queries.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// Copyright 2023 Specter Ops, Inc.
//
//
// Licensed under the Apache License, Version 2.0
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
// SPDX-License-Identifier: Apache-2.0

package azure
Expand All @@ -21,7 +21,6 @@ import (
"fmt"
"sync"

"github.com/specterops/bloodhound/src/model"
"github.com/gofrs/uuid"
"github.com/specterops/bloodhound/analysis"
"github.com/specterops/bloodhound/dawgs/graph"
Expand All @@ -30,6 +29,7 @@ import (
"github.com/specterops/bloodhound/graphschema/azure"
"github.com/specterops/bloodhound/graphschema/common"
"github.com/specterops/bloodhound/log"
"github.com/specterops/bloodhound/src/model"
)

func GraphStats(ctx context.Context, db graph.Database) (model.AzureDataQualityStats, model.AzureDataQualityAggregation, error) {
Expand All @@ -48,7 +48,7 @@ func GraphStats(ctx context.Context, db graph.Database) (model.AzureDataQualityS
runID = newUUID.String()
}

return stats, aggregation, db.ReadTransaction(ctx, func(tx graph.Transaction) error {
err := db.ReadTransaction(ctx, func(tx graph.Transaction) error {
if tenants, err := ops.FetchNodes(tx.Nodes().Filterf(func() graph.Criteria {
return query.Kind(query.Node(), azure.Tenant)
})); err != nil {
Expand All @@ -58,6 +58,8 @@ func GraphStats(ctx context.Context, db graph.Database) (model.AzureDataQualityS
if tenantObjectID, err := tenant.Properties.Get(common.ObjectID.String()).String(); err != nil {
log.Errorf("Tenant node %d does not have a valid %s property: %v", tenant.ID, common.ObjectID, err)
} else {
aggregation.Tenants++

var (
stat = model.AzureDataQualityStat{
RunID: runID,
Expand Down Expand Up @@ -163,4 +165,6 @@ func GraphStats(ctx context.Context, db graph.Database) (model.AzureDataQualityS

return nil
})

return stats, aggregation, err
}
52 changes: 52 additions & 0 deletions cmd/api/src/analysis/azure/queries_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2023 Specter Ops, Inc.
//
// Licensed under the Apache License, Version 2.0
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

//go:build integration
// +build integration

package azure_test

import (
"context"
"github.com/specterops/bloodhound/dawgs/graph"
schema "github.com/specterops/bloodhound/graphschema"
azure2 "github.com/specterops/bloodhound/src/analysis/azure"
"github.com/specterops/bloodhound/src/test/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
)

func TestAnalysisAzure_GraphStats(t *testing.T) {
testCtx := integration.NewGraphTestContext(t, schema.DefaultGraphSchema())
testCtx.DatabaseTest(func(harness integration.HarnessDetails, db graph.Database) {

_, agg, err := azure2.GraphStats(context.TODO(), testCtx.Graph.Database)
require.Nil(t, err)
assert.NotZero(t, agg.Tenants)
assert.NotZero(t, agg.Users)
assert.NotZero(t, agg.Groups)
assert.NotZero(t, agg.Apps)
assert.NotZero(t, agg.ServicePrincipals)
assert.NotZero(t, agg.Devices)
assert.NotZero(t, agg.ManagementGroups)
assert.NotZero(t, agg.Subscriptions)
assert.NotZero(t, agg.ResourceGroups)
assert.NotZero(t, agg.VMs)
assert.NotZero(t, agg.KeyVaults)
assert.NotZero(t, agg.Relationships)
})
}
1 change: 1 addition & 0 deletions cmd/api/src/test/integration/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ func (s *GraphTestContext) setupAzure() {
s.Harness.AZMGRoleManagementReadWriteDirectoryHarness.Setup(s)
s.Harness.AZMGServicePrincipalEndpointReadWriteAllHarness.Setup(s)
s.Harness.AZInboundControlHarness.Setup(s)
s.Harness.AZManagementGroup.Setup(s)
}

func (s *GraphTestContext) setupActiveDirectory() {
Expand Down
30 changes: 30 additions & 0 deletions cmd/api/src/test/integration/harnesses.go
Original file line number Diff line number Diff line change
Expand Up @@ -753,16 +753,41 @@ type AZGroupMembershipHarness struct {

func (s *AZGroupMembershipHarness) Setup(testCtx *GraphTestContext) {
tenantID := RandomObjectID(testCtx.testCtx)
s.Tenant = testCtx.NewAzureTenant(tenantID)
s.UserA = testCtx.NewAzureUser("UserA", "UserA", "", RandomObjectID(testCtx.testCtx), "", tenantID, false)
s.UserB = testCtx.NewAzureUser("UserB", "UserB", "", RandomObjectID(testCtx.testCtx), "", tenantID, false)
s.UserC = testCtx.NewAzureUser("UserC", "UserC", "", RandomObjectID(testCtx.testCtx), "", tenantID, false)
s.Group = testCtx.NewAzureGroup("Group", RandomObjectID(testCtx.testCtx), tenantID)

testCtx.NewRelationship(s.Tenant, s.Group, azure.Contains)

testCtx.NewRelationship(s.UserA, s.Group, azure.MemberOf)
testCtx.NewRelationship(s.UserB, s.Group, azure.MemberOf)
testCtx.NewRelationship(s.UserC, s.Group, azure.MemberOf)
}

type AZManagementGroupHarness struct {
Tenant *graph.Node
UserA *graph.Node
UserB *graph.Node
UserC *graph.Node
Group *graph.Node
}

func (s *AZManagementGroupHarness) Setup(testCtx *GraphTestContext) {
tenantID := RandomObjectID(testCtx.testCtx)
s.Tenant = testCtx.NewAzureTenant(tenantID)
s.UserA = testCtx.NewAzureUser("Batman", "Batman", "", RandomObjectID(testCtx.testCtx), "", tenantID, false)
s.UserB = testCtx.NewAzureUser("Wonder Woman", "Wonder Woman", "", RandomObjectID(testCtx.testCtx), "", tenantID, false)
s.UserC = testCtx.NewAzureUser("Flash", "Flash", "", RandomObjectID(testCtx.testCtx), "", tenantID, false)
s.Group = testCtx.NewAzureManagementGroup("Justice League", RandomObjectID(testCtx.testCtx), tenantID)
testCtx.NewRelationship(s.Tenant, s.Group, azure.Contains)

testCtx.NewRelationship(s.UserA, s.Group, azure.ManagementGroup)
testCtx.NewRelationship(s.UserB, s.Group, azure.ManagementGroup)
testCtx.NewRelationship(s.UserC, s.Group, azure.ManagementGroup)
}

type AZEntityPanelHarness struct {
Application *graph.Node
Device *graph.Node
Expand Down Expand Up @@ -1030,6 +1055,7 @@ func (s *AZMGServicePrincipalEndpointReadWriteAllHarness) Setup(testCtx *GraphTe
}

type AZInboundControlHarness struct {
AZTenant *graph.Node
ControlledAZUser *graph.Node
AZAppA *graph.Node
AZGroupA *graph.Node
Expand All @@ -1042,6 +1068,7 @@ type AZInboundControlHarness struct {

func (s *AZInboundControlHarness) Setup(testCtx *GraphTestContext) {
tenantID := RandomObjectID(testCtx.testCtx)
s.AZTenant = testCtx.NewAzureTenant(tenantID)
s.ControlledAZUser = testCtx.NewAzureUser("Controlled AZUser", "Controlled AZUser", "", RandomObjectID(testCtx.testCtx), HarnessUserLicenses, tenantID, HarnessUserMFAEnabled)
s.AZAppA = testCtx.NewAzureApplication("AZAppA", RandomObjectID(testCtx.testCtx), tenantID)
s.AZGroupA = testCtx.NewAzureGroup("AZGroupA", RandomObjectID(testCtx.testCtx), tenantID)
Expand All @@ -1051,6 +1078,8 @@ func (s *AZInboundControlHarness) Setup(testCtx *GraphTestContext) {
s.AZServicePrincipalA = testCtx.NewAzureServicePrincipal("AZServicePrincipalA", RandomObjectID(testCtx.testCtx), tenantID)
s.AZServicePrincipalB = testCtx.NewAzureServicePrincipal("AZServicePrincipalB", RandomObjectID(testCtx.testCtx), tenantID)

testCtx.NewRelationship(s.AZTenant, s.AZGroupA, azure.Contains)

testCtx.NewRelationship(s.AZUserA, s.AZGroupA, azure.MemberOf)
testCtx.NewRelationship(s.AZServicePrincipalB, s.AZGroupB, azure.MemberOf)

Expand Down Expand Up @@ -2198,6 +2227,7 @@ type HarnessDetails struct {
Completeness CompletenessHarness
AZBaseHarness AZBaseHarness
AZGroupMembership AZGroupMembershipHarness
AZManagementGroup AZManagementGroupHarness
AZEntityPanelHarness AZEntityPanelHarness
AZMGApplicationReadWriteAllHarness AZMGApplicationReadWriteAllHarness
AZMGAppRoleManagementReadWriteAllHarness AZMGAppRoleManagementReadWriteAllHarness
Expand Down
Loading

0 comments on commit d1c804a

Please sign in to comment.