Skip to content

Commit

Permalink
Replace AzureAD with Microsoft Graph in consent grant functions
Browse files Browse the repository at this point in the history
- Updates Get-AzureADPSPermissions to use Microsoft Graph cmdlets instead of deprecated AzureAD module.
- Modifies Get-HawkTenantConsentGrants to leverage Graph-based authentication.
- Maintains exact output format and data structure for backward compatibility.
- Updates documentation links to point to current Microsoft Learn pages for Microsoft Graph.
- Preserves original permission and consent validation logic while ensuring functionality with Graph.
- Improves object caching mechanism to handle Graph object types efficiently.

This migration ensures full feature parity with the previous AzureAD implementation while aligning with the modern Microsoft Graph SDK.
  • Loading branch information
jonnybottles committed Dec 4, 2024
1 parent e168e63 commit a89076c
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 313 deletions.
2 changes: 1 addition & 1 deletion Hawk/Hawk.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
'Get-HawkTenantConfiguration',
'Get-HawkTenantEDiscoveryConfiguration',
'Get-HawkTenantInboxRules',
'Get-HawkTenantConsentGrants',
'Get-HawkTenantConsentGrant',
'Get-HawkTenantRBACChanges',
'Get-HawkTenantAzureAppAuditLog',
'Get-HawkUserAuthHistory',
Expand Down
84 changes: 42 additions & 42 deletions Hawk/functions/Tenant/Get-HawkTenantConsentGrants.ps1
Original file line number Diff line number Diff line change
@@ -1,48 +1,48 @@
Function Get-HawkTenantConsentGrants {
<#
.SYNOPSIS
Gathers application grants
.DESCRIPTION
Used the script from https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/detect-and-remediate-illicit-consent-grants to gather information about
application and delegate grants. Attempts to detect high risk grants for review.
.OUTPUTS
File: Consent_Grants.csv
Path: \Tenant
Description: Output of all consent grants
.EXAMPLE
Get-HawkTenantConsentGrants
Function Get-HawkTenantConsentGrant {
<#
.SYNOPSIS
Gathers application grants
.DESCRIPTION
Uses Microsoft Graph to gather information about application and delegate grants.
Attempts to detect high risk grants for review.
.OUTPUTS
File: Consent_Grants.csv
Path: \Tenant
Description: Output of all consent grants
.EXAMPLE
Get-HawkTenantConsentGrant
Gathers Grants
#>
[CmdletBinding()]
param()

Gathers Grants
#>
Out-LogFile "Gathering OAuth / Application Grants"

Out-LogFile "Gathering Oauth / Application Grants"
Test-GraphConnection
Send-AIEvent -Event "CmdRun"

Test-AzureADConnection
Send-AIEvent -Event "CmdRun"
# Gather the grants using the internal Graph-based implementation
[array]$Grants = Get-AzureADPSPermission -ShowProgress
[bool]$flag = $false

# Gather the grants
# Using the script from the article https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/detect-and-remediate-illicit-consent-grants
[array]$Grants = Get-AzureADPSPermissions -ShowProgress
[bool]$flag = $false
# Search the Grants for the listed bad grants that we can detect
if ($Grants.ConsentType -contains 'AllPrincipals') {
Out-LogFile "Found at least one 'AllPrincipals' Grant" -notice
$flag = $true
}
if ([bool]($Grants.Permission -match 'all')) {
Out-LogFile "Found at least one 'All' Grant" -notice
$flag = $true
}

# Search the Grants for the listed bad grants that we can detect
if ($Grants.consenttype -contains 'AllPrinciples') {
Out-LogFile "Found at least one `'AllPrinciples`' Grant" -notice
$flag = $true
}
if ([bool]($Grants.permission -match 'all')){
Out-LogFile "Found at least one `'All`' Grant" -notice
$flag = $true
}
if ($flag) {
Out-LogFile 'Review the information at the following link to understand these results' -notice
Out-LogFile 'https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/detect-and-remediate-illicit-consent-grants' -notice
}
else {
Out-LogFile "To review this data follow:"
Out-LogFile "https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/detect-and-remediate-illicit-consent-grants"
}

if ($flag){
Out-LogFile 'Review the information at the following link to understand these results' -notice
Out-LogFile 'https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/detect-and-remediate-illicit-consent-grants#inventory-apps-with-access-in-your-organization' -notice
}
else {
Out-LogFile "To review this data follow:"
Out-LogFile "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/detect-and-remediate-illicit-consent-grants#inventory-apps-with-access-in-your-organization"
}

$Grants | Out-MultipleFileType -FilePrefix "Consent_Grants" -csv -json
}
$Grants | Out-MultipleFileType -FilePrefix "Consent_Grants" -csv -json
}
4 changes: 2 additions & 2 deletions Hawk/functions/Tenant/Start-HawkTenantInvestigation.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@
}

if ($PSCmdlet.ShouldProcess("Consent Grants", "Get consent grants")) {
Out-LogFile "Running Get-HawkTenantConsentGrants" -action
Get-HawkTenantConsentGrants
Out-LogFile "Running Get-HawkTenantConsentGrant" -action
Get-HawkTenantConsentGrant
}

