PRACTITIONER GUIDE | CLOUD SECURITY
Practitioner GuideUpdated 13 min read

Microsoft 365 Unified Audit Log Forensics: How to Extract Attacker Activity from UAL Records During Incident Response

90 days
default UAL retention for standard M365 licenses -- Microsoft Purview Audit (Premium) extends this to 365 days or 10 years with add-on
5,000
maximum results returned per Search-UnifiedAuditLog call -- use date range pagination for incidents spanning more than 5,000 events
350+
distinct operations (event types) captured in the UAL across all M365 workloads including Exchange, SharePoint, Teams, and Entra ID
60 min
typical delay between an action occurring in M365 and the corresponding audit record appearing in the UAL for search

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

Business email compromise investigations in M365 environments follow a predictable forensic sequence: identify the compromised account, trace what actions the attacker took after gaining access, find any persistence mechanisms they created, and determine what data they accessed. The Unified Audit Log contains all of this if the queries are structured correctly. The challenge is that Search-UnifiedAuditLog returns JSON-encoded audit data in the AuditData field that requires parsing to surface the meaningful fields.

Enabling UAL and Verifying Audit Coverage

The UAL is enabled by default in most M365 tenants, but should be verified:

# Connect to Security & Compliance PowerShell
Connect-IPPSSession -UserPrincipalName admin@domain.com

# Check if audit logging is enabled for the tenant
Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled

# Enable if disabled
Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true

# Check if mailbox audit logging is enabled for a specific user
Get-Mailbox -Identity user@domain.com | Select-Object AuditEnabled, AuditAdmin, AuditDelegate, AuditOwner

Mailbox-level audit logging captures owner actions (the user logging in to their own mailbox), delegate actions (someone with Send As or Full Access permissions), and admin actions. By default, owner actions are not all audited. Check the AuditOwner property -- if it does not include MailItemsAccessed, MoveToDeletedItems, SoftDelete, and HardDelete, update it:

Set-Mailbox -Identity user@domain.com -AuditOwner @{Add="MailItemsAccessed","MoveToDeletedItems","SoftDelete","HardDelete"}

Note: MailItemsAccessed requires a Microsoft 365 E5 or Purview Audit Premium license. Without this license, forensic coverage of which specific emails were read is not available.

Querying Inbox Rule Creation: The Top BEC Persistence Pattern

After compromising an M365 account, attackers almost always create inbox rules to hide replies, forward emails, or delete detection alerts:

# Find inbox rule creation events for a specific user over the last 90 days
$rules = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) -EndDate (Get-Date) `
    -Operations "New-InboxRule","Set-InboxRule","UpdateInboxRules" `
    -UserIds "compromised.user@domain.com" `
    -ResultSize 5000

# Parse the AuditData JSON for each result
$rules | ForEach-Object {
    $data = $_.AuditData | ConvertFrom-Json
    [PSCustomObject]@{
        Time = $_.CreationDate
        User = $_.UserIds
        Operation = $_.Operations
        RuleName = $data.Parameters | Where-Object {$_.Name -eq "Name"} | Select-Object -ExpandProperty Value
        ForwardTo = $data.Parameters | Where-Object {$_.Name -eq "ForwardTo"} | Select-Object -ExpandProperty Value
        DeleteMsg = $data.Parameters | Where-Object {$_.Name -eq "DeleteMessage"} | Select-Object -ExpandProperty Value
        MoveToFolder = $data.Parameters | Where-Object {$_.Name -eq "MoveToFolder"} | Select-Object -ExpandProperty Value
        SubjectFilter = $data.Parameters | Where-Object {$_.Name -eq "SubjectContainsWords"} | Select-Object -ExpandProperty Value
        ClientIP = $data.ClientIP
    }
} | Format-Table -AutoSize

High-priority findings:

  • ForwardTo set to an external address: active email exfiltration
  • SubjectContainsWords matching 'invoice', 'payment', 'wire', 'bank': BEC targeting filter
  • DeleteMessage True with SubjectContainsWords matching security alert terms: detection evasion
Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

OAuth Application Consent Events: The Consent Phishing Investigation Path

Consent phishing attacks trick users into granting a malicious OAuth application full access to their mailbox. The UAL captures both the consent event and subsequent application access:

# Find all OAuth application consent events in the last 90 days
$consent = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) -EndDate (Get-Date) `
    -Operations "Add app role assignment grant to user","Consent to application","Add delegated permission grant" `
    -ResultSize 5000

$consent | ForEach-Object {
    $data = $_.AuditData | ConvertFrom-Json
    [PSCustomObject]@{
        Time = $_.CreationDate
        User = $_.UserIds
        AppName = $data.Target | Where-Object {$_.Type -eq 2} | Select-Object -ExpandProperty ID
        Permissions = $data.ModifiedProperties | Where-Object {$_.Name -eq "Included Updated Scopes"} | Select-Object -ExpandProperty NewValue
        ClientIP = $data.ActorIpAddress
    }
} | Format-Table -AutoSize

# Once you have a suspicious app name, find all API access it performed
$appAccess = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) -EndDate (Get-Date) `
    -Operations "MailItemsAccessed" `
    -FreeText "suspicious-app-display-name" `
    -ResultSize 5000

