A user reports a suspicious email. Or Defender fires an alert for a risky sign-in. Or — more likely — someone in finance asks why the CEO sent them a wire transfer request from a Gmail address at 2am.
The investigation always starts in the same place: the Entra ID sign-in logs. Not because that's where the most evidence is, but because the sign-in log answers the question that determines everything else — how did the attacker authenticate, and why did your security controls let them in?
Step 1: Identify the compromise sign-in
The sign-in log records every authentication attempt with the source IP, device details, application accessed, Conditional Access evaluation result, MFA status, and risk score. Your first query establishes the timeline.
SigninLogs
| where TimeGenerated > ago(7d)
| where UserPrincipalName == "compromised.user@contoso.com"
| where ResultType == 0
| project TimeGenerated, IPAddress,
Location = tostring(LocationDetails.city),
AppDisplayName,
AuthenticationRequirement,
ConditionalAccessStatus,
DeviceDetail,
RiskLevelDuringSignIn,
UserAgent
| sort by TimeGenerated ascYou're looking for the transition point — the first successful sign-in from an unfamiliar IP or with an unfamiliar user agent. Everything before that is the legitimate user. Everything from that point forward is the investigation window.
Three fields tell you the attack method immediately. If AuthenticationRequirement shows MFA was satisfied from an attacker IP, you're dealing with AiTM phishing or token theft — the attacker intercepted or replayed a valid session. If MFA was not required, Conditional Access has a gap. If MFA failed repeatedly and then succeeded, that's MFA fatigue — the user approved the push after being bombarded.
The ConditionalAccessStatus field is equally important. If it shows "success" for the attacker's sign-in, your Conditional Access policies evaluated the sign-in and passed it. That's a policy design failure you need to fix after containment. If it shows "notApplied," no policy matched at all — which means the application or conditions weren't covered by any policy.
Step 2: Map the post-compromise activity
Once you've identified the compromise window, you need to know what the attacker did with the access. The three tables that answer this are AuditLogs, OfficeActivity, and CloudAppEvents.
AuditLogs
| where TimeGenerated > ago(7d)
| where InitiatedBy.user.userPrincipalName
== "compromised.user@contoso.com"
or TargetResources[0].userPrincipalName
== "compromised.user@contoso.com"
| project TimeGenerated, OperationName,
Category, Result,
Target = tostring(
TargetResources[0].displayName),
ModifiedProps = tostring(
TargetResources[0].modifiedProperties)
| sort by TimeGenerated ascThis query returns every administrative action the compromised account performed — MFA method registration, device registration, application consent, group membership changes, role assignments, and password resets. Each operation has an investigation significance.
The most critical operations to look for in the first pass: "User registered security info" (new MFA method — the attacker's persistence), "Consent to application" (OAuth persistence), "Add registered owner to device" or "Register device" (device registration — bypasses Conditional Access device compliance policies), and "New-InboxRule" or "Set-Mailbox" with ForwardingSmtpAddress (email forwarding — the BEC setup).
Step 3: Find all persistence mechanisms
This is the step most teams skip. They see the compromise, reset the password, revoke sessions, and close the ticket. The attacker re-authenticates the next morning using the MFA method they registered during the 30 minutes they had access.
Every persistence mechanism must be enumerated before containment. Miss one and the attacker returns.
// MFA methods registered during the compromise window
AuditLogs
| where TimeGenerated between
(datetime(2026-05-01T08:00:00Z)
.. datetime(2026-05-01T12:00:00Z))
| where OperationName has_any
("authentication method",
"registered security info",
"strongAuthenticationPhoneAppDetail")
| where TargetResources[0].userPrincipalName
== "compromised.user@contoso.com"
or InitiatedBy.user.userPrincipalName
== "compromised.user@contoso.com"
| project TimeGenerated, OperationName,
AdditionalDetailsRun the same pattern for device registrations, OAuth consent grants, and mailbox rules. Each one is a separate persistence channel that survives a password reset.
| Persistence type | Survives password reset? | Survives session revoke? | Where to check |
|---|---|---|---|
| MFA method registration | Yes | Yes | AuditLogs |
| OAuth application consent | Yes | Yes | AuditLogs + ServicePrincipalSignInLogs |
| Device registration | Yes | Yes | AuditLogs + Device management |
| Mailbox forwarding rule | Yes | Yes | OfficeActivity |
| Inbox rules | Yes | Yes | OfficeActivity |
Every row in that table is a "yes" to both questions. That's why a password reset alone doesn't contain an identity compromise — it only removes the original access method while leaving all the persistence the attacker established during their session.
Step 4: Contain — in the right order
Containment for identity compromise has a specific sequence. Do it out of order and you alert the attacker before you've removed their persistence.
First, revoke all active sessions (Revoke-AzureADUserAllRefreshToken or the Entra admin portal). This kills the current session but does not prevent re-authentication.
Second, remove every MFA method the attacker registered. Check the Authentication Methods blade in Entra — any method added during the compromise window gets deleted.
Third, remove any devices registered during the compromise window. An attacker-registered device that shows as "Entra AD registered" will satisfy Conditional Access policies requiring device registration.
Fourth, revoke OAuth application consent for any applications granted during the compromise window. Check both user consent and admin consent grants. If the application has been authenticating independently (check AADServicePrincipalSignInLogs), it has its own credentials and will continue accessing data regardless of what you do to the user account.
Fifth, remove mailbox rules — forwarding rules, inbox rules that move or delete messages, and any SMTP forwarding configured at the mailbox level.
Sixth — now you reset the password. Not before. Every step above removes a persistence mechanism that would let the attacker re-authenticate after the reset.
The query you should run right now
Before you encounter your next identity compromise, run this on your own tenant to understand your baseline:
AuditLogs
| where TimeGenerated > ago(30d)
| where OperationName has_any
("Consent to application",
"registered security info",
"Register device",
"Add registered owner")
| summarize Count = count()
by OperationName,
bin(TimeGenerated, 1d)
| render timechartThis shows you the daily volume of persistence-class operations in your tenant. When a compromise happens, you'll know whether 3 new MFA registrations in a day is normal or an anomaly. Without that baseline, every investigation starts with the question "is this normal?" instead of "this is anomalous, here's why."
The Entra ID Security course walks through the complete identity threat landscape — every attack pattern, the defense that stops it, and the detection that catches it. The Practical Incident Response course covers the full identity compromise investigation methodology in IR8, including AiTM phishing, OAuth consent attacks, and the persistence analysis that determines containment scope. Both courses start with free modules — no account required.
What to do this week
- Run the baseline query above on your tenant. Save the output. You'll need it when the next alert fires.
- Check your Conditional Access policies for the gap that appears most often in investigations: policies that require MFA but accept "registered" devices instead of "compliant" devices. An attacker who registers their own device satisfies "registered" instantly.
- Verify that your IR runbook includes the six-step containment sequence — session revoke, MFA cleanup, device removal, OAuth revocation, mailbox rule removal, then password reset. If your runbook says "reset password and revoke sessions," it's missing four steps.
- Review the last three identity-related incidents your SOC handled. Were all persistence mechanisms checked? If the tickets were closed after a password reset, you may have unresolved persistence in your tenant right now.
Next week: Endpoint security baselines — what to harden before you deploy EDR.