Microsoft 365 Defender Advanced Hunting with PowerShell
Hi All,
You might already know, that i am a big Fan of Defender for Office 365 Advanced Hunting.
It's easy and fast to analyze the last 30 Days of your Messaging Logs.
Defender for Office 365 Advanced Hunting
I've published some of the KQL Querys in my GitHub Rpo
You can find Advanced Hunting it in de Microsoft 365 Defender Portal
To Access these Querys with PowerShell we need to have an Azure Active Directory Application
It's documented by the following Links, how to Access these API's.
Access the Microsoft 365 Defender APIs
Microsoft 365 Defender Advanced hunting API
You need to select "APIs my organization uses" and search for "Microsoft Threat Protection"
For Delegated permissions you need "AdvancedHunting.Read" Permission
For Aplication permissions you need "AdvancedHunting.Read.All" Permission
After that you need to Admin Consent (Global Administrator / Application Administrator / Cloud Application Administrator)
Note: The code of this Script has also been published to my GitHub Repo
First we need to get an Access Token.I use the MSAL.PS PowerShell Module.To inspect the Token i use the JWTDetails PowerShell Module
Install-Module MSAL.PS
Install-Module JWTDetails
Install-Module JWTDetails
This is the Code to Authenticate with MSAL.PS with the Certificate where i have the private Key from my Current User Certificate Store. Note that i use a Scope to get the Token.
#Application Authentication
$AppId = "23299ad3-9e6f-4390-a121-1e5a394a6914" #PSSecurity
$TenantId = "icewolfch.onmicrosoft.com"
$ThumbPrint = "07EFF3918F47995EB53B91848F69B5C0E78622FD"
$Certificate = Get-ChildItem Cert:\CurrentUser\My\ | Where-Object {$_.Thumbprint -eq $ThumbPrint}
Import-Module MSAL.PS
Clear-MsalTokenCache
$Scopes = "https://api.security.microsoft.com/.default"
$Token = Get-MsalToken -ClientId $AppId -ClientCertificate $Certificate -TenantId $TenantId -Scopes $Scopes
$AccessToken = $Token.AccessToken
Get-JWTDetails -token $AccessToken
$AppId = "23299ad3-9e6f-4390-a121-1e5a394a6914" #PSSecurity
$TenantId = "icewolfch.onmicrosoft.com"
$ThumbPrint = "07EFF3918F47995EB53B91848F69B5C0E78622FD"
$Certificate = Get-ChildItem Cert:\CurrentUser\My\ | Where-Object {$_.Thumbprint -eq $ThumbPrint}
Import-Module MSAL.PS
Clear-MsalTokenCache
$Scopes = "https://api.security.microsoft.com/.default"
$Token = Get-MsalToken -ClientId $AppId -ClientCertificate $Certificate -TenantId $TenantId -Scopes $Scopes
$AccessToken = $Token.AccessToken
Get-JWTDetails -token $AccessToken
Note that under Roles the "AdvancedHunting.Read.All" Permission is visible.
Now i can create the Query
#KQL Query Multiline
$query = @'
//TOP 10 URL Domains
EmailUrlInfo
| summarize count() by UrlDomain
| top 10 by count_
'@
$query = @'
//TOP 10 URL Domains
EmailUrlInfo
| summarize count() by UrlDomain
| top 10 by count_
'@
I have th add the AccessToken to the Header and convert the Body to JSON to include the KQL Query as JSON.
Then a HTTP Post can be invoked
$uri = "https://api.security.microsoft.com/api/advancedhunting/run"
$Headers = @{
"Content-Type" = "application/json"
"Authorization" = "Bearer "+ $AccessToken
}
$Body = ConvertTo-Json -InputObject @{ 'Query' = $query }
$Response = Invoke-RestMethod -Method Post -Uri $uri -Headers $Headers -Body $Body
If ($Null -ne $Response)
{
$Response.Results
}
If you want to use delegated Authentication (Authenicate as User) you still need the App.
#Delegated Authentication
$AppId = "23299ad3-9e6f-4390-a121-1e5a394a6914" #PSSecurity
$TenantId = "icewolfch.onmicrosoft.com"
Import-Module MSAL.PS
Clear-MsalTokenCache
$Scopes = "https://api.security.microsoft.com/.default"
$Token = Get-MsalToken -ClientId $AppId -TenantId $TenantId -Scopes $Scopes
$AccessToken = $Token.AccessToken
Get-JWTDetails -token $AccessToken
$AppId = "23299ad3-9e6f-4390-a121-1e5a394a6914" #PSSecurity
$TenantId = "icewolfch.onmicrosoft.com"
Import-Module MSAL.PS
Clear-MsalTokenCache
$Scopes = "https://api.security.microsoft.com/.default"
$Token = Get-MsalToken -ClientId $AppId -TenantId $TenantId -Scopes $Scopes
$AccessToken = $Token.AccessToken
Get-JWTDetails -token $AccessToken
Note that under scp the "AdvancedHunting.Read" Permission is visible and also the UPN of the Account that has logged in.
The Query remains the same
#KQL Query Multiline
$query = @'
//TOP 10 URL Domains
EmailUrlInfo
| summarize count() by UrlDomain
| top 10 by count_
'@
$uri = "https://api.security.microsoft.com/api/advancedhunting/run"
$Headers = @{
"Content-Type" = "application/json"
"Authorization" = "Bearer "+ $AccessToken
}
$Body = ConvertTo-Json -InputObject @{ 'Query' = $query }
$Response = Invoke-RestMethod -Method Post -Uri $uri -Headers $Headers -Body $Body
If ($Null -ne $Response)
{
$Response.Results
}
$query = @'
//TOP 10 URL Domains
EmailUrlInfo
| summarize count() by UrlDomain
| top 10 by count_
'@
$uri = "https://api.security.microsoft.com/api/advancedhunting/run"
$Headers = @{
"Content-Type" = "application/json"
"Authorization" = "Bearer "+ $AccessToken
}
$Body = ConvertTo-Json -InputObject @{ 'Query' = $query }
$Response = Invoke-RestMethod -Method Post -Uri $uri -Headers $Headers -Body $Body
If ($Null -ne $Response)
{
$Response.Results
}
And that's how you use PowerShell to Invoke KQL Querys in Microsoft 365 Defender Advanced Huniting.
Now it's your turn. Happy Hunting😊
Regards
Andres Bohren