hunt-2025-035 v1.0 by Paul Newton

Sensitive Keyword Search via Graph

Platform

Entra

Data Sources

AADNonInteractiveUserSignInLogs MicrosoftGraphActivityLogs

MITRE ATT&CK

Tactics

Defense Evasion

Techniques

Threat Actors

APT29/CozyBear/MidnightBlizzard

Tags

#entra #cloud #identity #oauth

Hunt Hypothesis

Threat Actors will use token theft as a means of initial access, privilege escalation and persistence. Poorly secured tokens by third parties can increase the risk of token theft and replay.

Sensitive Keyword Search via Graph

Analytic #1

This looks for sensitive key words being searched across mail, files and sharepoint via the GraphAPI. Utilises Graph API activity logs.

Detection Queries

KQL
let SensitiveKeywords = dynamic(["password", "secret", "confidential", "credentials", "api key", "apikey", "token", "private", "sensitive", "internal", "restricted", "ssn", "social security", "credit card"]);
let GraphSearches = 
MicrosoftGraphActivityLogs
| where RequestUri contains "/messages" and RequestUri contains "%24search"
  or RequestUri contains "/drive/root/search"
  or RequestUri contains "/drive/" and RequestUri contains "search"
  or RequestUri contains "/sites" and RequestUri contains "search"
  or RequestUri contains "/search/query"
| extend DecodedUri = url_decode(RequestUri)
| where DecodedUri has_any (SensitiveKeywords)
| extend SearchTerm = case(
  RequestUri contains "%24search", extract(@'%24search=([^&]*)', 1, RequestUri),
  RequestUri contains "/search(q=", extract(@'/search\(q=''([^'']*)', 1, RequestUri),
  RequestUri contains "/search?q=", extract(@'/search\?q=([^&]*)', 1, RequestUri),
  "")
| extend DecodedSearchTerm = url_decode(SearchTerm)
| extend ResourceType = case(
  RequestUri contains "/messages", "Email",
  RequestUri contains "/drive", "OneDrive/SharePoint Files",
  RequestUri contains "/sites", "SharePoint Sites",
  "Other");
let AADLogs = 
AADNonInteractiveUserSignInLogs
| project AppId, UserId, Identity, AppDisplayName, AADLocation = Location;
GraphSearches
| join kind=leftouter (AADLogs) on AppId, UserId
| project TimeGenerated, SignInActivityId, Identity, AppDisplayName, IPAddress, UserAgent, 
    ResourceType, RequestMethod, DecodedUri, DecodedSearchTerm, ResponseStatusCode, 
    Location, AADLocation
| order by TimeGenerated desc

Triage Steps

  1. Review the specific sensitive keywords being searched for in the alert
  2. Identify which resource type was targeted (Email, OneDrive, SharePoint)
  3. Check if the user has a legitimate business reason to search for sensitive terms
  4. Investigate the application making the requests and verify it's authorized
  5. Review the UserAgent to identify if automated tooling is being used
  6. Check the response codes to see if the searches were successful
  7. Look for patterns of multiple sensitive keyword searches in a short timeframe
  8. If malicious, investigate what data may have been accessed and consider revoking app access

True Positive Example

Example 1

Log Entry:
{
  "TimeGenerated": "06/12/2025, 14:13:48.444",
  "SignInActivityId": "70ObFHiCDUW42aMM2OEcAA",
  "Identity": "Hunter",
  "AppDisplayName": "TruffleHog Test App",
  "IPAddress": "79.135.105.18",
  "UserAgent": "data_exfil_tool",
  "ResourceType": "Email",
  "RequestMethod": "GET",
  "DecodedUri": "https://graph.microsoft.com/v1.0/me/messages?$search=\"secret\"&$select=subject,from,receivedDateTime,hasAttachments,bodyPreview&$top=5",
  "DecodedSearchTerm": "\"secret\"",
  "ResponseStatusCode": "200",
  "Location": "UAE North",
  "AADLocation": "AZ"
}
Analysis:

Attacker searching user emails for the keyword 'secret' via Graph API. The custom UserAgent 'data_exfil_tool' and successful 200 response indicates automated credential harvesting activity.

Example 2

Log Entry:
{
  "TimeGenerated": "06/12/2025, 14:13:48.444",
  "SignInActivityId": "70ObFHiCDUW42aMM2OEcAA",
  "Identity": "Hunter",
  "AppDisplayName": "TruffleHog Test App",
  "IPAddress": "79.135.105.18",
  "UserAgent": "data_exfil_tool",
  "ResourceType": "Email",
  "RequestMethod": "GET",
  "DecodedUri": "https://graph.microsoft.com/v1.0/me/messages?$search=\"secret\"&$select=subject,from,receivedDateTime,hasAttachments,bodyPreview&$top=5",
  "DecodedSearchTerm": "\"secret\"",
  "ResponseStatusCode": "200",
  "Location": "UAE North",
  "AADLocation": "AZ"
}
Analysis:

Multiple searches for sensitive keywords across email indicates systematic data reconnaissance. The attacker is likely building a profile of sensitive information accessible via the compromised token.

Example 3

Log Entry:
{
  "TimeGenerated": "06/12/2025, 13:43:51.184",
  "SignInActivityId": "70ObFHiCDUW42aMM2OEcAA",
  "Identity": "Hunter",
  "AppDisplayName": "TruffleHog Test App",
  "IPAddress": "79.135.105.18",
  "UserAgent": "data_exfil_tool",
  "ResourceType": "Email",
  "RequestMethod": "GET",
  "DecodedUri": "https://graph.microsoft.com/v1.0/me/messages?$search=\"confidential\"&$select=subject,from,receivedDateTime,hasAttachments,bodyPreview&$top=5",
  "DecodedSearchTerm": "\"confidential\"",
  "ResponseStatusCode": "200",
  "Location": "Poland Central",
  "AADLocation": "AZ"
}
Analysis:

Continuation of keyword-based email searches, now targeting 'confidential' content. The pattern of searching for various sensitive terms suggests an organized data exfiltration campaign.