if ($PSCmdlet.ShouldProcess("Azure Admins", "Get Azure admin list")) {
Expand Down
163 changes: 163 additions & 0 deletions Hawk/internal/functions/Get-AzureADPSPermission.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
Function Get-AzureADPSPermission {
[CmdletBinding()]
param(
[switch] $DelegatedPermissions,
[switch] $ApplicationPermissions,
[string[]] $UserProperties = @("DisplayName"),
[string[]] $ServicePrincipalProperties = @("DisplayName"),
[switch] $ShowProgress,
[int] $PrecacheSize = 999
)

# Verify Graph connection
try {
$tenant_details = Get-MgOrganization
}
catch {
throw "You must call Connect-MgGraph before running this script."
}
Write-Verbose ("TenantId: {0}" -f $tenant_details.Id)

# Cache objects
$script:ObjectByObjectId = @{}
$script:ObjectByObjectType = @{
'ServicePrincipal' = @{}
'User' = @{}
}

function CacheObject ($Object, $Type) {
if ($Object) {
$script:ObjectByObjectType[$Type][$Object.Id] = $Object
$script:ObjectByObjectId[$Object.Id] = $Object
}
}

function GetObjectByObjectId ($ObjectId) {
if (-not $script:ObjectByObjectId.ContainsKey($ObjectId)) {
Write-Verbose ("Querying Graph API for object '{0}'" -f $ObjectId)
try {
$object = Get-MgDirectoryObject -DirectoryObjectId $ObjectId
# Determine type from OdataType
$type = $object.AdditionalProperties.'@odata.type'.Split('.')[-1]
CacheObject -Object $object -Type $type
}
catch {
Write-Verbose "Object not found."
}
}
return $script:ObjectByObjectId[$ObjectId]
}

# Cache all service principals
Write-Verbose "Retrieving all ServicePrincipal objects..."
$servicePrincipals = Get-MgServicePrincipal -All
foreach($sp in $servicePrincipals) {
CacheObject -Object $sp -Type 'ServicePrincipal'
}
$servicePrincipalCount = $servicePrincipals.Count

# Cache users
Write-Verbose ("Retrieving up to {0} User objects..." -f $PrecacheSize)
$users = Get-MgUser -Top $PrecacheSize
foreach($user in $users) {
CacheObject -Object $user -Type 'User'
}

if ($DelegatedPermissions -or (-not ($DelegatedPermissions -or $ApplicationPermissions))) {
Write-Verbose "Retrieving OAuth2PermissionGrants..."
$oauth2Grants = Get-MgOAuth2PermissionGrant -All

foreach ($grant in $oauth2Grants) {
if ($grant.Scope) {
$grant.Scope.Split(" ") | Where-Object { $_ } | ForEach-Object {
$scope = $_

$grantDetails = [ordered]@{
"PermissionType" = "Delegated"
"ClientObjectId" = $grant.ClientId
"ResourceObjectId" = $grant.ResourceId
"Permission" = $scope
"ConsentType" = $grant.ConsentType
"PrincipalObjectId" = $grant.PrincipalId
}

# Add service principal properties
if ($ServicePrincipalProperties.Count -gt 0) {
$client = $script:ObjectByObjectId[$grant.ClientId]
$resource = $script:ObjectByObjectId[$grant.ResourceId]

$insertAtClient = 2
$insertAtResource = 3
foreach ($propertyName in $ServicePrincipalProperties) {
$grantDetails.Insert($insertAtClient++, "Client$propertyName", $client.$propertyName)
$insertAtResource++
$grantDetails.Insert($insertAtResource, "Resource$propertyName", $resource.$propertyName)
$insertAtResource++
}
}

# Add user properties
if ($UserProperties.Count -gt 0) {
$principal = if ($grant.PrincipalId) {
$script:ObjectByObjectId[$grant.PrincipalId]
} else { @{} }

foreach ($propertyName in $UserProperties) {
$grantDetails["Principal$propertyName"] = $principal.$propertyName
}
}

New-Object PSObject -Property $grantDetails
}
}
}
}

if ($ApplicationPermissions -or (-not ($DelegatedPermissions -or $ApplicationPermissions))) {
Write-Verbose "Retrieving AppRoleAssignments..."

$i = 0
foreach ($sp in $servicePrincipals) {
if ($ShowProgress) {
Write-Progress -Activity "Retrieving application permissions..." `
-Status ("Checked {0}/{1} apps" -f $i++, $servicePrincipalCount) `
-PercentComplete (($i / $servicePrincipalCount) * 100)
}

$appRoleAssignments = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All

foreach ($assignment in $appRoleAssignments) {
if ($assignment.PrincipalType -eq "ServicePrincipal") {
$resource = $script:ObjectByObjectId[$assignment.ResourceId]
$appRole = $resource.AppRoles | Where-Object { $_.Id -eq $assignment.AppRoleId }

$grantDetails = [ordered]@{
"PermissionType" = "Application"
"ClientObjectId" = $assignment.PrincipalId
"ResourceObjectId" = $assignment.ResourceId
"Permission" = $appRole.Value
}

if ($ServicePrincipalProperties.Count -gt 0) {
$client = $script:ObjectByObjectId[$assignment.PrincipalId]

$insertAtClient = 2
$insertAtResource = 3
foreach ($propertyName in $ServicePrincipalProperties) {
$grantDetails.Insert($insertAtClient++, "Client$propertyName", $client.$propertyName)
$insertAtResource++
$grantDetails.Insert($insertAtResource, "Resource$propertyName", $resource.$propertyName)
$insertAtResource++
}
}

New-Object PSObject -Property $grantDetails
}
}
}

if ($ShowProgress) {
Write-Progress -Completed -Activity "Retrieving application permissions..."
}
}
}
Loading

0 comments on commit a89076c

Please sign in to comment.