12.6 Post-Compromise Activity Assessment

4-6 hours · Module 12

Post-Compromise Activity Assessment

The sign-in investigation (11.5) confirmed the compromise: the attacker replayed stolen tokens and accessed M365 services from 203.0.113.47. This subsection determines what the attacker did after gaining access. The results directly inform containment scope (11.7) and eradication actions (11.8).

Required role: Microsoft Sentinel Reader for KQL queries.


Step 1: Check for inbox rule creation

Inbox rules are the attacker’s first persistence and stealth mechanism. Rules redirect, delete, or hide incoming email — preventing the victim from seeing password reset notifications, security alerts, or replies to the attacker’s fraudulent emails.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Inbox rules created by compromised users from attacker infrastructure
CloudAppEvents
| where TimeGenerated > datetime(2026-02-27T08:00:00Z)
| where ActionType in ("New-InboxRule", "Set-InboxRule", "Enable-InboxRule")
| extend RuleData = parse_json(RawEventData)
| extend Creator = tostring(RuleData.UserId)
| extend ClientIP = tostring(RuleData.ClientIP)
| extend RuleName = tostring(RuleData.Parameters
    | mv-expand RuleData.Parameters
    | where tostring(RuleData.Parameters.Name) == "Name"
    | project tostring(RuleData.Parameters.Value))
| extend MoveToFolder = tostring(RuleData.Parameters
    | mv-expand RuleData.Parameters
    | where tostring(RuleData.Parameters.Name) == "MoveToFolder"
    | project tostring(RuleData.Parameters.Value))
| extend ForwardTo = tostring(RuleData.Parameters
    | mv-expand RuleData.Parameters
    | where tostring(RuleData.Parameters.Name) in ("ForwardTo", "RedirectTo", "ForwardAsAttachmentTo")
    | project tostring(RuleData.Parameters.Value))
| extend DeleteMessage = tostring(RuleData.Parameters
    | mv-expand RuleData.Parameters
    | where tostring(RuleData.Parameters.Name) == "DeleteMessage"
    | project tostring(RuleData.Parameters.Value))
| project TimeGenerated, Creator, ClientIP, RuleName,
    MoveToFolder, ForwardTo, DeleteMessage
| order by TimeGenerated asc

What to look for:

Forwarding rules. ForwardTo or RedirectTo containing an external email address (not @northgateeng.com). This is data exfiltration — every incoming email is copied to the attacker. Document the external address as an IOC.

Delete rules. DeleteMessage = “True” with conditions matching keywords like “password,” “reset,” “security,” “alert,” “suspicious,” “unauthorized.” The attacker is hiding security notifications from the victim.

Move-to-folder rules. MoveToFolder pointing to RSS Feeds, Conversation History, or a custom hidden folder. The attacker routes email out of the inbox so the victim does not see it.

Rules created from the attacker IP. If ClientIP matches the attacker IP (203.0.113.47), the rule was created by the attacker — not by the user. Rules created from the user’s known IP may be legitimate.

Create a bookmark for each malicious rule found. Tag: INC-2026-0227-001, post-compromise, inbox-rule. Record the exact rule name and conditions — you will need these for eradication (11.8).


Step 2: Check for mail forwarding configuration

Separate from inbox rules — Exchange Online has a mailbox-level forwarding setting.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Mailbox forwarding changes
CloudAppEvents
| where TimeGenerated > datetime(2026-02-27T08:00:00Z)
| where ActionType == "Set-Mailbox"
| extend Details = parse_json(RawEventData)
| extend TargetMailbox = tostring(Details.ObjectId)
| extend ForwardingAddress = tostring(Details.Parameters
    | mv-expand Details.Parameters
    | where tostring(Details.Parameters.Name) in
        ("ForwardingSmtpAddress", "ForwardingAddress", "DeliverToMailboxAndForward")
    | project tostring(Details.Parameters.Value))
| where isnotempty(ForwardingAddress)
| project TimeGenerated, TargetMailbox, ForwardingAddress,
    ClientIP = tostring(Details.ClientIP)

If results exist: Every email sent to the mailbox is forwarded to the attacker’s address — in addition to any inbox rules. This is a separate persistence mechanism that survives inbox rule removal. Note it for eradication.


Step 3: Check for email access (MailItemsAccessed)

Determine what the attacker read. This establishes the data exposure scope.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// Email access from attacker IP  what did they read?
CloudAppEvents
| where TimeGenerated > datetime(2026-02-27T08:00:00Z)
| where ActionType == "MailItemsAccessed"
| where AccountObjectId in (
    // Object IDs of confirmed compromised users
    SigninLogs
    | where IPAddress == "203.0.113.47"
    | where ResultType == "0"
    | distinct UserId
)
| extend Details = parse_json(RawEventData)
| extend ClientIP = tostring(Details.ClientIPAddress)
| where ClientIP == "203.0.113.47"  // Only access from attacker IP
| summarize
    EmailsAccessed = count(),
    FirstAccess = min(TimeGenerated),
    LastAccess = max(TimeGenerated),
    AccessMethods = make_set(tostring(Details.ClientInfoString), 5)
    by AccountObjectId

