Skip to content

Commit

Permalink
feat: post process AZAddSecret edges from roles instead of principals (
Browse files Browse the repository at this point in the history
  • Loading branch information
mistahj67 authored Apr 26, 2024
1 parent 726f653 commit 03010e4
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 76 deletions.
28 changes: 28 additions & 0 deletions cmd/api/src/analysis/azure/azure_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package azure_test
import (
"context"
schema "github.com/specterops/bloodhound/graphschema"
"slices"
"testing"

"github.com/specterops/bloodhound/graphschema/azure"
Expand Down Expand Up @@ -648,6 +649,33 @@ func TestRoleEntityDetails(t *testing.T) {
})
}

func TestRoleAddSecret(t *testing.T) {
testContext := integration.NewGraphTestContext(t, schema.DefaultGraphSchema())
testContext.ReadTransactionTestWithSetup(func(harness *integration.HarnessDetails) error {
harness.AZAddSecretHarness.Setup(testContext)
return nil
}, func(harness integration.HarnessDetails, tx graph.Transaction) {

postProcessingStats, err := azureanalysis.AppRoleAssignments(context.Background(), testContext.Graph.Database)
assert.Nil(t, err)
assert.NotNil(t, postProcessingStats.RelationshipsCreated[azure.AddSecret])
assert.Equal(t, 4, int(*postProcessingStats.RelationshipsCreated[azure.AddSecret]))

// Validate that the AZAddSecret edges were created
addSecretEdges, err := ops.FetchRelationships(tx.Relationships().Filterf(func() graph.Criteria {
return query.Kind(query.Relationship(), azure.AddSecret)
}))
assert.Nil(t, err)
assert.Len(t, addSecretEdges, 4)

for _, edge := range addSecretEdges {
assert.Equal(t, azure.AddSecret, edge.Kind)
assert.True(t, slices.Contains([]graph.ID{harness.AZAddSecretHarness.AppAdminRole.ID, harness.AZAddSecretHarness.CloudAppAdminRole.ID}, edge.StartID))
assert.True(t, slices.Contains([]graph.ID{harness.AZAddSecretHarness.AZApp.ID, harness.AZAddSecretHarness.AZServicePrincipal.ID}, edge.EndID))
}
})
}