Cross-reference consent events with Graph API sign-in logs to determine the access scope the application actually used after consent was granted.

MFA and Authentication Method Changes

Attackers who gain account access often add a secondary MFA method to maintain persistence after the victim's password is changed:

# Find authentication method additions and removals (Entra ID operations in UAL)
$mfaChanges = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) -EndDate (Get-Date) `
    -Operations "User registered security info","User deleted security info","User registered all required security info","Admin updated security info","Admin deleted security info" `
    -ResultSize 5000

$mfaChanges | ForEach-Object {
    $data = $_.AuditData | ConvertFrom-Json
    [PSCustomObject]@{
        Time = $_.CreationDate
        TargetUser = ($data.ObjectId)
        Actor = $_.UserIds
        Operation = $_.Operations
        Method = $data.AdditionalDetails | Where-Object {$_.key -eq "Type"} | Select-Object -ExpandProperty value
        ClientIP = $data.ActorIpAddress
    }
} | Format-Table -AutoSize

For each MFA registration event:

  1. Correlate the actor IP with the user's normal login IP pattern (from Entra ID sign-in logs)
  2. If the actor is the same as the target user (self-registration), check whether the IP is consistent with the user's normal locations
  3. If the actor is not the target user (admin registration), verify the action was authorized
  4. Registration of a new authenticator app from an unfamiliar IP immediately after an account compromise is a strong persistence indicator

SharePoint Mass Download and Teams Export Detection

Data staging and exfiltration through SharePoint and Teams produces distinct audit event patterns:

