Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
af39e51
Updated to the latest commit of main branch on the original repo
vishalk-metron Jun 17, 2025
848b218
Update .gitignore
vishalk-metron Jun 17, 2025
62498f4
Partial code completion for fetching devices from intune
vishalk-metron Jun 17, 2025
0d5c890
sample integration example (partial, may not work)
vishalk-metron Jun 17, 2025
45f8965
Merge remote-tracking branch 'spectreops-ah-repo/main' into vishalk-m…
vishalk-metron Jun 17, 2025
a62a190
Intune basic APIs have been implemented
vishalk-metron Jun 17, 2025
688ccf2
Added powershell script to get JWT Token from graph
vishalk-metron Jun 17, 2025
c6a476f
Update .gitignore
vishalk-metron Jun 17, 2025
373cfc2
Updated the file 'list-intune-script-results.go' to get results from …
vishalk-metron Jun 18, 2025
c85f340
Added files for Registry values module - incomplete
vishalk-metron Jun 19, 2025
ab1d17b
Removed Registry Values Files to clean up the PR
vishalk-metron Jun 19, 2025
8c4e2a8
Delete registry.go
vishalk-metron Jun 19, 2025
6c20e19
Removed references for script execution module
vishalk-metron Jun 19, 2025
14f9461
Removed Duplicate Code, Unused Code
vishalk-metron Jun 19, 2025
5fcda19
Reduced Code Duplication
vishalk-metron Jun 19, 2025
414247f
Working Unoptimised version
vishalk-metron Jun 25, 2025
a63b083
Implemented Real API instead of mock results
vishalk-metron Jun 26, 2025
160a712
Delete cla.yml
vishalk-metron Jun 26, 2025
97867d2
Removing Action / Checks
vishalk-metron Jun 26, 2025
fd673c1
test commit
vishalk-metron Jun 26, 2025
e1c2866
Revert "test commit"
vishalk-metron Jun 27, 2025
ba2d4f3
Revert "Removing Action / Checks"
vishalk-metron Jun 27, 2025
8ebed47
Revert "Delete cla.yml"
vishalk-metron Jun 27, 2025
5a48c7d
Delete intune_converter.go
vishalk-metron Jun 27, 2025
39bdfca
Update list-intune-registry-analysis.go
vishalk-metron Jul 2, 2025
5811b81
Delete get_token.ps1
vishalk-metron Jul 2, 2025
f2c2b46
CodeRabbit PR Comments Resolved
vishalk-metron Jul 11, 2025
8eebeac
CodeRabbit PR Comments Resolved
vishalk-metron Jul 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -232,3 +232,7 @@ tags

# Built Visual Studio Code Extensions
*.vsix
.github/workflows/cla.yml
.github/workflows/vuln-scan.yml
/.github
get_token.ps1
76 changes: 67 additions & 9 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ import (
"fmt"
"net/http"
"net/url"
"time"

"github.com/bloodhoundad/azurehound/v2/client/config"
"github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/client/rest"
"github.com/bloodhoundad/azurehound/v2/models/azure"
"github.com/bloodhoundad/azurehound/v2/models/intune"
"github.com/bloodhoundad/azurehound/v2/panicrecovery"
"github.com/bloodhoundad/azurehound/v2/pipeline"
)
Expand Down Expand Up @@ -174,22 +176,35 @@ type azureClient struct {
tenant azure.Tenant
}

// Core AzureGraphClient interface - unchanged to preserve compatibility
type AzureGraphClient interface {
GetAzureADOrganization(ctx context.Context, selectCols []string) (*azure.Organization, error)

ListAzureADGroups(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Group]
ListAzureADGroupMembers(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]
ListAzureADGroupOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]
ListAzureADAppOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]
ListAzureADApps(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Application]

ListAzureADUsers(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.User]
ListAzureADRoleAssignments(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.UnifiedRoleAssignment]
ListAzureADRoles(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Role]
ListAzureADServicePrincipalOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]

ListAzureADApps(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Application]
ListAzureADAppOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]

ListAzureADServicePrincipals(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.ServicePrincipal]
ListAzureDeviceRegisteredOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]
ListAzureADServicePrincipalOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]

ListAzureADRoles(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Role]
ListAzureADRoleAssignments(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.UnifiedRoleAssignment]

ListAzureDevices(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.Device]
ListAzureDeviceRegisteredOwners(ctx context.Context, objectId string, params query.GraphParams) <-chan AzureResult[json.RawMessage]

ListAzureADAppRoleAssignments(ctx context.Context, servicePrincipalId string, params query.GraphParams) <-chan AzureResult[azure.AppRoleAssignment]
ListAzureUnifiedRoleEligibilityScheduleInstances(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.UnifiedRoleEligibilityScheduleInstance]

ListAzureADTenants(ctx context.Context, includeAllTenantCategories bool) <-chan AzureResult[azure.Tenant]
GetAzureADTenants(ctx context.Context, includeAllTenantCategories bool) (azure.TenantList, error)

ListRoleAssignmentPolicies(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.UnifiedRoleManagementPolicyAssignment]
}

