Dissection approfondie du unified audit log (UAL)
Le Unified Audit Log (UAL) de Microsoft Purview constitue la colonne vertébrale forensique de toute réponse à incident dans Microsoft 365. Lorsqu’un attaquant opère au sein d’un tenant d’entreprise — qu’il crée des règles de redirection furtives dans Exchange Online, exfiltre des brevets industriels depuis SharePoint Online, manipule des canaux dans Microsoft Teams ou enregistre une application OAuth dans Entra ID —, l’UAL est le référentiel centralisé conçu pour consigner ses traces.
Néanmoins, appréhender l’UAL comme une simple base de données relationnelle ou un flux syslog standard mène inévitablement à l’échec d’investigation. L’UAL est un moteur d’agrégation asynchrone multi-tenant ingérant les événements de plus de 40 microservices distincts. Son schéma est polymorphe, ses délais d’ingestion s’étendent de quelques minutes à 24 heures selon la charge applicative, et ses interfaces d’extraction imposent des limites strictes de pagination et de débit.
1. Architecture d’ingestion & topologie des flux
Section intitulée « 1. Architecture d’ingestion & topologie des flux »L’UAL ne génère aucune télémétrie par lui-même. Chaque composant Microsoft 365 enregistre ses transactions localement au sein de sa frontière applicative, puis les publie sur un bus d’événements distribué :
graph TD subgraph "Producteurs de Télémétrie" EXO[Exchange Online<br/>Actions Boîtes & Admin] SPO[SharePoint Online<br/>Fichiers & Partages] ODB[OneDrive Entreprise<br/>Sync & Téléchargements] TEAMS[Microsoft Teams<br/>Messages, Canaux, Bots] ENTRA[Entra ID<br/>Modifications d'Annuaire] PUR[Services Purview<br/>DLP & eDiscovery] end
subgraph "Infrastructure d'Ingestion Purview" HUB[Bus d'Événements Interne Distributed Service Bus] NORM[Moteur de Normalisation & Enrichissement<br/>IP Client, Identité, Contexte de Session] ES_STORE[Magasin Purview Compliance Partitionné<br/>Indexation par Tenant & Horodatage UTC] end
subgraph "Interfaces d'Extraction Forensique" PS[PowerShell Exchange Online<br/>Search-UnifiedAuditLog] MGMT_API[Office 365 Management Activity API<br/>Abonnements Webhooks & Polling] GRAPH[Microsoft Graph API<br/>/security/auditLog/queries] PORTAL[Portail de Conformité Purview<br/>Recherches Asynchrones & Export CSV] end
EXO -->|15 min - 60 min| HUB SPO -->|15 min - 30 min| HUB ODB -->|15 min - 30 min| HUB TEAMS -->|1 h - 24 h| HUB ENTRA -->|15 min - 60 min| HUB PUR -->|30 min - 4 h| HUB
HUB --> NORM NORM --> ES_STORE
ES_STORE --> PS ES_STORE --> MGMT_API ES_STORE --> GRAPH ES_STORE --> PORTALDélais d’ingestion par composant (latences forensiques)
Section intitulée « Délais d’ingestion par composant (latences forensiques) »Une erreur classique en phase de réponse à incident consiste à conclure à l’absence d’activité hostile sous prétexte qu’aucun enregistrement n’apparaît dans l’UAL. Le délai d’ingestion (temps écoulé entre l’action sur le composant et sa visibilité dans l’UAL) dépend directement de la charge applicative :
| Composant | Délai d’ingestion nominal | Délai maximal (SLA / Pic de charge) | Impact en investigation (DFIR) |
|---|---|---|---|
| Exchange online | 15 à 45 minutes | Jusqu’à 4 heures | Les événements volumineux (MailItemsAccessed) sont mis en mémoire tampon avant d’être injectés. |
| SharePoint & OneDrive | 15 à 30 minutes | Jusqu’à 2 heures | Les opérations de téléchargement en masse sont consolidées par micro-lots. |
| Microsoft Entra ID | 15 à 60 minutes | Jusqu’à 2 heures | Les logs d’audit apparaissent plus vite dans le portail Entra (~2-5 min) que dans l’UAL Purview. |
| Microsoft teams | 2 à 6 heures | Jusqu’à 24 heures | Forte variance de télémétrie ; l’investigation en temps réel ne peut s’appuyer sur l’UAL seul. |
| Power platform / apps | 1 à 4 heures | Jusqu’à 24 heures | Pipeline de télémétrie à priorité basse. |
2. Anatomie du schéma de l’UAL
Section intitulée « 2. Anatomie du schéma de l’UAL »Chaque entrée dans l’UAL est structurée en deux couches : une enveloppe externe de métadonnées communes normalisées, et une charge utile polymorphe interne au format JSON imbriquée sous forme de chaîne de caractères dans la propriété AuditData.
Propriétés de l’enveloppe externe
Section intitulée « Propriétés de l’enveloppe externe »| Champ | Type | Description technique | Portée forensique |
|---|---|---|---|
CreationTime | DateTime UTC | Horodatage précis de l’action sur le composant source. | Capital : correspond au moment de l’action, non à l’heure d’ingestion UAL. |
RecordType | Entier / Enum | Identifiant catégorisant le composant ou la nature de l’événement. | Permet un filtrage ultra-rapide côté serveur (ex: 15 pour Entra, 2 pour Exchange). |
Operation | Chaîne | Action élémentaire réalisée (ex: FileDownloaded, New-InboxRule). | Pivot principal de détection des techniques MITRE ATT&CK. |
OrganizationId | GUID | Identifiant unique du tenant Microsoft 365. | Garantit l’étanchéité multi-tenant lors de collectes multi-entités. |
UserType | Entier / Enum | Nature de l’acteur (Regular, Admin, System, ServicePrincipal). | Distingue une action humaine d’un service automatisé ou d’un service principal. |
UserKey | Chaîne | Identifiant canonique immuable de l’utilisateur (PUID). | Permet de suivre un acteur même après renommage de son UPN ou changement d’alias. |
Workload | Chaîne | Service cible (Exchange, SharePoint, AzureActiveDirectory). | Délimite le périmètre applicatif inspecté. |
ResultStatus | Chaîne | Statut de l’opération (Succeeded, Failed, PartiallySucceeded). | Discrimine les échecs de force brute des exécutions réussies. |
AuditData | String (JSON) | Schéma spécifique contenant l’ensemble des paramètres contextuels. | Requiert une désérialisation JSON pour extraire adresses IP, chemins et jetons. |
Énumération des principaux RecordType
Section intitulée « Énumération des principaux RecordType »Filtrer par RecordType réduit drastiquement la charge serveur et évite d’atteindre le plafond d’extraction des requêtes :
RecordType 1 : ExchangeAdmin (Commandes PowerShell admin & modifications de configuration)RecordType 2 : ExchangeItem (Accès aux éléments de boîte : MailItemsAccessed, SoftDelete)RecordType 4 : General (Opérations transverses, recherches eDiscovery)RecordType 6 : SharePointFileOperation (Téléchargements, consultations, suppressions de fichiers)RecordType 8 : ComplianceDLPExchange (Déclenchements des règles DLP sur les flux de messagerie)RecordType 15 : AzureActiveDirectory (Gestion des utilisateurs, rôles, consentements OAuth)RecordType 25 : MicrosoftTeams (Création d'équipes, réglages de canaux, ajouts d'invités)RecordType 49 : SecurityComplianceAlerts (Génération d'alertes de sécurité Purview et Defender)3. Dissection du contenu polymorphe AuditData
Section intitulée « 3. Dissection du contenu polymorphe AuditData »Selon le RecordType, la chaîne AuditData contient des attributs radicalement différents. L’analyste doit adapter ses expressions de parsing.
{ "CreationTime": "2026-09-15T08:14:22", "Id": "a4f89d32-28e1-4c12-b891-883109aef102", "Operation": "MailItemsAccessed", "OrganizationId": "72f988bf-86f1-41af-91ab-2d7cd011db47", "RecordType": 2, "ResultStatus": "Succeeded", "UserKey": "1003200189ABCDEF@tenant.onmicrosoft.com", "UserType": 0, "Version": 1, "Workload": "Exchange", "ClientIPAddress": "198.51.100.45", "ClientInfoString": "Client=REST;Client=OutlookService;Version=16.0.17830.20138;", "ClientRequestId": "9b12a843-ef45-42a1-9a14-8712a45930b1", "ExternalAccess": false, "InternalLogonType": 0, "MailboxOwnerUPN": "cfo@defense-corp.org", "MailboxOwnerSid": "S-1-5-21-3829104821-291823901-192831092-1004", "MailboxGuid": "4d12f890-341a-4f89-91a1-987120adfe01", "LogonType": 0, "OperationProperties": [ { "Name": "MailAccessType", "Value": "Bind" }, { "Name": "IsThrottled", "Value": "False" } ], "Folder": { "FolderItems": [ { "InternetMessageId": "<BL3PR02MB10293847@BL3PR02.EURPRD02.PROD.OUTLOOK.COM>", "Subject": "CONFIDENTIAL: Q3 Financial Restructuring Strategy", "ItemSize": 45812 } ], "Id": "LgAAAAD4k1...AQ==" }}{ "CreationTime": "2026-09-15T08:32:11", "Id": "e12a4b89-1234-4567-890a-bcdef0123456", "Operation": "FileDownloaded", "OrganizationId": "72f988bf-86f1-41af-91ab-2d7cd011db47", "RecordType": 6, "ResultStatus": "Succeeded", "UserKey": "i:0#.f|membership|attaquant_recon@external.org", "UserType": 0, "Workload": "SharePoint", "ClientIP": "203.0.113.195", "UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0", "ObjectId": "https://defensecorp.sharepoint.com/sites/RAndD/Documents Partages/Plan_Strategique_Hermes.pdf", "SiteUrl": "https://defensecorp.sharepoint.com/sites/RAndD", "SourceFileName": "Plan_Strategique_Hermes.pdf", "SourceFileExtension": "pdf", "EventSource": "SharePoint", "ItemType": "File"}{ "CreationTime": "2026-09-15T09:02:44", "Id": "f98234ab-5678-4321-9abc-0123456789de", "Operation": "Add member to role.", "OrganizationId": "72f988bf-86f1-41af-91ab-2d7cd011db47", "RecordType": 15, "ResultStatus": "Success", "Workload": "AzureActiveDirectory", "Actor": [ { "ID": "admin_compromis@defense-corp.org", "Type": 5 } ], "Target": [ { "ID": "Global Administrator", "Type": 2 }, { "ID": "Compte_Piraté_Invité#EXT#@defense-corp.onmicrosoft.com", "Type": 1 } ], "ModifiedProperties": [ { "Name": "Role.DisplayName", "NewValue": ""Global Administrator"", "OldValue": "" } ]}4. Extraction & requêtage opérationnel : commandes maîtresses
Section intitulée « 4. Extraction & requêtage opérationnel : commandes maîtresses »L’interrogation de l’UAL via le portail web de conformité est inadaptée aux investigations critiques (plafond de 50 000 lignes et latence du navigateur). L’analyste doit maîtriser l’extraction programmatique.
PowerShell Exchange online : maîtrise de Search-UnifiedAuditLog
Section intitulée « PowerShell Exchange online : maîtrise de Search-UnifiedAuditLog »La cmdlet Search-UnifiedAuditLog est l’outil interactif de référence. Cependant, des requêtes imprudentes s’interrompent fréquemment ou retournent des données tronquées :
# Connexion avec privilèges minimaux (rôles Compliance Administrator / View-Only Audit Logs)Connect-ExchangeOnline -UserPrincipalName analyste-dfir@defense-corp.org
# Définition impérative des dates au format UTC$startDate = (Get-Date "2026-09-14T00:00:00Z").ToUniversalTime()$endDate = (Get-Date "2026-09-15T23:59:59Z").ToUniversalTime()
# Requête ciblée avec conversion des en-têtes$auditEvents = Search-UnifiedAuditLog ` -StartDate $startDate ` -EndDate $endDate ` -RecordType ExchangeItem ` -Operations "MailItemsAccessed", "SendAs", "New-InboxRule" ` -ResultSize 5000 ` -FormattedLe piège des 50 000 enregistrements et le pattern de découpage temporel
Section intitulée « Le piège des 50 000 enregistrements et le pattern de découpage temporel »Search-UnifiedAuditLog impose un plafond absolu de 50 000 enregistrements par requête. Lorsqu’une fenêtre temporelle dépasse ce volume, la commande cesse silencieusement de retourner des résultats sans lever la moindre exception.
Pour garantir l’exhaustivité des preuves, l’équipe DFIR doit implémenter un algorithme de découpage par fenêtres glissantes (Date-Slicing) :
function Get-CompleteUnifiedAuditLogFR { param( [Parameter(Mandatory=$true)][DateTime]$StartUtc, [Parameter(Mandatory=$true)][DateTime]$EndUtc, [Parameter(Mandatory=$false)][string]$RecordType, [Parameter(Mandatory=$false)][string]$Operations )
$windowStart = $StartUtc $intervalHours = 4 $allRecords = [System.Collections.Generic.List[PSObject]]::new()
while ($windowStart -lt $EndUtc) { $windowEnd = $windowStart.AddHours($intervalHours) if ($windowEnd -gt $EndUtc) { $windowEnd = $EndUtc }
Write-Host "[-] Extraction UAL fenêtre : $windowStart -> $windowEnd" -ForegroundColor Cyan
$session = "DFIR_Session_" + [Guid]::NewGuid().ToString() $page = 1 $totalWindowCount = 0
do { $params = @{ StartDate = $windowStart EndDate = $windowEnd ResultSize = 5000 SessionCommand = "ReturnLargeSet" SessionId = $session } if ($RecordType) { $params["RecordType"] = $RecordType } if ($Operations) { $params["Operations"] = $Operations }
$batch = Search-UnifiedAuditLog @params if ($batch) { $batchCount = $batch.Count $totalWindowCount += $batchCount $allRecords.AddRange($batch) Write-Host " [+] Page $page : $batchCount événements collectés (Total fenêtre : $totalWindowCount)" -ForegroundColor Gray $page++ } else { break } } while ($batchCount -eq 5000)
# Si le plafond de 50 000 est frôlé, diviser l'intervalle horaire par deux if ($totalWindowCount -ge 49000) { Write-Warning "[!] Fenêtre proche de la saturation des 50k. Réduction de l'intervalle..." $intervalHours = [Math]::Max(1, [Math]::Floor($intervalHours / 2)) continue }
$windowStart = $windowEnd }
return $allRecords}5. Export de télémétrie industrielle : office 365 management activity API
Section intitulée « 5. Export de télémétrie industrielle : office 365 management activity API »Pour l’alimentation continue d’un SIEM ou les extractions massives, l’Office 365 Management Activity API constitue le standard d’ingestion asynchrone :
sequenceDiagram autonumber participant App as Collecteur DFIR / SIEM (Application Azure AD) participant API as Office 365 Management API participant Blob as Stockage Blobs Azure Purview
App->>API: POST /subscriptions/start?contentType=Audit.Exchange API-->>App: 200 OK (Souscription Active) Note over API: Agrégation continue des événements par lots API->>App: Notification Webhook (ou interrogation GET par l'App) App->>API: GET /subscriptions/content?contentType=Audit.Exchange API-->>App: 200 OK (Liste des URIs de blobs) loop Pour chaque URI de contenu App->>Blob: GET https://manage.office.com/.../contentBlob Blob-->>App: 200 OK (Flux GZip contenant le tableau JSON) endL’API segmente les flux en 5 types de contenu indépendants :
Audit.AzureActiveDirectoryAudit.ExchangeAudit.SharePointAudit.General(Comprend Teams, OneDrive, Purview, Power Platform)DLP.All(Règles de prévention des fuites de données)
6. Chasse KQL avancée dans Defender XDR (CloudAppEvents)
Section intitulée « 6. Chasse KQL avancée dans Defender XDR (CloudAppEvents) »Dans les environnements dotés de licences Microsoft Defender for Cloud Apps ou Defender XDR, les flux de l’UAL sont automatiquement injectés dans la table CloudAppEvents d’Advanced Hunting, permettant des requêtes sub-secondes sur 30 jours :
// Détection de créations de règles de messagerie suspectes corrélées aux accèsCloudAppEvents| where TimeGenerated > ago(7d)| where ActionType in ("New-InboxRule", "Set-InboxRule", "MailItemsAccessed")| extend AuditData = parse_json(RawEventData)| extend ClientIP = tostring(AuditData.ClientIPAddress), Mailbox = tostring(AuditData.MailboxOwnerUPN), RuleName = tostring(AuditData.Parameters[0].Value)| summarize MailItemsAccessedCount = countif(ActionType == "MailItemsAccessed"), ReglesCrees = make_set_if(RuleName, ActionType has "InboxRule"), AdressesIP = make_set(ClientIP), Pays = make_set(Location) by Mailbox, bin(TimeGenerated, 1h)| where array_length(ReglesCrees) > 0| order by TimeGenerated desc7. Pièges d’investigation & anomalies forensiques
Section intitulée « 7. Pièges d’investigation & anomalies forensiques »8. Maillage documentaire & liens transverses
Section intitulée « 8. Maillage documentaire & liens transverses »- 08. Architecture des journaux — Cartographie globale des quatre plans de journalisation.
- 14. Audit log vs unified audit log vs entra audit log — Matrice comparative des portées et des chevauchements.
- 17. Audit de boîte mail & analyse de MailItemsAccessed — Extraction détaillée des preuves de lecture et vol de mails.
- 18. Rétention d’audit Microsoft 365 & réalités de licences — Règles de conservation (180j vs 1 an vs 10 ans) et prérequis de licence.
- 45. Reconstitution d’une timeline d’attaque — Méthodologie de corrélation multi-sources.\n