Skip to content

Commit

Permalink
Merge pull request #36 from BloodHoundAD/NewNodes
Browse files Browse the repository at this point in the history
feat: Add collection of several new node types
  • Loading branch information
andyrobbins authored Mar 30, 2023
2 parents b3a75f3 + 6cd1627 commit 60e3117
Show file tree
Hide file tree
Showing 38 changed files with 2,182 additions and 152 deletions.
6 changes: 5 additions & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ type AzureClient interface {
ListAzureADServicePrincipals(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.ServicePrincipalResult
ListAzureADTenants(ctx context.Context, includeAllTenantCategories bool) <-chan azure.TenantResult
ListAzureADUsers(ctx context.Context, filter string, search string, orderBy string, selectCols []string) <-chan azure.UserResult
ListAzureContainerRegistries(ctx context.Context, subscriptionId string) <-chan azure.ContainerRegistryResult
ListAzureWebApps(ctx context.Context, subscriptionId string) <-chan azure.WebAppResult
ListAzureManagedClusters(ctx context.Context, subscriptionId string, statusOnly bool) <-chan azure.ManagedClusterResult
ListAzureVMScaleSets(ctx context.Context, subscriptionId string, statusOnly bool) <-chan azure.VMScaleSetResult
ListAzureDeviceRegisteredOwners(ctx context.Context, objectId string, securityEnabledOnly bool) <-chan azure.DeviceRegisteredOwnerResult
ListAzureDevices(ctx context.Context, filter, search, orderBy, expand string, selectCols []string) <-chan azure.DeviceResult
ListAzureKeyVaults(ctx context.Context, subscriptionId string, top int32) <-chan azure.KeyVaultResult
Expand All @@ -155,7 +159,7 @@ type AzureClient interface {
ListAzureStorageAccounts(ctx context.Context, subscriptionId string) <-chan azure.StorageAccountResult
ListAzureStorageContainers(ctx context.Context, subscriptionId string, resourceGroupName string, saName string, filter string, includeDeleted string, maxPageSize string) <-chan azure.StorageContainerResult
ListAzureAutomationAccounts(ctx context.Context, subscriptionId string) <-chan azure.AutomationAccountResult
ListAzureWorkflows(ctx context.Context, subscriptionId string, filter string, top int32) <-chan azure.WorkflowResult
ListAzureLogicApps(ctx context.Context, subscriptionId string, filter string, top int32) <-chan azure.LogicAppResult
ListAzureFunctionApps(ctx context.Context, subscriptionId string) <-chan azure.FunctionAppResult
ListResourceRoleAssignments(ctx context.Context, subscriptionId string, filter string, expand string) <-chan azure.RoleAssignmentResult
ListRoleAssignmentsForResource(ctx context.Context, resourceId string, filter string) <-chan azure.RoleAssignmentResult
Expand Down
116 changes: 116 additions & 0 deletions client/container_registries.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright (C) 2022 Specter Ops, Inc.
//
// This file is part of AzureHound.
//
// AzureHound is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// AzureHound is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package client

import (
"context"
"fmt"
"net/url"

"github.com/bloodhoundad/azurehound/client/query"
"github.com/bloodhoundad/azurehound/client/rest"
"github.com/bloodhoundad/azurehound/models/azure"
)

func (s *azureClient) GetAzureContainerRegistry(ctx context.Context, subscriptionId, groupName, crName, expand string) (*azure.ContainerRegistry, error) {
var (
path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ContainerRegistry/registries/%s", subscriptionId, groupName, crName)
params = query.Params{ApiVersion: "2023-01-01-preview", Expand: expand}.AsMap()
headers map[string]string
response azure.ContainerRegistry
)
if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
return nil, err
} else if err := rest.Decode(res.Body, &response); err != nil {
return nil, err
} else {
return &response, nil
}
}

func (s *azureClient) GetAzureContainerRegistries(ctx context.Context, subscriptionId string) (azure.ContainerRegistryList, error) {
var (
path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.ContainerRegistry/registries", subscriptionId)
params = query.Params{ApiVersion: "2023-01-01-preview"}.AsMap()
headers map[string]string
response azure.ContainerRegistryList
)

if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
return response, err
} else if err := rest.Decode(res.Body, &response); err != nil {
return response, err
} else {
return response, nil
}
}

func (s *azureClient) ListAzureContainerRegistries(ctx context.Context, subscriptionId string) <-chan azure.ContainerRegistryResult {
out := make(chan azure.ContainerRegistryResult)

go func() {
defer close(out)

var (
errResult = azure.ContainerRegistryResult{
SubscriptionId: subscriptionId,
}
nextLink string
)

if result, err := s.GetAzureContainerRegistries(ctx, subscriptionId); err != nil {
errResult.Error = err
out <- errResult
} else {
for _, u := range result.Value {
out <- azure.ContainerRegistryResult{SubscriptionId: subscriptionId, Ok: u}
}

nextLink = result.NextLink
for nextLink != "" {
var list azure.ContainerRegistryList
if url, err := url.Parse(nextLink); err != nil {
errResult.Error = err
out <- errResult
nextLink = ""
} else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
errResult.Error = err
out <- errResult
nextLink = ""
} else if res, err := s.resourceManager.Send(req); err != nil {
errResult.Error = err
out <- errResult
nextLink = ""
} else if err := rest.Decode(res.Body, &list); err != nil {
errResult.Error = err
out <- errResult
nextLink = ""
} else {
for _, u := range list.Value {
out <- azure.ContainerRegistryResult{
SubscriptionId: "/subscriptions/" + subscriptionId,
Ok: u,
}
}
nextLink = list.NextLink
}
}
}
}()
return out
}
24 changes: 12 additions & 12 deletions client/workflows.go → client/logic_apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ import (
"github.com/bloodhoundad/azurehound/models/azure"
)