# Detect mass file downloads from SharePoint (more than 50 files in one hour)
$spDownloads = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) `
    -RecordType SharePointFileOperation `
    -Operations "FileDownloaded" `
    -ResultSize 5000

$spDownloads | ForEach-Object {
    $data = $_.AuditData | ConvertFrom-Json
    [PSCustomObject]@{
        Time = $_.CreationDate
        User = $_.UserIds
        File = $data.SourceFileName
        SiteURL = $data.SiteUrl
        ClientIP = $data.ClientIP
        Hour = [datetime]::Parse($_.CreationDate).ToString("yyyy-MM-dd HH")
    }
} | Group-Object User, Hour | Where-Object {$_.Count -gt 50} |
    Select-Object @{N='User';E={$_.Name.Split(',')[0]}},
                  @{N='Hour';E={$_.Name.Split(',')[1]}},
                  @{N='FileCount';E={$_.Count}} |
    Sort-Object FileCount -Descending

# Teams channel message exports (used to stage conversation data)
$teamsExport = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) `
    -Operations "MessagesExported","ChatRetrieved" `
    -ResultSize 1000

For SharePoint mass download incidents, also check whether the downloads used a browser (identifiable by user agent in ClientIP metadata) or a scripted tool -- scripted downloads typically show consistent per-second request rates that differ from human browsing patterns.

The bottom line

The M365 Unified Audit Log is the foundation of every M365 incident investigation. The critical UAL queries are: inbox rule creation (BEC persistence), OAuth app consent (consent phishing), MFA method addition (authentication persistence), and SharePoint mass download (data staging). Parse the AuditData JSON field to extract meaningful details from each event type. Extend default mailbox audit logging to include MailItemsAccessed (requires E5 or Purview Premium) for complete forensic coverage of mailbox access by attackers.

Frequently asked questions

How far back can I search the UAL during an incident response?

The default UAL retention is 90 days for most M365 licenses. Microsoft 365 E5, Office 365 E5, and Microsoft Purview Audit Premium licenses extend retention to 1 year for all event types and up to 10 years for specific compliance-critical events. During IR, check the license level immediately to understand the investigation horizon. If an incident was ongoing for more than 90 days before detection and the tenant has standard licensing, the earliest attacker activity logs may be gone.

What is the difference between UAL and mailbox audit logging?

The UAL captures tenant-level activity across all M365 services including admin operations, SharePoint, Teams, and Entra ID. Mailbox audit logging captures per-mailbox access events at the individual email item level (which emails were read, moved, deleted, or sent). MailItemsAccessed events in mailbox audit logging allow forensic reconstruction of exactly which email items an attacker read. The UAL is the first-stop investigation source; mailbox audit logging provides deeper email-specific forensic detail.

How do I export large volumes of UAL data when 5,000 results are not enough?

Paginate using date ranges. Search-UnifiedAuditLog returns a maximum of 5,000 results per call. For high-volume events, split the time window into smaller intervals (1-hour or 6-hour windows) and run separate queries for each interval. Alternatively, use the Purview compliance portal's audit log export feature, which bypasses the 5,000 row limit and exports up to 50,000 records per export job to a CSV file. For bulk forensic exports, the Microsoft Graph API audit log endpoint also supports paging without the 5,000-record cap.

Can I tell from the UAL which IP address was used for an attacker's login?

Yes, but the UAL is not the best source for this. The Entra ID sign-in logs (Entra ID > Monitoring > Sign-in logs) are the authoritative source for login IP addresses, user agent strings, and authentication methods used. The UAL captures the ClientIP for actions taken after login (inbox rule creation, file downloads, etc.) but some UAL records have empty or internal IP addresses for server-side operations. For IP-based attacker tracing, start with Entra ID sign-in logs filtered to the compromised user and the incident time window.

How long does Microsoft retain Unified Audit Log data and what are the licensing differences?

Retention depends on the license assigned to the user whose actions generated the log entries. Microsoft 365 E3 and below: 90 days. Microsoft 365 E5 or users with the Microsoft Purview Audit (Premium) add-on: 1 year. With Microsoft Purview Audit (Premium), you can extend retention to 10 years by creating audit retention policies in the Purview compliance portal. Note that the license applies to the user performing the action, not the admin investigating -- if an E3 user's mailbox is compromised, their UAL entries are retained for only 90 days regardless of the investigating admin's license level. For incident response on E3 tenants, export and preserve audit logs immediately.

What is the fastest way to search the Unified Audit Log for a specific user's actions during an incident?

Use Search-UnifiedAuditLog with the -UserIds parameter to scope to one account: Search-UnifiedAuditLog -StartDate '2026-06-01' -EndDate '2026-06-30' -UserIds user@domain.com -ResultSize 5000 | Export-Csv user_audit.csv. For incident response where you need results immediately, use the Microsoft Purview compliance portal's Audit search with the User filter set to the compromised account and date range set to the suspected compromise window. The portal supports export to CSV and shows results faster than the PowerShell cmdlet for small result sets. For large result sets (more than 5,000 events), use the Office 365 Management Activity API with PowerShell pagination, as Search-UnifiedAuditLog caps at 5,000 results per call and requires iterating with a session ID to retrieve all results.

Sources & references

  1. Microsoft: Search the audit log in the Microsoft Purview compliance portal
  2. Microsoft: Detailed properties in the audit log
  3. CISA: Detecting Post-Compromise Threat Activity in Microsoft Cloud Environments

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.