Disclaimer: All research and opinions expressed here are my own and are independent of any employer or organisation.

Spike in invalid token usage (50173)

hunt-2025-037 v1.0 Entra created Paul Newton

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.

Spike in invalid token usage (50173)

This analytic looks for cases where there is a spike in invalid token usage, with a short time span. This could be indicative of mass token replay against accounts. This analytic is reliant on the error code 50173 "The provided grant has expired due to it being revoked, a fresh auth token is needed.....". This could indicate exfiltration of tokens for replay where some of the tokens have expired or are no longer valid.

KQL
let LookbackPeriod = 7d;
let BinSize = 5m;  // Tighter window to catch bursts
let MinEvents = 10;
AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(LookbackPeriod)
| where ResultType == 50173
| summarize 
    Count = count(),
    UniqueIPs = dcount(IPAddress),
    IPAddresses = make_set(IPAddress),
    UniqueTokens = dcount(UniqueTokenIdentifier),
    UniqueUsers = dcount(UserPrincipalName),
    Users = make_set(UserPrincipalName),
    Locations = make_set(Location),
    UniqueLocations = dcount(Location),
    UserAgents = make_set(UserAgent),
    ResourcesAccessed = make_set(ResourceDisplayName),
    IncomingTokenTypes = make_set(IncomingTokenType),
    FirstSeen = min(TimeGenerated),
    LastSeen = max(TimeGenerated)
    by bin(TimeGenerated, BinSize), AppDisplayName, AppId
| where Count >= MinEvents
| extend 
    TimeWindow = strcat(format_datetime(FirstSeen, 'HH:mm:ss'), " - ", format_datetime(LastSeen, 'HH:mm:ss')),
    IPLocationRatio = round(todouble(UniqueIPs) / todouble(UniqueLocations), 2),
    TokensPerIP = round(todouble(UniqueTokens) / todouble(UniqueIPs), 2)
| project 
    TimeGenerated,
    TimeWindow,
    AppDisplayName,
    AppId,
    Count,
    UniqueIPs,
    UniqueTokens,
    UniqueUsers,
    UniqueLocations,
    IPLocationRatio,
    TokensPerIP,
    IPAddresses,
    Users,
    Locations,
    UserAgents,
    ResourcesAccessed,
    IncomingTokenTypes
| order by Count desc

Triage steps

  1. 1 Review the time window and count of failed authentications - high volume in short time indicates mass replay
  2. 2 Check if there were recent password changes or token revocations for the affected users
  3. 3 Investigate the application generating the invalid token errors
  4. 4 Review if multiple users are affected or just a single account
  5. 5 Analyze the UserAgent to identify if automated tooling is being used
  6. 6 Check the IP addresses and locations to identify potential attacker infrastructure
  7. 7 Look for successful authentications before or after the spike that may indicate compromise
  8. 8 If confirmed mass replay attempt, reset credentials and revoke application access

True positive example

Example 1

TimeGenerated
06/12/2025, 19:55:00.000
TimeWindow
19:55:02 - 19:57:07
AppDisplayName
TruffleHog Test App
AppId
c32a4v3a-c5bd-4d70-b388-091430657d83
Count
86
UniqueIPs
1
UniqueTokens
86
UniqueUsers
1
UniqueLocations
1
IPLocationRatio
1
TokensPerIP
86
IPAddresses
["79.135.105.18"]
Users
["[email protected]"]
Locations
["AZ"]
UserAgents
["python-requests/2.31.0"]
ResourcesAccessed
["Microsoft Graph"]
IncomingTokenTypes
["refreshToken"]
UserDisplayName
Hunter
ResourceDisplayName
Microsoft Graph
IPAddress
79.135.105.18
Location
AZ
Browser
Python Requests 2.31
DeviceId
IncomingTokenType
refreshToken
SessionStatus
unbound

Mass replay attempt detected - 86 invalid tokens attempted in a 2-minute window from a single IP using Python automation. This pattern indicates an attacker attempting to use a large cache of stolen tokens, many of which have been revoked or expired.

Example 2

TimeGenerated
06/12/2025, 19:50:00.000
TimeWindow
19:54:24 - 19:54:57
AppDisplayName
TruffleHog Test App
AppId
ca2a4f3a-c6bd-4b70-b888-0914b0657d83
Count
13
UniqueIPs
1
UniqueTokens
13
UniqueUsers
1
UniqueLocations
1
IPLocationRatio
1
TokensPerIP
13
IPAddresses
["79.135.105.18"]
Users
["[email protected]"]
Locations
["AZ"]
UserAgents
["python-requests/2.31.0"]
ResourcesAccessed
["Microsoft Graph"]
IncomingTokenTypes
["refreshToken"]
UserDisplayName
Hunter
ResourceDisplayName
Microsoft Graph
IPAddress
79.135.105.18
Location
AZ
Browser
Python Requests 2.31
DeviceId
IncomingTokenType
refreshToken
SessionStatus
unbound

Smaller burst of 13 invalid token attempts in 33 seconds. While lower volume than the previous spike, the rapid-fire automation pattern is consistent with credential stuffing or token replay attacks from compromised application data.

Back to all hunts