One IP Address Authenticated to Seven Accounts in Nine Minutes
The first alert belonged to one user.
A successful sign-in had appeared from an unfamiliar IP address.
It would have been easy to investigate that account, reset the password and close the incident.
Agent Foskett searched the IP address instead.
Seven different accounts had authenticated from it in nine minutes.

Pivot On The Infrastructure
Sometimes the user is only the first clue. The source IP can reveal how many identities belong to the same incident.
The first sign-in did not look like a tenant-wide incident
Start with the successful sign-in
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
let User = "alex@contoso.com";
SigninLogs
| where TimeGenerated > ago(24h)
| where UserPrincipalName =~ User
| where ResultType == 0
| project TimeGenerated,
UserPrincipalName,
IPAddress,
AppDisplayName,
ClientAppUsed,
ConditionalAccessStatus,
DeviceDetail,
LocationDetails
| order by TimeGenerated descNow reverse the investigation
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
let SuspiciousIP = "203.0.113.44";
SigninLogs
| where TimeGenerated > ago(24h)
| where IPAddress == SuspiciousIP
| project TimeGenerated,
UserPrincipalName,
ResultType,
ResultDescription,
AppDisplayName,
ClientAppUsed,
ConditionalAccessStatus,
DeviceDetail
| order by TimeGenerated ascSeven accounts appeared in nine minutes
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
let SuspiciousIP = "203.0.113.44";
SigninLogs
| where TimeGenerated > ago(24h)
| where IPAddress == SuspiciousIP
| summarize Attempts = count(),
Successful = countif(ResultType == 0),
Failed = countif(ResultType != 0),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by UserPrincipalName
| order by FirstSeen ascMeasure the behaviour, not just the count
Find IPs touching many identities
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
SigninLogs
| where TimeGenerated > ago(24h)
| summarize Users = dcount(UserPrincipalName),
UserList = make_set(UserPrincipalName, 50),
Attempts = count(),
Successful = countif(ResultType == 0),
Failed = countif(ResultType != 0),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by IPAddress, bin(TimeGenerated, 15m)
| where Users >= 5
| order by Users desc
