This post provides details about the queries that can be used to hunt various attack techniques in Microsoft 365 environment.

Queries to Threat Hunt in Microsoft 365 Environment

1.Hunt for Mailboxes configured with Email Forwarding

Query Exchange Online Configuration:

Get-Mailbox -ResultSize Unlimited | Where-Object {($Null -ne $_.ForwardingSmtpAddress)} | Select Identity,Name,ForwardingSmtpAddress

Query Unified Audit Logs:

$logs = Search-UnifiedAuditLog -Operations set-mailbox -StartDate 2022-01-01 -EndDate 2022-06-30 ForEach ($record in $logs){ $AuditData = $record.AuditData | ConvertFrom-Json if ( $AuditData.Parameters | Where-Object Name -eq 'forwardingsmtpaddress' ) {$record}}

2.Hunt for Mailboxes configured with Inbox Rules to Auto Email Forward

Query Exchange Online Configuration:

$Mailboxes = Get-Mailbox ; foreach ($Mailbox in $Mailboxes) { Get-InboxRule -mailbox $Mailbox.Name | Where-Object {($Null -ne $_.ForwardTo) -or ($Null -ne $_.RedirectTo) -or ($Null -ne $_.ForwardAsAttachmentTo) } | select-object identity,Name,Enabled,ForwardAsAttachmentTo,ForwardTo,RedirectTo }

Query Unified Audit Logs:

$logs = Search-UnifiedAuditLog -operations new-inboxrule,set-inboxrule -StartDate 2022-01-01 -EndDate 2022-07-08 ForEach ($record in $logs){ $AuditData = $record.AuditData | ConvertFrom-Json if ( $AuditData.Parameters | Where-Object {($_.Name -like 'ForwardTo') -or ($_.Name -eq 'RedirectTo') -or ($_.Name -eq 'ForwardAsAttachmentTo')}) {$record}}

3.Hunt for Transport Rules configured with Auto Email Forward

Query Exchange Online Configuration:

Get-TransportRule | where-object{($Null -ne $_.BlindCopyTo)}

Query Admin Audit Log:

Search-AdminAuditLog -Cmdlets New-TransportRule,Set-TransportRule -parameter BlindCopyTo

Query Unified Audit Logs:

Search-UnifiedAuditLog -Operations New-TransportRule, Set-TransportRule -StartDate 2022-01-01 -EndDate 2022-06-30

4.Hunt for mailboxes configured with Full Access Delegation Settings

Query Exchange Online Configuration:

Get-Mailbox -Resultsize Unlimited | Get-MailboxPermission | Where-Object { ($_.Accessrights -like "FullAccess")}

Query Unified Audit Logs:

$logs = Search-UnifiedAuditLog -operations add-mailboxpermission -StartDate 2022-01-01 -EndDate 2022-07-08 ForEach ($record in $logs){ $AuditData = $record.AuditData | ConvertFrom-Json if ( $AuditData.Parameters | Where-Object {($_.Value -eq 'FullAccess')}) {$record}}

5.Hunt for mailboxes configured with SendAs Delegation Settings

Query Exchange Online Configuration:

Get-Mailbox -Resultsize Unlimited | Get-RecipientPermission | where-Object { ($_.Accessrights -like "SendAs")}

Query Unified Audit Logs:

$logs = Search-UnifiedAuditLog -operations Add-RecipientPermission -StartDate 2022-01-01 -EndDate 2022-07-20 ForEach ($record in $logs){ $AuditData = $record.AuditData | ConvertFrom-Json if ( $AuditData.Parameters | Where-Object {($_.Value -eq 'SendAs')}) {$record}}

6.Hunt for mailboxes configured with Mailbox Folder Permissions

Query Exchange Online Configuration:

$mailboxes = Get-Mailbox -ResultSize Unlimited ForEach ($record in $logs){ $AuditData = $record.AuditData | ConvertFrom-Json if ( $AuditData.Parameters | Where-Object {($_.Value -like 'Anonymous') -or ($_.Value -eq 'Default') }) {$record}}

Query Unified Audit Logs:

$logs = Search-UnifiedAuditLog -operations add-MailboxFolderPermission,Set-MailboxFolderPermission -StartDate 2022-01-01 -EndDate 2022-07-08 ForEach ($record in $logs){ $AuditData = $record.AuditData | ConvertFrom-Json if ( $AuditData.Parameters | Where-Object {($_.Value -like ''Anonymous'') -or ($_.Value -eq 'Default') }) {$record}}

