In this module

AD6.2 The Compromised Account Procedure

5-6 hours · Module 6 · Free
Operational Objective
A confirmed credential compromise is the most common security incident an IT administrator will handle. The attacker has valid credentials — obtained through phishing, password spray, token theft, or infostealer malware — and has signed in to the user's M365 account. Every minute of access allows the attacker to read emails, download documents, create forwarding rules, register MFA methods, and prepare for lateral movement or financial fraud. This subsection provides the complete 5-step response procedure: revoke sessions, reset password, review MFA, remove persistence, and report. Each step includes the exact PowerShell commands and portal navigation, the expected outcomes, and verification that the step worked.
Deliverable: A printed, tested 5-step compromised account response procedure with PowerShell commands — ready to execute within 10 minutes of confirming a credential compromise.
Estimated completion: 35 minutes
COMPROMISED ACCOUNT — 5-STEP PROCEDURE 1. REVOKE Revoke all active sessions and tokens Kicks attacker out NOW 1 min 2. RESET Reset password to random strong password Prevents re-entry 1 min 3. REVIEW MFA Check MFA methods Remove attacker devices Removes persistence 3 min 4. REMOVE Remove inbox rules, OAuth apps, delegates Removes all persistence 3 min 5. REPORT Document timeline Notify manager Classify incident 5 min

Figure AD6.2 — The 5-step compromised account procedure. Revoke (1 min) → Reset (1 min) → Review MFA (3 min) → Remove persistence (3 min) → Report (5 min). Total: ~13 minutes from confirmation to containment plus documentation. Print this procedure and keep it accessible.

Step 1: Revoke all sessions (1 minute)

The moment you confirm a credential compromise, revoke the user's sessions. This terminates every active session — browser, Outlook, mobile apps, Teams — immediately.

PowerShell (fastest):

Connect-MgGraph -Scopes "User.ReadWrite.All"
$user = "r.williams@northgateeng.com"
Revoke-MgUserSignInSession -UserId $user
Write-Host "All sessions revoked for $user at $(Get-Date)"