func TestServicePrincipalEntityDetails(t *testing.T) {
testContext := integration.NewGraphTestContext(t, schema.DefaultGraphSchema())
testContext.ReadTransactionTestWithSetup(func(harness *integration.HarnessDetails) error {
Expand Down
3 changes: 0 additions & 3 deletions cmd/api/src/analysis/azure/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,13 @@ func Post(ctx context.Context, db graph.Database) (*analysis.AtomicPostProcessin
return &aggregateStats, err
} else if userRoleStats, err := azureAnalysis.UserRoleAssignments(ctx, db); err != nil {
return &aggregateStats, err
} else if addSecretStats, err := azureAnalysis.AddSecret(ctx, db); err != nil {
return &aggregateStats, err
} else if executeCommandStats, err := azureAnalysis.ExecuteCommand(ctx, db); err != nil {
return &aggregateStats, err
} else if appRoleAssignmentStats, err := azureAnalysis.AppRoleAssignments(ctx, db); err != nil {
return &aggregateStats, err
} else {
aggregateStats.Merge(stats)
aggregateStats.Merge(userRoleStats)
aggregateStats.Merge(addSecretStats)
aggregateStats.Merge(executeCommandStats)
aggregateStats.Merge(appRoleAssignmentStats)
return &aggregateStats, nil
Expand Down
1 change: 1 addition & 0 deletions cmd/api/src/test/integration/harnesses.go
Original file line number Diff line number Diff line change
Expand Up @@ -6862,6 +6862,7 @@ type HarnessDetails struct {
NumCollectedActiveDirectoryDomains int
AZInboundControlHarness AZInboundControlHarness
ExtendedByPolicyHarness ExtendedByPolicyHarness
AZAddSecretHarness AZAddSecretHarness
ESC3Harness1 ESC3Harness1
ESC3Harness2 ESC3Harness2
ESC3Harness3 ESC3Harness3
Expand Down
186 changes: 186 additions & 0 deletions cmd/api/src/test/integration/harnesses/AZAddSecretHarness.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
{
"style": {
"font-family": "sans-serif",
"background-color": "#ffffff",
"background-image": "",
"background-size": "100%",
"node-color": "#ffffff",
"border-width": 4,
"border-color": "#68bc00",
"radius": 50,
"node-padding": 5,
"node-margin": 2,
"outside-position": "auto",
"node-icon-image": "",
"node-background-image": "",
"icon-position": "inside",
"icon-size": 64,
"caption-position": "inside",
"caption-max-width": 200,
"caption-color": "#000000",
"caption-font-size": 50,
"caption-font-weight": "normal",
"label-position": "inside",
"label-display": "pill",
"label-color": "#000000",
"label-background-color": "#ffffff",
"label-border-color": "#000000",
"label-border-width": 4,
"label-font-size": 40,
"label-padding": 5,
"label-margin": 4,
"directionality": "directed",
"detail-position": "inline",
"detail-orientation": "parallel",
"arrow-width": 5,
"arrow-color": "#aea1ff",
"margin-start": 5,
"margin-end": 5,
"margin-peer": 20,
"attachment-start": "normal",
"attachment-end": "normal",
"relationship-icon-image": "",
"type-color": "#000000",
"type-background-color": "#ffffff",
"type-border-color": "#000000",
"type-border-width": 0,
"type-font-size": 16,
"type-padding": 5,
"property-position": "outside",
"property-alignment": "colon",
"property-color": "#000000",
"property-font-size": 16,
"property-font-weight": "normal"
},
"nodes": [
{
"id": "n1",
"position": {
"x": 597.3793091010091,
"y": -206.05591982464335
},
"caption": "AZTenant",
"labels": [],
"properties": {},
"style": {}
},
{
"id": "n3",
"position": {
"x": 850.2593421152671,
"y": -372.9391447378271
},
"caption": "AppAdminRole",
"labels": [],
"properties": {},
"style": {}
},
{
"id": "n4",
"position": {
"x": 1187.6561016316446,
"y": -307.91634473234114
},
"caption": "AZApp",
"labels": [],
"properties": {},
"style": {}
},
{
"id": "n5",
"position": {
"x": 850.2593421152671,
"y": -60.05556469118005
},
"caption": "CloudAppAdminRole",
"labels": [],
"properties": {},
"style": {}
},
{
"id": "n8",
"position": {
"x": 1187.6561016316446,
"y": -104.19549491694585
},
"caption": "AZServicePrincipal",
"labels": [],
"properties": {},
"style": {}
}
],
"relationships": [
{
"id": "n3",
"fromId": "n1",
"toId": "n4",
"type": "AZContains",
"properties": {},
"style": {}
},
{
"id": "n4",
"fromId": "n3",
"toId": "n4",
"type": "AZAddSecret",
"properties": {},
"style": {
"arrow-color": "#fda1ff"
}
},
{
"id": "n9",
"fromId": "n1",
"toId": "n8",
"type": "AZContains",
"properties": {},
"style": {}
},
{
"id": "n21",
"fromId": "n1",
"toId": "n3",
"type": "AZContains",
"properties": {},
"style": {}
},
{
"id": "n22",
"fromId": "n1",
"toId": "n5",
"type": "AZContains",
"properties": {},
"style": {}
},
{
"id": "n30",
"fromId": "n5",
"toId": "n4",
"type": "AZAddSecret",
"properties": {},
"style": {
"arrow-color": "#fda1ff"
}
},
{
"id": "n32",
"type": "AZAddSecret",
"style": {
"arrow-color": "#fda1ff"
},
"properties": {},
"fromId": "n3",
"toId": "n8"
},
{
"id": "n33",
"type": "AZAddSecret",
"style": {
"arrow-color": "#fda1ff"
},
"properties": {},
"fromId": "n5",
"toId": "n8"
}
]
}
18 changes: 18 additions & 0 deletions cmd/api/src/test/integration/harnesses/AZAddSecretHarness.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions cmd/ui/src/views/Users/Users.test.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
// Copyright 2024 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

import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { render, screen, within } from 'src/test-utils';
Expand Down
Loading

0 comments on commit 03010e4

Please sign in to comment.