11.7 Containment

4-6 hours · Module 11

Containment

The investigation confirmed compromised accounts with active attacker sessions. Containment stops the bleeding — it cuts the attacker’s access. Every action in this subsection has a blast radius and a rollback procedure because containment actions affect real users in a production environment.

The containment order matters. Execute in this sequence:

Required role: User Administrator (for password reset), Authentication Administrator (for MFA and token revocation), or Global Administrator. If you do not have these roles, escalate to someone who does — containment cannot wait for an access request approval cycle.


Action 1: Revoke all refresh tokens

This is the highest-priority containment action. It invalidates the attacker’s stolen tokens.

Execute: For each confirmed compromised account:

1
2
3
4
5
// PowerShell  revoke all refresh tokens
// Connect-MgGraph -Scopes "User.ReadWrite.All"
// Revoke-MgUserSignInSession -UserId "j.morrison@northgateeng.com"
// Revoke-MgUserSignInSession -UserId "s.chen@northgateeng.com"
// Revoke-MgUserSignInSession -UserId "a.patel@northgateeng.com"

Or via the Entra ID portal: Users → select user → Revoke sessions.

Blast radius: The user loses all active sessions across all devices and all M365 applications immediately. They must re-authenticate on every device and every application. This affects: Outlook desktop (re-prompts for sign-in), Teams (signs out), OneDrive sync (pauses until re-authenticated), SharePoint (session ends), mobile apps (re-prompts), and any third-party apps using Azure AD SSO. Per-user scope.

Rollback: Not reversible — you cannot un-revoke tokens. The user simply re-authenticates. There is no negative consequence beyond the temporary disruption of re-authentication.

Verify:

1
2
3
4
5
6
7
// Verify: no new sign-ins from attacker IP after revocation
SigninLogs
| where TimeGenerated > ago(30m)
| where UserPrincipalName in ("j.morrison@northgateeng.com",
    "s.chen@northgateeng.com", "a.patel@northgateeng.com")
| where IPAddress == "203.0.113.47"
| project TimeGenerated, UserPrincipalName, IPAddress, ResultType

Expected result: Zero rows. If the attacker IP still appears with ResultType 0 after revocation, the attacker has obtained a new token (possibly from a different compromise path) — escalate immediately.


Action 2: Reset passwords

After token revocation, reset the password to prevent the attacker from re-authenticating with the stolen password.

Execute: For each compromised account, reset to a strong random password. Do NOT communicate the new password via email (the attacker may still have inbox rule access — remove rules first, subsection 11.8). Use a separate channel: phone call, in-person, or SMS.

Blast radius: Same as token revocation — the user must re-authenticate with the new password on all devices. If the user has saved the password in a browser or password manager, those saved credentials become invalid. Per-user scope.

Rollback: Reset to a different password if the initial reset causes issues. There is no way to restore the previous password.

Before executing: Check whether the user account is synced from on-premises AD (hybrid environment). If yes: reset the password in on-premises AD and wait for sync (typically 30 minutes with Azure AD Connect). Resetting directly in Entra ID may cause sync conflicts.

Verify:

1
2
3
4
5
6
7
8
// Verify: password was reset (audit log confirmation)
AuditLogs
| where TimeGenerated > ago(1h)
| where OperationName == "Reset password (by admin)"
| where TargetResources[0].userPrincipalName in
    ("j.morrison@northgateeng.com", "s.chen@northgateeng.com", "a.patel@northgateeng.com")
| project TimeGenerated, TargetUser = tostring(TargetResources[0].userPrincipalName),
    ResetBy = tostring(InitiatedBy.user.userPrincipalName)

Action 3: Block the attacker IP in conditional access

Prevent the attacker from using any remaining or future tokens from their infrastructure.

Execute: Create a conditional access policy: Name: “BLOCK — AiTM Attacker IPs — INC-2026-0227-001”. Assignments: All users. Conditions: Locations → Include → named location containing 203.0.113.47 (and any other attacker IPs identified). Grant: Block access.

Blast radius: All users in the tenant are blocked from signing in from the specified IPs. If any legitimate user shares the same IP (extremely unlikely for VPS infrastructure, possible for residential proxies), they will be blocked. Tenant-wide scope for the specified IPs.