7.List all the flows. Look for email autoforward and data extraction flows.

Query Power Automate:

$flowCollection = @() Connect-MsolService $users = Get-MsolUser -All | Select-Object UserPrincipalName, ObjectId $flows = get-AdminFlow foreach($flow in $flows){ $flowProperties = $flow.internal.properties $Creator = $users | where-object{$_.ObjectId -eq $flowProperties.creator.UserID} $triggers = $flowProperties.definitionsummary.triggers $actions = $flowProperties.definitionsummary.actions | where-object {$_.swaggerOperationId} [datetime]$modifiedTime = $flow.LastModifiedTime [datetime]$createdTime = $flowProperties.createdTime $flowCollection += new-object psobject -property @{displayName = $flowProperties.displayName;environment = $flowProperties.Environment.name;State = $flowProperties.State;Triggers = $triggers.swaggerOperationId;Actions = $actions.swaggerOperationId;Created = $createdTime.ToString("dd-MM-yyyy HH:mm:ss");Modified = $modifiedTime.ToString("dd-MM-yyyy HH:mm:ss");CreatedBy = $Creator.userPrincipalName } $flowCollection }

8.Hunt for identities with Application Impersonation Role assigned

Query Azure AD Tenant:

$AppImperGroups = Get-RoleGroup | Where-Object Roles -like ApplicationImpersonation ForEach ($Group in $AppImperGroups) { Get-RoleGroupMember $Group.Name }

Get-ManagementRoleAssignment -Role ApplicationImpersonation

Query Unified Audit Logs:

$logs = Search-UnifiedAuditLog -operations 'New-RoleGroup, New-ManagementRoleAssignment,set-ManagementRoleAssignment' -StartDate 2022-01-01 -EndDate 2022-07-08 ForEach ($record in $logs){ $AuditData = $record.AuditData | ConvertFrom-Json if ( $AuditData.Parameters | Where-Object {($_.Value -like 'ApplicationImpersonation')}) {$record}}

9.Hunt for Service principals and their OAuth permission Grants

Query Azure AD Tenant:

Get-AzureADServicePrincipal | ForEach-Object{ $spn = $_; $objID = $spn.ObjectID; $grants = Get-AzureADServicePrincipalOAuth2PermissionGrant -ObjectId $objID; foreach ($grant in $grants) { $user = Get-AzureADUser -ObjectId $grant.PrincipalId; $OAuthGrant = New-Object PSObject; $OAuthGrant | Add-Member Noteproperty 'ObjectID' $grant.objectId; $OAuthGrant | Add-Member Noteproperty 'User' $user.UserPrincipalName; $OAuthGrant | Add-Member Noteproperty 'AppDisplayName' $spn.DisplayName; $OAuthGrant | Add-Member Noteproperty 'AppPublisherName' $spn.PublisherName; $OAuthGrant | Add-Member Noteproperty 'AppReplyURLs' $spn.ReplyUrls; $OAuthGrant | Add-Member Noteproperty 'GrantConsentType' $grant.consentType; $OAuthGrant | Add-Member Noteproperty 'GrantScopes' $grant.scope; } Write-Output $OAuthGrant }

Query Unified Audit Logs:

Search-UnifiedAuditLog -recordtype SharePointSharingOperation -operations 'anonymouslinkcreated,anonymouslinkupdated' -startdate 2022-07-30 -enddate 2022-08-01

Query Unified Audit Logs:

Search-UnifiedAuditLog -recordtype SharePointSharingOperation -operations 'AnonymousLinkUsed' -startdate 2022-07-30 -enddate 2022-08-01

12.List all Service Principals configured with secrets in Azure AD

Query Azure AD Tenant:

$Spns = Get-AzureADServicePrincipal -All $true foreach ($Spn in $Spns) { if ($Spn.PasswordCredentials.Count -ne 0 -or $Spn.KeyCredentials.Count -ne 0) { Write-Host 'Application Display Name::'$Spn.DisplayName Write-Host 'Application Password Count::' $Spn.PasswordCredentials.Count Write-Host 'Application Key Count::' $Spn.KeyCredentials.Count Write-Host '' } }