Forum Discussion

nt20111290's avatar
nt20111290
Copper Contributor
Mar 22, 2023

Microsoft Defender - Advanced Hunting API

Hello!

 

I am looking into utilizing the Advanced Hunting API to search for emails sent by a specific IP / sender / sender domain. Within the Advanced Hunting console, I am able to carry out the following query without any issues:

 

EmailEvents | where Timestamp > ago(1d)
| where SenderIPv4 contains 'x.x.x.x' | take 1
 
However, I need to do a search against a large number of emails addresses / IPs, hence looking into
using the API to do some sort of loop with PowerShell. I followed the steps here to create an app:
https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/exposed-apis-create-app-nativeapp?view=o365-worldwide
and gave the app the correct permission of "WindowsDefenderATP -> AdvancedQuery.Read.All".
 
When using PowerShell, I can generate a bearer token without any issues, but when attempting to execute the query above,
I receive this error:
 
Invoke-WebRequest : The remote server returned an error: (400) Bad Request
 
Using Postman, I see a slightly more detailed error message:
 
"code": "BadRequest",
"message": "'table' operator: Failed to resolve table expression named 'EmailEvents'. Fix semantic errors in your query.
 
However, if I changed the query to for example:
 
"DeviceEvents | take 1"
 
It works without any issues. My organization currently has a mixture of A5 (E5 equivalent) and A1 licenses, so license wise I don't believe it is an issue.
 
Any suggestions on how to fix this would be great. Alternatively, if you have a different method of pulling email activities for multiple IPs / senders, let me know.
My end goal is to see if IPs / senders added to an anti-spam policy are still being in used in the last X days, and if not, remove it.
 
Thank you
 

4 Replies

  • nt20111290's avatar
    nt20111290
    Copper Contributor

    After doing some more digging, I was able to get it working. There were a few issues, I was not using the correct endpoint. Additionally, my permissions were not setup correctly as the permissions stated on MS documents were not the ones that I was supposed to use.

    Once you create the OAUTH app under "App registrations", make sure to add the "Microsoft Threat Protection -> AdvancedHunting.Read.All" API permission. This is the code that I used:

    $tenantId = '[TENANT_ID]'
    $appId = '[APP_ID]'
    $appSecret = '[APP_SECRET]'
    
    $resourceAppIdUri = 'https://api.security.microsoft.com'
    $oAuthUri = "https://login.windows.net/$tenantId/oauth2/token"
    
    $authBody = [Ordered] @{
        resource = $resourceAppIdUri
        client_id = $appId
        client_secret = $appSecret
        grant_type = 'client_credentials'
    }
    
    $authResponse = Invoke-RestMethod -Method Post -Uri $oAuthUri -Body $authBody -ErrorAction Stop
    $token = $authResponse.access_token
    
    $headers = @{ 
        'Content-Type' = 'application/json'
        Accept = 'application/json'
        Authorization = "Bearer $token" 
    }
    
    # This assumes the .csv file has a column named 'AllowedSenders'
    $AntiSpamInboundSenders = (Import-CSv -Path "C:\PATH_TO_CSV_FILE").AllowedSenders
    
    # By default, the API can only pull data for the last 30 days
    foreach ($Sender in $AntiSpamInboundSenders){
        Write-Host ("-" * 100) -ForegroundColor Yellow
        Write-Host "Checking $Sender"
        
        # Search by sender domain
        $query = "EmailEvents | where SenderMailFromDomain contains '$Sender' | where Timestamp > ago(30d) | take 1"
        # Search by sender
        # $query = "EmailEvents | where SenderMailFromAddress contains '$Sender' or SenderFromAddress contains '$Sender' | where Timestamp > ago(30d) | take 1"
        
        # Search by IP
        #$query = "EmailEvents | where SenderIPv4 contains '$IP' | where Timestamp > ago(30d) | take 1"
        $body = ConvertTo-Json -InputObject @{ 'Query' = $query }
    
        $queryUrl = "https://api.security.microsoft.com/api/advancedhunting/run"
        $webResponse = Invoke-WebRequest -Method Post -Uri $queryUrl -Headers $headers -Body $body -ErrorAction Stop
        $Response =  ($webResponse | ConvertFrom-Json).Results
    
        if ($Response){
            $Sender = $Response.SenderFromAddress
            $RecipientEmailAddress = $Response.RecipientEmailAddress
            $Timestamp = $Response.Timestamp
            $Subject = $Response.Subject
    
            Write-Host $Sender
            Write-Host $RecipientEmailAddress
            Write-Host $Timestamp
            Write-Host $Subject
            
        }else{
            Write-Host "No results" -ForegroundColor Red
        }
        Start-Sleep -Seconds 1 # This is to reduce the number of queries sent to not go over the API limit request
    }

     I hope this is useful.

  • GrahamP67's avatar
    GrahamP67
    Copper Contributor

    I am having this exact same issues when trying the query 'EmailAttachmentInfo | limit 10'  I get a 400 but if i change the query to 'DeviceRegistryEvents | limit 10' the script runs ok.

     

    Odd thing is in Defender I cant see the schema DeviceRegistryEvents.

     

    DId you ever find a fix, is it permissions related?

     

Resources