type AzureResourceManagerClient interface {
Expand All @@ -214,10 +229,53 @@ type AzureResourceManagerClient interface {
ListAzureFunctionApps(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.FunctionApp]
}

type AzureClient interface {
// New interface for Intune-specific Graph operations
type IntuneGraphClient interface {
ValidateScriptDeployment(ctx context.Context) error

ListIntuneDevices(ctx context.Context, params query.GraphParams) <-chan AzureResult[azure.IntuneDevice]
ExecuteRegistryCollectionScript(ctx context.Context, deviceID string) (*azure.ScriptExecution, error)
GetScriptExecutionResults(ctx context.Context, scriptID string) <-chan AzureResult[azure.ScriptExecutionResult]
WaitForScriptCompletion(ctx context.Context, scriptID string, maxWaitTime time.Duration) (*azure.RegistryData, error)
CollectRegistryDataFromDevice(ctx context.Context, deviceID string) (*azure.RegistryData, error)
CollectRegistryDataFromAllDevices(ctx context.Context) <-chan AzureResult[azure.DeviceRegistryData]
GetDeployedScriptID(ctx context.Context, scriptName string) (string, error)
TriggerScriptExecution(ctx context.Context, scriptID, deviceID string) error

// Add Intune methods
ListIntuneManagedDevices(ctx context.Context, params query.GraphParams) <-chan AzureResult[intune.ManagedDevice]
GetIntuneDeviceCompliance(ctx context.Context, deviceId string, params query.GraphParams) <-chan AzureResult[intune.ComplianceState]
GetIntuneDeviceConfiguration(ctx context.Context, deviceId string, params query.GraphParams) <-chan AzureResult[intune.ConfigurationState]
}

// Composed interface that includes both core and Intune functionality
type ExtendedAzureGraphClient interface {
AzureGraphClient
AzureResourceManagerClient
AzureRoleManagementClient
IntuneGraphClient
}

// Core AzureClient interface - unchanged to preserve compatibility
type AzureClient interface {
ExtendedAzureGraphClient

ListAzureSubscriptions(ctx context.Context) <-chan AzureResult[azure.Subscription]
ListAzureResourceGroups(ctx context.Context, subscriptionId string, params query.RMParams) <-chan AzureResult[azure.ResourceGroup]
ListAzureVirtualMachines(ctx context.Context, subscriptionId string, params query.RMParams) <-chan AzureResult[azure.VirtualMachine]
ListAzureVMScaleSets(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.VMScaleSet]
ListAzureKeyVaults(ctx context.Context, subscriptionId string, params query.RMParams) <-chan AzureResult[azure.KeyVault]
ListAzureStorageAccounts(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.StorageAccount]
ListAzureStorageContainers(ctx context.Context, subscriptionId, resourceGroupName, saName, filter, includeDeleted, maxPageSize string) <-chan AzureResult[azure.StorageContainer]
ListAzureContainerRegistries(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.ContainerRegistry]
ListAzureWebApps(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.WebApp]
ListAzureFunctionApps(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.FunctionApp]
ListAzureLogicApps(ctx context.Context, subscriptionId, filter string, top int32) <-chan AzureResult[azure.LogicApp]
ListAzureAutomationAccounts(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.AutomationAccount]
ListAzureManagedClusters(ctx context.Context, subscriptionId string) <-chan AzureResult[azure.ManagedCluster]

ListAzureManagementGroups(ctx context.Context, skipToken string) <-chan AzureResult[azure.ManagementGroup]
ListAzureManagementGroupDescendants(ctx context.Context, groupId string, top int32) <-chan AzureResult[azure.DescendantInfo]

ListRoleAssignmentsForResource(ctx context.Context, resourceId, filter, tenantId string) <-chan AzureResult[azure.RoleAssignment]

TenantInfo() azure.Tenant
CloseIdleConnections()
Expand Down
62 changes: 62 additions & 0 deletions client/intune_devices.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// File: client/intune_devices.go
// Copyright (C) 2022 SpecterOps
// Implementation of Intune device management API calls

package client

import (
"context"
"fmt"

"github.com/bloodhoundad/azurehound/v2/client/query"
"github.com/bloodhoundad/azurehound/v2/constants"
"github.com/bloodhoundad/azurehound/v2/models/intune"
)

func setDefaultParams(params *query.GraphParams) {
if params.Top == 0 {
params.Top = 999
}
}

// ListIntuneManagedDevices retrieves all managed devices from Intune
// GET /deviceManagement/managedDevices
func (s *azureClient) ListIntuneManagedDevices(ctx context.Context, params query.GraphParams) <-chan AzureResult[intune.ManagedDevice] {
var (
out = make(chan AzureResult[intune.ManagedDevice])
path = fmt.Sprintf("/%s/deviceManagement/managedDevices", constants.GraphApiVersion)
)

setDefaultParams(&params)

go getAzureObjectList[intune.ManagedDevice](s.msgraph, ctx, path, params, out)
return out
}

// GetIntuneDeviceCompliance retrieves compliance information for a specific device
// GET /deviceManagement/managedDevices/{id}/deviceCompliancePolicyStates
func (s *azureClient) GetIntuneDeviceCompliance(ctx context.Context, deviceId string, params query.GraphParams) <-chan AzureResult[intune.ComplianceState] {
var (
out = make(chan AzureResult[intune.ComplianceState])
path = fmt.Sprintf("/%s/deviceManagement/managedDevices/%s/deviceCompliancePolicyStates", constants.GraphApiVersion, deviceId)
)

setDefaultParams(&params)

go getAzureObjectList[intune.ComplianceState](s.msgraph, ctx, path, params, out)
return out
}

// GetIntuneDeviceConfiguration retrieves configuration information for a specific device
// GET /deviceManagement/managedDevices/{id}/deviceConfigurationStates
func (s *azureClient) GetIntuneDeviceConfiguration(ctx context.Context, deviceId string, params query.GraphParams) <-chan AzureResult[intune.ConfigurationState] {
var (
out = make(chan AzureResult[intune.ConfigurationState])
path = fmt.Sprintf("/%s/deviceManagement/managedDevices/%s/deviceConfigurationStates", constants.GraphApiVersion, deviceId)
)

setDefaultParams(&params)

go getAzureObjectList[intune.ConfigurationState](s.msgraph, ctx, path, params, out)
return out
}
Loading
Loading