Rollback: Disable or delete the conditional access policy. Effect is immediate — sign-ins from the IP are allowed again within minutes.

Before enabling: Verify the IP is not a legitimate corporate IP, VPN exit, or shared infrastructure: SigninLogs | where TimeGenerated > ago(90d) | where IPAddress == "203.0.113.47" | where ResultType == "0" | summarize dcount(UserPrincipalName). If many legitimate users have signed in from this IP historically, do NOT block it without further investigation.

Cost impact: No cost. Conditional access policy evaluation is included in Entra ID licensing.

Compliance mapping: NIST CSF RS.MI-1 (Incidents are contained). ISO 27001 A.5.26 (Response to information security incidents). SOC 2 CC7.4 (The entity responds to identified security incidents).


Action 4: Disable compromised accounts (if severity warrants)

If the investigation reveals the attacker has established multiple persistence mechanisms and the blast radius of ongoing compromise exceeds the disruption of disabling the account: disable the account.

Decision criteria: Disable if: the attacker registered MFA methods, the attacker granted OAuth application consent, or internal phishing from the compromised account is ongoing. Do NOT disable if: containment actions 1-3 are sufficient and the user’s role requires immediate access (e.g., the CFO during an active financial close).

Execute: Entra ID → Users → select user → Block sign-in → Yes.

Blast radius: The user cannot sign in to any M365 service or Azure AD-integrated application. All active sessions are terminated. The user is completely locked out. Per-user scope — total access loss.

Rollback: Entra ID → Users → select user → Block sign-in → No. Access restored within minutes. User must re-authenticate.

Verify:

1
2
3
4
5
6
// Verify: account is blocked  sign-in attempts should fail
SigninLogs
| where TimeGenerated > ago(30m)
| where UserPrincipalName == "j.morrison@northgateeng.com"
| where ResultType != "0"
| project TimeGenerated, ResultType, ResultDescription

Expected: Any sign-in attempt shows ResultType 50057 (“User account is disabled”).


Containment timeline documentation

After executing all containment actions, document the timeline as an incident comment:

“Containment actions executed [date/time UTC]:

  1. Refresh tokens revoked for j.morrison, s.chen, a.patel at [time].
  2. Passwords reset for all 3 accounts at [time]. New passwords communicated via phone.
  3. Attacker IP 203.0.113.47 blocked via conditional access policy at [time].
  4. s.chen account disabled at [time] (MFA modification detected — elevated risk).

Verified: no new sign-ins from attacker IP after containment. Eradication (inbox rules, forwarding, MFA) pending — subsection 11.8.”

Subsection artifact: The containment action sequence above with blast radius and rollback for each step. This is the containment section of your AiTM investigation playbook. It is also the containment section of the IR report (11.11).


Knowledge check

Check your understanding

1. You revoke tokens and reset the password for a compromised user. 15 minutes later, the Livestream shows a new sign-in from the attacker IP for the same user. What happened?

The attacker has a secondary access path that survived containment. Possible causes: the attacker registered an MFA method (subsection 11.6 Step 4) and phished the new password, the attacker has OAuth application consent that generates its own tokens (subsection 11.6 Step 5), or the password was communicated via the compromised email channel and the attacker intercepted it. Immediate action: disable the account entirely (Action 4). Then investigate the secondary access path before re-enabling.
Token revocation failed — try again
The sign-in is the legitimate user
This is a sign-in log delay

2. The CFO's account is compromised but she is in the middle of quarterly financial close. Do you disable the account?

Not immediately — if token revocation + password reset + IP block are sufficient to contain the threat. The blast radius of disabling the CFO during financial close is severe business disruption. Execute Actions 1-3 first. Verify containment with the Livestream (no new attacker sign-ins). If the attacker returns despite Actions 1-3, escalate: the security risk of an active attacker in the CFO's mailbox outweighs the business disruption of account disablement. Document the risk decision and the rationale in the incident comment.
Always disable — security overrides business needs
Never disable — the CFO is too important
Wait until financial close is complete