Skip to content

Commit

Permalink
Merge branch 'main' into NewNodes
Browse files Browse the repository at this point in the history
  • Loading branch information
ddlees committed Mar 30, 2023
2 parents 0893a7e + b3a75f3 commit 7030d93
Show file tree
Hide file tree
Showing 68 changed files with 616 additions and 866 deletions.
2 changes: 1 addition & 1 deletion cmd/configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ var configureCmd = &cobra.Command{

func configureCmdImpl(cmd *cobra.Command, args []string) {
if err := configure(); err != nil {
exit(err)
exit(fmt.Errorf("failed to configure cobra CLI: %w", err))
}
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/install_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ func installCmdImpl(cmd *cobra.Command, args []string) {
)

if err := configureService(); err != nil {
exit(err)
exit(fmt.Errorf("failed to configure service: %w", err))
} else if err := installService(constants.DisplayName, config, recoveryActions); err != nil {
exit(err)
exit(fmt.Errorf("failed to install service: %w", err))
}
}

Expand Down
58 changes: 19 additions & 39 deletions cmd/list-app-owners.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package cmd

import (
"context"
"fmt"
"os"
"os/signal"
"sync"
Expand Down Expand Up @@ -48,56 +47,37 @@ func listAppOwnersCmdImpl(cmd *cobra.Command, args []string) {
defer gracefulShutdown(stop)

log.V(1).Info("testing connections")
if err := testConnections(); err != nil {
exit(err)
} else if azClient, err := newAzureClient(); err != nil {
exit(err)
} else {
log.Info("collecting azure app owners...")
start := time.Now()
stream := listAppOwners(ctx, azClient, listApps(ctx, azClient))
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}
azClient := connectAndCreateClient()
log.Info("collecting azure app owners...")
start := time.Now()
stream := listAppOwners(ctx, azClient, listApps(ctx, azClient))
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}

func listAppOwners(ctx context.Context, client client.AzureClient, apps <-chan interface{}) <-chan interface{} {
func listAppOwners(ctx context.Context, client client.AzureClient, apps <-chan azureWrapper[models.App]) <-chan azureWrapper[models.AppOwners] {
var (
out = make(chan interface{})
ids = make(chan string)
streams = pipeline.Demux(ctx.Done(), ids, 25)
out = make(chan azureWrapper[models.AppOwners])
streams = pipeline.Demux(ctx.Done(), apps, 25)
wg sync.WaitGroup
)

go func() {
defer close(ids)

for result := range pipeline.OrDone(ctx.Done(), apps) {
if app, ok := result.(AzureWrapper).Data.(models.App); !ok {
log.Error(fmt.Errorf("failed type assertion"), "unable to continue enumerating app owners", "result", result)
return
} else {
ids <- app.Id
}
}
}()

wg.Add(len(streams))
for i := range streams {
stream := streams[i]
go func() {
defer wg.Done()
for id := range stream {
for app := range stream {
var (
data = models.AppOwners{
AppId: id,
AppId: app.Data.AppId,
}
count = 0
)
for item := range client.ListAzureADAppOwners(ctx, id, "", "", "", nil) {
for item := range client.ListAzureADAppOwners(ctx, app.Data.Id, "", "", "", nil) {
if item.Error != nil {
log.Error(item.Error, "unable to continue processing owners for this app", "appId", id)
log.Error(item.Error, "unable to continue processing owners for this app", "appId", app.Data.AppId)
} else {
appOwner := models.AppOwner{
Owner: item.Ok,
Expand All @@ -109,11 +89,11 @@ func listAppOwners(ctx context.Context, client client.AzureClient, apps <-chan i
}
}

out <- AzureWrapper{
Kind: enums.KindAZAppOwner,
Data: data,
}
log.V(1).Info("finished listing app owners", "appId", id, "count", count)
out <- NewAzureWrapper(
enums.KindAZAppOwner,
data,
)
log.V(1).Info("finished listing app owners", "appId", app.Data.AppId, "count", count)
}
}()
}
Expand Down
27 changes: 8 additions & 19 deletions cmd/list-app-owners_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"testing"

"github.com/bloodhoundad/azurehound/client/mocks"
"github.com/bloodhoundad/azurehound/enums"
"github.com/bloodhoundad/azurehound/models"
"github.com/bloodhoundad/azurehound/models/azure"
"github.com/golang/mock/gomock"
Expand All @@ -40,7 +41,7 @@ func TestListAppOwners(t *testing.T) {

mockClient := mocks.NewMockAzureClient(ctrl)

mockAppsChannel := make(chan interface{})
mockAppsChannel := make(chan azureWrapper[models.App])
mockAppOwnerChannel := make(chan azure.AppOwnerResult)
mockAppOwnerChannel2 := make(chan azure.AppOwnerResult)

Expand All @@ -53,12 +54,8 @@ func TestListAppOwners(t *testing.T) {

go func() {
defer close(mockAppsChannel)
mockAppsChannel <- AzureWrapper{
Data: models.App{},
}
mockAppsChannel <- AzureWrapper{
Data: models.App{},
}
mockAppsChannel <- NewAzureWrapper(enums.KindAZApp, models.App{})
mockAppsChannel <- NewAzureWrapper(enums.KindAZApp, models.App{})
}()
go func() {
defer close(mockAppOwnerChannel)
Expand All @@ -81,21 +78,13 @@ func TestListAppOwners(t *testing.T) {

if result, ok := <-channel; !ok {
t.Fatalf("failed to receive from channel")
} else if wrapper, ok := result.(AzureWrapper); !ok {
t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{})
} else if data, ok := wrapper.Data.(models.AppOwners); !ok {
t.Errorf("failed type assertion: got %T, want %T", wrapper.Data, models.AppOwners{})
} else if len(data.Owners) != 2 {
t.Errorf("got %v, want %v", len(data.Owners), 2)
} else if len(result.Data.Owners) != 2 {
t.Errorf("got %v, want %v", len(result.Data.Owners), 2)
}

if result, ok := <-channel; !ok {
t.Fatalf("failed to receive from channel")
} else if wrapper, ok := result.(AzureWrapper); !ok {
t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{})
} else if data, ok := wrapper.Data.(models.AppOwners); !ok {
t.Errorf("failed type assertion: got %T, want %T", wrapper.Data, models.AppOwners{})
} else if len(data.Owners) != 1 {
t.Errorf("got %v, want %v", len(data.Owners), 2)
} else if len(result.Data.Owners) != 1 {
t.Errorf("got %v, want %v", len(result.Data.Owners), 2)
}
}
21 changes: 8 additions & 13 deletions cmd/list-app-role-assignments.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,14 @@ func listAppRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) {
defer gracefulShutdown(stop)

log.V(1).Info("testing connections")
if err := testConnections(); err != nil {
exit(err)
} else if azClient, err := newAzureClient(); err != nil {
exit(err)
} else {
log.Info("collecting azure active directory app role assignments...")
start := time.Now()
servicePrincipals := listServicePrincipals(ctx, azClient)
stream := listAppRoleAssignments(ctx, azClient, servicePrincipals)
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}
azClient := connectAndCreateClient()
log.Info("collecting azure active directory app role assignments...")
start := time.Now()
servicePrincipals := listServicePrincipals(ctx, azClient)
stream := listAppRoleAssignments(ctx, azClient, servicePrincipals)
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}

func listAppRoleAssignments(ctx context.Context, client client.AzureClient, servicePrincipals <-chan interface{}) <-chan interface{} {
Expand Down
31 changes: 13 additions & 18 deletions cmd/list-apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,17 @@ func listAppsCmdImpl(cmd *cobra.Command, args []string) {
defer gracefulShutdown(stop)

log.V(1).Info("testing connections")
if err := testConnections(); err != nil {
exit(err)
} else if azClient, err := newAzureClient(); err != nil {
exit(err)
} else {
log.Info("collecting azure active directory applications...")
start := time.Now()
stream := listApps(ctx, azClient)
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}
azClient := connectAndCreateClient()
log.Info("collecting azure active directory applications...")
start := time.Now()
stream := listApps(ctx, azClient)
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}

func listApps(ctx context.Context, client client.AzureClient) <-chan interface{} {
out := make(chan interface{})
func listApps(ctx context.Context, client client.AzureClient) <-chan azureWrapper[models.App] {
out := make(chan azureWrapper[models.App])

go func() {
defer close(out)
Expand All @@ -72,14 +67,14 @@ func listApps(ctx context.Context, client client.AzureClient) <-chan interface{}
} else {
log.V(2).Info("found application", "app", item)
count++
out <- AzureWrapper{
Kind: enums.KindAZApp,
Data: models.App{
out <- NewAzureWrapper(
enums.KindAZApp,
models.App{
Application: item.Ok,
TenantId: client.TenantInfo().TenantId,
TenantName: client.TenantInfo().DisplayName,
},
}
)
}
}
log.Info("finished listing all apps", "count", count)
Expand Down
6 changes: 1 addition & 5 deletions cmd/list-apps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,7 @@ func TestListApps(t *testing.T) {
}()

channel := listApps(ctx, mockClient)
result := <-channel
if _, ok := result.(AzureWrapper); !ok {
t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{})
}

<-channel
if _, ok := <-channel; ok {
t.Error("expected channel to close from an error result but it did not")
}
Expand Down
21 changes: 8 additions & 13 deletions cmd/list-automation-account-role-assignments.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,14 @@ func listAutomationAccountRoleAssignmentImpl(cmd *cobra.Command, args []string)
defer gracefulShutdown(stop)

log.V(1).Info("testing connections")
if err := testConnections(); err != nil {
exit(err)
} else if azClient, err := newAzureClient(); err != nil {
exit(err)
} else {
log.Info("collecting azure automation account role assignments...")
start := time.Now()
subscriptions := listSubscriptions(ctx, azClient)
stream := listAutomationAccountRoleAssignments(ctx, azClient, listAutomationAccounts(ctx, azClient, subscriptions))
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}
azClient := connectAndCreateClient()
log.Info("collecting azure automation account role assignments...")
start := time.Now()
subscriptions := listSubscriptions(ctx, azClient)
stream := listAutomationAccountRoleAssignments(ctx, azClient, listAutomationAccounts(ctx, azClient, subscriptions))
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}

func listAutomationAccountRoleAssignments(ctx context.Context, client client.AzureClient, automationAccounts <-chan interface{}) <-chan interface{} {
Expand Down
19 changes: 7 additions & 12 deletions cmd/list-automation-accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,13 @@ func listAutomationAccountsCmdImpl(cmd *cobra.Command, args []string) {
defer gracefulShutdown(stop)

log.V(1).Info("testing connections")
if err := testConnections(); err != nil {
exit(err)
} else if azClient, err := newAzureClient(); err != nil {
exit(err)
} else {
log.Info("collecting azure automation accounts...")
start := time.Now()
stream := listAutomationAccounts(ctx, azClient, listSubscriptions(ctx, azClient))
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}
azClient := connectAndCreateClient()
log.Info("collecting azure automation accounts...")
start := time.Now()
stream := listAutomationAccounts(ctx, azClient, listSubscriptions(ctx, azClient))
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}

func listAutomationAccounts(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} {
Expand Down
27 changes: 10 additions & 17 deletions cmd/list-azure-ad.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,17 @@ func listAzureADCmdImpl(cmd *cobra.Command, args []string) {
defer gracefulShutdown(stop)

log.V(1).Info("testing connections")
if err := testConnections(); err != nil {
exit(err)
} else if azClient, err := newAzureClient(); err != nil {
exit(err)
} else {
log.Info("collecting azure ad objects...")
start := time.Now()
stream := listAllAD(ctx, azClient)
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}
azClient := connectAndCreateClient()
log.Info("collecting azure ad objects...")
start := time.Now()
stream := listAllAD(ctx, azClient)
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}

func listAllAD(ctx context.Context, client client.AzureClient) <-chan interface{} {
var (
apps = make(chan interface{})
apps2 = make(chan interface{})

devices = make(chan interface{})
devices2 = make(chan interface{})

Expand All @@ -87,8 +79,9 @@ func listAllAD(ctx context.Context, client client.AzureClient) <-chan interface{
)

// Enumerate Apps, AppOwners and AppMembers
pipeline.Tee(ctx.Done(), listApps(ctx, client), apps, apps2)
appOwners := listAppOwners(ctx, client, apps2)
appChans := pipeline.TeeFixed(ctx.Done(), listApps(ctx, client), 2)
apps := pipeline.ToAny(ctx.Done(), appChans[0])
appOwners := pipeline.ToAny(ctx.Done(), listAppOwners(ctx, client, appChans[1]))

// Enumerate Devices and DeviceOwners
pipeline.Tee(ctx.Done(), listDevices(ctx, client), devices, devices2)
Expand Down
19 changes: 7 additions & 12 deletions cmd/list-azure-rm.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,13 @@ func listAzureRMCmdImpl(cmd *cobra.Command, args []string) {
defer gracefulShutdown(stop)

log.V(1).Info("testing connections")
if err := testConnections(); err != nil {
exit(err)
} else if azClient, err := newAzureClient(); err != nil {
exit(err)
} else {
log.Info("collecting azure resource management objects...")
start := time.Now()
stream := listAllRM(ctx, azClient)
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}
azClient := connectAndCreateClient()
log.Info("collecting azure resource management objects...")
start := time.Now()
stream := listAllRM(ctx, azClient)
outputStream(ctx, stream)
duration := time.Since(start)
log.Info("collection completed", "duration", duration.String())
}

func listAllRM(ctx context.Context, client client.AzureClient) <-chan interface{} {
Expand Down
Loading

0 comments on commit 7030d93

Please sign in to comment.