func (s *azureClient) GetAzureWorkflow(ctx context.Context, subscriptionId, groupName, workflowName, expand string) (*azure.Workflow, error) {
func (s *azureClient) GetAzureLogicApp(ctx context.Context, subscriptionId, groupName, logicappName, expand string) (*azure.LogicApp, error) {
var (
path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Logic/workflows/%s", subscriptionId, groupName, workflowName)
path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Logic/workflows/%s", subscriptionId, groupName, logicappName)
params = query.Params{ApiVersion: "2016-06-01", Expand: expand}.AsMap()
headers map[string]string
response azure.Workflow
response azure.LogicApp
)
if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
return nil, err
Expand All @@ -43,12 +43,12 @@ func (s *azureClient) GetAzureWorkflow(ctx context.Context, subscriptionId, grou
}
}

func (s *azureClient) GetAzureWorkflows(ctx context.Context, subscriptionId string, filter string, top int32) (azure.WorkflowList, error) {
func (s *azureClient) GetAzureLogicApps(ctx context.Context, subscriptionId string, filter string, top int32) (azure.LogicAppList, error) {
var (
path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Logic/workflows", subscriptionId)
params = query.Params{ApiVersion: "2016-06-01", Filter: filter, Top: top}.AsMap()
headers map[string]string
response azure.WorkflowList
response azure.LogicAppList
)

if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
Expand All @@ -60,30 +60,30 @@ func (s *azureClient) GetAzureWorkflows(ctx context.Context, subscriptionId stri
}
}

func (s *azureClient) ListAzureWorkflows(ctx context.Context, subscriptionId string, filter string, top int32) <-chan azure.WorkflowResult {
out := make(chan azure.WorkflowResult)
func (s *azureClient) ListAzureLogicApps(ctx context.Context, subscriptionId string, filter string, top int32) <-chan azure.LogicAppResult {
out := make(chan azure.LogicAppResult)

go func() {
defer close(out)

var (
errResult = azure.WorkflowResult{
errResult = azure.LogicAppResult{
SubscriptionId: subscriptionId,
}
nextLink string
)

if result, err := s.GetAzureWorkflows(ctx, subscriptionId, filter, top); err != nil {
if result, err := s.GetAzureLogicApps(ctx, subscriptionId, filter, top); err != nil {
errResult.Error = err
out <- errResult
} else {
for _, u := range result.Value {
out <- azure.WorkflowResult{SubscriptionId: subscriptionId, Ok: u}
out <- azure.LogicAppResult{SubscriptionId: subscriptionId, Ok: u}
}

nextLink = result.NextLink
for nextLink != "" {
var list azure.WorkflowList
var list azure.LogicAppList
if url, err := url.Parse(nextLink); err != nil {
errResult.Error = err
out <- errResult
Expand All @@ -102,7 +102,7 @@ func (s *azureClient) ListAzureWorkflows(ctx context.Context, subscriptionId str
nextLink = ""
} else {
for _, u := range list.Value {
out <- azure.WorkflowResult{
out <- azure.LogicAppResult{
SubscriptionId: "/subscriptions/" + subscriptionId,
Ok: u,
}
Expand Down
116 changes: 116 additions & 0 deletions client/managed_clusters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright (C) 2022 Specter Ops, Inc.
//
// This file is part of AzureHound.
//
// AzureHound is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// AzureHound is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package client

import (
"context"
"fmt"
"net/url"

"github.com/bloodhoundad/azurehound/client/query"
"github.com/bloodhoundad/azurehound/client/rest"
"github.com/bloodhoundad/azurehound/models/azure"
)

func (s *azureClient) GetAzureManagedCluster(ctx context.Context, subscriptionId, groupName, mcName, expand string) (*azure.ManagedCluster, error) {
var (
path = fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ContainerService/managedClusters/%s", subscriptionId, groupName, mcName)
params = query.Params{ApiVersion: "2021-07-01", Expand: expand}.AsMap()
headers map[string]string
response azure.ManagedCluster
)
if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
return nil, err
} else if err := rest.Decode(res.Body, &response); err != nil {
return nil, err
} else {
return &response, nil
}
}

func (s *azureClient) GetAzureManagedClusters(ctx context.Context, subscriptionId string, statusOnly bool) (azure.ManagedClusterList, error) {
var (
path = fmt.Sprintf("/subscriptions/%s/providers/Microsoft.ContainerService/managedClusters", subscriptionId)
params = query.Params{ApiVersion: "2021-07-01", StatusOnly: statusOnly}.AsMap()
headers map[string]string
response azure.ManagedClusterList
)

if res, err := s.resourceManager.Get(ctx, path, params, headers); err != nil {
return response, err
} else if err := rest.Decode(res.Body, &response); err != nil {
return response, err
} else {
return response, nil
}
}

func (s *azureClient) ListAzureManagedClusters(ctx context.Context, subscriptionId string, statusOnly bool) <-chan azure.ManagedClusterResult {
out := make(chan azure.ManagedClusterResult)

go func() {
defer close(out)

var (
errResult = azure.ManagedClusterResult{
SubscriptionId: subscriptionId,
}
nextLink string
)

if result, err := s.GetAzureManagedClusters(ctx, subscriptionId, statusOnly); err != nil {
errResult.Error = err
out <- errResult
} else {
for _, u := range result.Value {
out <- azure.ManagedClusterResult{SubscriptionId: subscriptionId, Ok: u}
}

nextLink = result.NextLink
for nextLink != "" {
var list azure.ManagedClusterList
if url, err := url.Parse(nextLink); err != nil {
errResult.Error = err
out <- errResult
nextLink = ""
} else if req, err := rest.NewRequest(ctx, "GET", url, nil, nil, nil); err != nil {
errResult.Error = err
out <- errResult
nextLink = ""
} else if res, err := s.resourceManager.Send(req); err != nil {
errResult.Error = err
out <- errResult
nextLink = ""
} else if err := rest.Decode(res.Body, &list); err != nil {
errResult.Error = err
out <- errResult
nextLink = ""
} else {
for _, u := range list.Value {
out <- azure.ManagedClusterResult{
SubscriptionId: "/subscriptions/" + subscriptionId,
Ok: u,
}
}
nextLink = list.NextLink
}
}
}
}()
return out
}
Loading

0 comments on commit 60e3117

Please sign in to comment.