Why this matters: The number of emails accessed determines the data breach scope. If the attacker accessed 5 emails from a finance manager’s mailbox, the exposure is limited. If they accessed 500 emails over 3 hours, they may have harvested financial data, employee PII, or business-sensitive communications. This number goes into the IR report (11.11) and may trigger data breach notification obligations depending on the content of the accessed emails.

Compliance mapping: NIST CSF RS.AN-2 (The impact of the incident is understood). ISO 27001 A.5.25 (Assessment and decision on information security events). Determining what data was accessed is a regulatory requirement — you must be able to state the scope of data exposure.


Step 4: Check for MFA method modification

The attacker may register a new MFA method to maintain access after the stolen token expires.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// MFA method changes for compromised users
AuditLogs
| where TimeGenerated > datetime(2026-02-27T08:00:00Z)
| where OperationName has_any (
    "User registered security info",
    "User registered all required security info",
    "Admin registered security info",
    "User changed default security info")
| extend TargetUser = tostring(TargetResources[0].userPrincipalName)
| where TargetUser in ("j.morrison@northgateeng.com", "s.chen@northgateeng.com", "a.patel@northgateeng.com")
| extend IPAddress = tostring(InitiatedBy.user.ipAddress)
| project TimeGenerated, TargetUser, OperationName, IPAddress,
    ModifiedProperties = tostring(TargetResources[0].modifiedProperties)
| order by TimeGenerated asc

What to look for: Any MFA registration from the attacker IP or from an IP that is not the user’s known corporate IP. If the attacker registered their own Authenticator app, they can survive a password reset — they authenticate with the new password (obtained from a follow-up phishing attempt or password spray) using their own MFA method.

This is critical for eradication (11.8). If a new MFA method was registered, it must be removed in addition to revoking tokens and resetting the password. Failure to remove the attacker’s MFA method means containment is incomplete.


The attacker may have granted consent to a malicious OAuth application to maintain persistent API access to the mailbox.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// OAuth consent grants by compromised users
AuditLogs
| where TimeGenerated > datetime(2026-02-27T08:00:00Z)
| where OperationName == "Consent to application"
| where Result == "success"
| extend ConsentUser = tostring(InitiatedBy.user.userPrincipalName)
| where ConsentUser in ("j.morrison@northgateeng.com", "s.chen@northgateeng.com", "a.patel@northgateeng.com")
| extend AppName = tostring(TargetResources[0].displayName)
| extend AppId = tostring(TargetResources[0].id)
| extend IPAddress = tostring(InitiatedBy.user.ipAddress)
| project TimeGenerated, ConsentUser, AppName, AppId, IPAddress

If results exist: The attacker has persistent API access via the OAuth application. Even after password reset and token revocation, the OAuth app can access the mailbox using its own credentials. This consent must be revoked during eradication (11.8).


Compile post-compromise activity summary

After running all five steps, compile the findings:

UserInbox RuleForwardingEmails AccessedMFA ModifiedOAuth App
j.morrisonYes — forward to evil@attacker.com, delete security alertsYes — SMTP forward to evil@attacker.com~340 emails over 3 hoursNoNo
s.chenYes — move security alerts to RSS FeedsNo~120 emails over 1 hourYes — new Authenticator registeredNo
a.patelYes — forward to evil2@attacker.comNo~85 emails over 45 minutesNoNo

This table is the eradication checklist (11.8) and the scope section of the IR report (11.11).

Subsection artifact: The five post-compromise queries above plus the activity summary template. These form the post-compromise assessment section of your AiTM investigation playbook.


Knowledge check

Check your understanding

1. You find an inbox rule that deletes all incoming emails containing the words "password reset" and "security alert." What is the attacker's objective?

The attacker is hiding evidence of the compromise from the victim. If IT sends a password reset notification or a security alert about suspicious activity, the inbox rule deletes it before the victim sees it. This extends the attacker's dwell time — the victim does not know their account is compromised because they never receive the notifications that would alert them. The rule must be removed during eradication (11.8) before any password reset or security notification is sent.
The attacker wants to reduce the victim's inbox volume
The rule is a legitimate spam filter
The attacker is testing inbox rule creation

2. You revoke tokens and reset the password for s.chen. The attacker registered a new Authenticator app on s.chen's account. Is containment complete?

No. The attacker's registered Authenticator app survives password reset and token revocation. If the attacker obtains the new password (via a follow-up phishing attempt or credential stuffing with a reused password), they can authenticate using their own MFA method. Remove the attacker's MFA registration from the user's authentication methods before considering containment complete. Subsection 11.8 covers this eradication step.
Yes — password reset and token revocation are sufficient
Yes — the attacker cannot use the Authenticator without the password
Only if conditional access blocks the attacker's IP