Portal (if PowerShell isn't available): Navigate to entra.microsoft.com → Users → search for the user → select the user → "Revoke sessions" button at the top of the user page.

Verification: After revoking, the user is forced to re-authenticate on all devices. If the attacker has a stolen token, the token is invalidated. If the attacker has an active browser session, the session terminates. The user will need to sign in again with the NEW password (which you reset in step 2) and complete MFA.

What this does NOT do: Revoking sessions doesn't change the password. It doesn't remove MFA methods. It doesn't delete inbox rules. Those are separate steps. Session revocation is the emergency stop — it removes the attacker's immediate access.

Important AiTM note: For AiTM attacks where the attacker has a captured refresh token, session revocation invalidates the token. However, if the attacker has already used the refresh token to obtain a new access token (within the 1-hour access token lifetime), that specific access token may remain valid for up to 1 hour. Continuous Access Evaluation (CAE), if enabled in your tenant, can shorten this window to near-real-time. Check whether CAE is enabled: entra.microsoft.com → Protection → Conditional Access → Session → Continuous access evaluation.

Step 2: Reset password (1 minute)

Immediately after revoking sessions, reset the user's password to a random, strong password.

# Generate a random password
$newPwd = -join ((65..90) + (97..122) + (48..57) + (33,35,36,37,38,42) | Get-Random -Count 20 | ForEach-Object { [char]$_ })
$passwordProfile = @{
    password = $newPwd
    forceChangePasswordNextSignIn = $true
}
Update-MgUser -UserId $user -PasswordProfile $passwordProfile
Write-Host "Password reset for $user. Temp password: $newPwd"
Write-Host "User will be forced to change on next sign-in."

Portal: entra.microsoft.com → Users → select user → "Reset password."

Important: Set "forceChangePasswordNextSignIn" to true. This means the temporary password is only used once — the user creates a new password on their next sign-in. Don't communicate the temporary password via email to the compromised account (the attacker could read it). Send it via Teams message, phone call, or in-person. If the user's Teams is also compromised (possible if the attacker has a session), communicate via phone call.

Verification: After the password reset, the attacker cannot sign in with the old password. Combined with session revocation (step 1), the attacker has no current access and no way to re-enter.

Step 3: Review and clean MFA methods (3 minutes)

Check what MFA methods are registered for the user. Attackers who compromise an account often register a new MFA method (a phone number or authenticator app on their device) to maintain persistent access after a password reset.

# List all MFA methods for the user
Get-MgUserAuthenticationMethod -UserId $user | ForEach-Object {
    $method = $_
    $type = $method.AdditionalProperties["@odata.type"]
    Write-Host "Type: $type, ID: $($method.Id)"
    if ($type -match "phone") {
        $phone = Get-MgUserAuthenticationPhoneMethod -UserId $user -PhoneAuthenticationMethodId $method.Id
        Write-Host "  Phone: $($phone.PhoneNumber) ($($phone.PhoneType))"
    }
}

Portal: entra.microsoft.com → Users → select user → Authentication methods.

What to look for: Any MFA method the user doesn't recognize. Common attacker patterns: a new phone number registered (different country code from the user's known phone), a new Microsoft Authenticator app added (the user has one, but now there are two), or a FIDO2 key registered (the user doesn't own one).

Action: Remove any MFA method the user doesn't recognize. Confirm with the user: "You have two Authenticator apps registered. Did you add the second one?" If not, delete it. If the user only has one legitimate method and it was registered by the attacker, delete ALL methods and re-register the user's legitimate method from scratch.

# Remove a specific phone authentication method
Remove-MgUserAuthenticationPhoneMethod -UserId $user -PhoneAuthenticationMethodId "METHOD_ID_HERE"
Write-Host "Removed suspicious MFA method"

Step 4: Remove persistence mechanisms (3 minutes)

Check for attacker persistence in three areas: inbox rules, OAuth app consents, and mailbox delegates.

Inbox rules (the most common BEC persistence):

Connect-ExchangeOnline
Get-InboxRule -Mailbox $user | Select-Object Name, Enabled, ForwardTo,
    ForwardAsAttachmentTo, RedirectTo, DeleteMessage, MoveToFolder |
    Format-List

Look for rules that forward, redirect, or delete emails. Legitimate user rules exist (e.g., "Move newsletters to folder"). Attacker rules typically: forward emails matching financial keywords to external addresses, delete emails from specific senders (to hide evidence of their activity), or move emails to RSS Subscriptions or Conversation History folders (folders users never check).

Delete any suspicious rules:

# Remove a specific inbox rule
Remove-InboxRule -Mailbox $user -Identity "RULE_NAME_HERE" -Confirm:$false
Write-Host "Removed inbox rule: RULE_NAME_HERE"

OAuth app consents:

# Check OAuth app permissions granted by the user
Get-MgUserOauth2PermissionGrant -UserId $user | Select-Object ClientId,
    ConsentType, Scope, PrincipalId | Format-Table

Look for app consents you don't recognize — particularly apps with broad permissions (Mail.Read, Mail.ReadWrite, Files.ReadWrite.All). Attackers use consent phishing to maintain access through an OAuth app even after password resets. Remove suspicious consents:

Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId "GRANT_ID_HERE"

Mailbox delegates:

Get-MailboxPermission -Identity $user | Where-Object {
    $_.User -ne "NT AUTHORITY\SELF" -and $_.IsInherited -eq $false
} | Format-Table User, AccessRights

Look for unexpected users with FullAccess, SendAs, or SendOnBehalf permissions. Attackers sometimes add delegate access to maintain mailbox visibility after the compromised user's password is reset.

Step 5: Report and document (5 minutes)

Record the incident timeline and actions taken. Use this template:

Incident Report — Compromised Account

  • User: r.williams@northgateeng.com
  • Discovered: Monday 14 Apr 2026, 09:15 (Monday security review)
  • Initial compromise: Sunday 13 Apr 2026, ~02:00 (based on sign-in log)
  • Method: AiTM phishing — sign-in from IP 198.51.100.22 (Eastern Europe), MFA satisfied by claim
  • Attacker activity: 2 inbox rules created (forwarding "invoice" and "payment" emails to ext.address@proton.me), 47 emails read
  • Containment actions:

- 09:16 — Sessions revoked (Revoke-MgUserSignInSession) - 09:17 — Password reset (force change on next sign-in) - 09:19 — MFA methods reviewed — 1 suspicious phone number removed - 09:22 — 2 inbox rules removed (Remove-InboxRule) - 09:23 — OAuth consents reviewed — none suspicious - 09:24 — Mailbox delegates reviewed — none suspicious

  • Data exposure: 47 emails read. 3 emails forwarded to external address before rules removed. Forwarded emails contained vendor invoices with bank details.
  • Escalation: Manager notified at 09:30. Legal notified re potential data breach (vendor bank details exposed).
  • Status: Contained. User password reset. Attacker access terminated.

Email this report to your manager. File it in your incident log. Classify the Defender portal incident as True Positive with a comment referencing this report.

Compliance Myth: "Just resetting the password is enough to secure a compromised account"
Password reset alone leaves three attack vectors open. First, active sessions continue using existing tokens — the attacker remains signed in until the token expires (up to 1 hour without CAE). Second, attacker-registered MFA methods survive a password reset — the attacker re-authenticates with their own MFA device. Third, inbox rules, OAuth consents, and mailbox delegates persist through password resets — the attacker's forwarding rule continues sending emails to the external address indefinitely. The full 5-step procedure (revoke + reset + MFA + persistence + report) addresses all five vectors. Password reset alone addresses one.
Decision point

During Step 3 (MFA review), you discover that the compromised user has three MFA methods registered: their legitimate phone (UK number), a second phone (Nigerian number they don't recognize), and a Microsoft Authenticator app they don't recall adding. What do you do?

Option A: Remove only the Nigerian phone number — it's obviously the attacker's.

Option B: Remove the Nigerian phone number AND the unrecognized Authenticator app. Leave only the user's legitimate UK phone number. Then have the user re-register their preferred Authenticator app from their legitimate device in your presence (or via a confirmed video call). The unrecognized Authenticator app may be the attacker's device — removing it ensures only the user's legitimate devices can complete MFA.

The correct answer is Option B. Remove everything the user doesn't explicitly recognize. The Authenticator app could be registered on the attacker's phone — leaving it would allow the attacker to re-authenticate even after the password reset. Better to remove it and have the user re-register than to leave a potentially compromised MFA method in place. The inconvenience of re-registration takes 2 minutes. The risk of leaving the attacker's MFA method takes another incident.

Try it: Test the compromised account procedure on a test account

Create a test user in your tenant (or use an existing test account). Execute the full 5-step procedure:

1. Revoke sessions: Revoke-MgUserSignInSession -UserId testuser@yourdomain.com 2. Reset password: Update-MgUser -UserId testuser@yourdomain.com -PasswordProfile @{password="TempP@ss2026!"; forceChangePasswordNextSignIn=$true} 3. Review MFA: Get-MgUserAuthenticationMethod -UserId testuser@yourdomain.com 4. Check inbox rules: Get-InboxRule -Mailbox testuser@yourdomain.com 5. Check OAuth consents: Get-MgUserOauth2PermissionGrant -UserId testuser@yourdomain.com

Time the exercise. Your target: under 10 minutes for all 5 steps. After practising on a test account, you'll execute the procedure confidently on a real compromised account without hesitation.

Save the PowerShell commands as C:\SecurityScripts\Respond-CompromisedAccount.ps1. When a real incident occurs, run the script with the compromised user's UPN as a parameter.

After completing all 5 steps of the compromised account procedure, how do you verify that the attacker no longer has access?
Check the sign-in log for the compromised user over the next 24 hours. If no new sign-ins appear from unfamiliar IPs, the containment was successful. If a new sign-in appears from the same attacker IP or a new unfamiliar IP, something was missed — re-execute the procedure and check for additional persistence you didn't catch — Correct. Post-containment monitoring confirms the procedure worked. A new sign-in after the procedure means the attacker found a persistence method you didn't remove (an OAuth app, a secondary compromised account, or a token that wasn't properly revoked).
Ask the user if anything looks different — The user may not notice subtle changes like a new MFA method or an inbox rule. Technical verification is required.
No verification needed — the 5 steps cover everything — The procedure covers the most common persistence methods, but sophisticated attackers may use methods not covered (e.g., OAuth apps with long-lived tokens, compromised service principals). Post-containment monitoring is essential.
Wait for the next Monday review — if nothing appears, it worked — 7 days is too long to verify containment. Check the sign-in log daily for 2-3 days after the procedure.

Saving the procedure as a runnable script

Combine the core AD6.2 steps into a single parameterised PowerShell script:

# Respond-CompromisedAccount.ps1
param([Parameter(Mandatory)][string]$UserUPN)

Write-Host "=== COMPROMISED ACCOUNT RESPONSE ===" -ForegroundColor Red
Write-Host "User: $UserUPN | Started: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"

Connect-MgGraph -Scopes "User.ReadWrite.All" -NoWelcome

# Step 1: Revoke sessions
Revoke-MgUserSignInSession -UserId $UserUPN
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Step 1 DONE: Sessions revoked" -ForegroundColor Green

# Step 2: Reset password
$newPwd = -join ((65..90)+(97..122)+(48..57)+(33,35,36,37) | Get-Random -Count 16 | ForEach-Object {[char]$_})
Update-MgUser -UserId $UserUPN -PasswordProfile @{password=$newPwd; forceChangePasswordNextSignIn=$true}
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Step 2 DONE: Password reset. Temp: $newPwd" -ForegroundColor Green

# Step 3: List MFA methods
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Step 3: Review MFA methods below:" -ForegroundColor Yellow
Get-MgUserAuthenticationMethod -UserId $UserUPN | ForEach-Object {
    Write-Host "  $($_.AdditionalProperties['@odata.type']) | ID: $($_.Id)"
}

# Step 4: Check inbox rules
Connect-ExchangeOnline -ShowBanner:$false
Write-Host "[$(Get-Date -Format 'HH:mm:ss')] Step 4: Inbox rules:" -ForegroundColor Yellow
$rules = Get-InboxRule -Mailbox $UserUPN | Where-Object { $_.ForwardTo -or $_.RedirectTo -or $_.DeleteMessage }
if ($rules) { $rules | Format-List Name,ForwardTo,RedirectTo,DeleteMessage }
else { Write-Host "  No suspicious rules found" -ForegroundColor Green }

Write-Host "`nStep 5: Document in incident report template. Communicate temp password via phone/SMS."

Save as C:\SecurityScripts\Respond-CompromisedAccount.ps1. During an incident, run: .\Respond-CompromisedAccount.ps1 -UserUPN r.williams@northgateeng.com. Steps 1-4 execute in under 3 minutes. Review MFA and rules output, take manual action on findings, then complete step 5 (documentation).

You're reading the free modules of M365 Security: From Admin to Defender

The full course continues with advanced topics, production detection rules, worked investigation scenarios, and deployable artifacts.

View Pricing See Full Syllabus