Préservation urgente des preuves Microsoft 365
Face à une compromission avérée ou suspectée d’un tenant Microsoft 365, l’adversaire le plus redoutable de l’analyste DFIR n’est pas uniquement le groupe d’attaquants : c’est le compte à rebours de rétention des journaux. Contrairement aux infrastructures locales où une image disque ou une copie de journaux d’événements peut être figée indéfiniment, la télémétrie cloud de Microsoft 365 vieillit en continu et fait l’objet d’un écrasement automatique et irréversible dicté par les cycles de rétention de la plateforme.
Un retard de quelques heures ou de quelques jours dans les opérations initiales peut anéantir définitivement les historiques de connexion interactive, les traces de remise de messages en temps réel ou les journaux d’activité applicative. Cette fiche définit un protocole chronologique rigoureux de préservation d’urgence des preuves sur Microsoft 365 et Entra ID.
La préservation des preuves dans Microsoft 365 repose sur deux axes opérationnels distincts mais complémentaires :
- Préservation du plan des journaux (télémétrie éphémère) : extraire et archiver les logs opérationnels glissants (connexions Entra ID, audits d’annuaire, suivi des messages Exchange, télémétrie brute Defender) avant l’atteinte de leur date limite de rétention native.
- Préservation du plan des données (immuabilité des contenus) : appliquer des mesures de gel conservatoire (Litigation Hold, eDiscovery Hold Purview) sur les boîtes aux lettres, les bibliothèques OneDrive et les sites SharePoint pour empêcher l’attaquant ou les utilisateurs légitimes d’effacer définitivement des e-mails, des fichiers ou des messages instantanés.
Comprendre la frontière entre rétention des logs et rétention des contenus est fondamental : le Litigation Hold ne conserve aucun log d’audit, et l’export des logs d’audit ne fige aucun contenu de boîte mail. Les deux actions doivent être menées de front.
Ordre chronologique de préservation selon la vitesse d’expiration
Section intitulée « Ordre chronologique de préservation selon la vitesse d’expiration »Les actions de collecte doivent être ordonnancées selon la vitesse d’expiration des données forensiques :
graph TD subgraph "Hiérarchie de vitesse d'expiration" T1["Niveau 1 : Ultra-Critique (Expiration 0 à 7 jours)<br/>- Logs Entra ID Free (7j)<br/>- Suivi des messages temps réel (10j)<br/>- Contexte éphémère de fraude MFA"] T2["Niveau 2 : Haute Priorité (Expiration 10 à 30 jours)<br/>- Logs Entra ID P1/P2 (30j)<br/>- Advanced Hunting brut Defender XDR (30j)<br/>- Événements à risque Identity Protection"] T3["Niveau 3 : Conformité & Contenus (30 à 180 jours)<br/>- Journal d'audit unifié Purview (180j standard)<br/>- Suivi des messages historique (90j)<br/>- Boucles de purge des boîtes et OneDrive"] end T1 -->|Préserver en Heure 1 à 4| T2 T2 -->|Préserver en Heure 4 à 12| T3| Fenêtre de rétention | Flux de données | Conséquence du retard | Action immédiate |
|---|---|---|---|
| 7 jours | Connexions & Audits Entra ID Free | Historique d’authentification et adresses IP sources définitivement purgés. | Export massif immédiat via script Graph API PowerShell. |
| 10 jours | Suivi des messages Exchange en temps réel (Get-MessageTrace) | Les métadonnées détaillées par saut basculent vers la recherche historique lente. | Extraire les traces de messages pour tous les comptes ciblés. |
| 14 à 30 jours | Dossier Éléments supprimés & Purges (Boîte mail) | Les e-mails effacés par l’attaquant sont purgés de Recoverable Items\Purges. | Activer immédiatement le Litigation hold sur les boîtes concernées. |
| 30 jours | Connexions Entra P1/P2 & Télémétrie brute Defender XDR | Les tables Advanced Hunting (CloudAppEvents, DeviceInfo) sont tronquées à 30j. | Exporter les requêtes KQL et activer le streaming vers Log Analytics. |
| 90 jours | Suivi historique des messages Exchange | Les logs de transport antérieurs à 90 jours sont irrécupérables. | Lancer un Start-HistoricalSearch sur le périmètre large. |
| 180 jours | Journal d’audit unifié Purview (Audit Standard) | Les événements d’activité utilisateurs et administrateurs sont purgés. | Exporter l’UAL via Search-UnifiedAuditLog par fenêtres temporelles. |
Étape 1 : poser un gel conservatoire immédiat (litigation hold)
Section intitulée « Étape 1 : poser un gel conservatoire immédiat (litigation hold) »Lorsqu’un attaquant accède à une boîte aux lettres, il configure couramment des règles de suppression automatique ou efface manuellement les traces de ses envois de phishing. L’activation du Litigation Hold fige immédiatement la boîte aux lettres : même si l’attaquant vide les éléments supprimés ou purge les messages par combinaison Maj+Suppr, Exchange Online déplace silencieusement les éléments vers les dossiers masqués Recoverable Items\Purges et DiscoveryHolds, d’où ils ne peuvent plus être effacés.
# Connexion à Exchange OnlineConnect-ExchangeOnline -ShowBanner:$false
$TargetMailbox = "victime@domaine.com"$IncidentId = "INC-2026-8941"
# 1. Vérifier l'état actuel de rétentionGet-Mailbox -Identity $TargetMailbox | Select-Object DisplayName, LitigationHoldEnabled, LitigationHoldDate, RetentionHoldEnabled
# 2. Appliquer le Litigation Hold d'urgence (Rétention illimitée)Set-Mailbox -Identity $TargetMailbox ` -LitigationHoldEnabled $true ` -LitigationHoldDuration Unlimited ` -LitigationHoldOwner "DFIR-$IncidentId" ` -RetentionUrl "https://incident-management.interne/cases/$IncidentId"
Write-Host "[+] Litigation Hold appliqué avec succès sur $TargetMailbox" -ForegroundColor Green
# 3. Contrôler l'état mis à jourGet-Mailbox -Identity $TargetMailbox | Select-Object LitigationHoldEnabled, LitigationHoldDate, LitigationHoldOwner# Appliquer le gel conservatoire sur tous les comptes compromis listés dans un CSV$TargetAccounts = Import-Csv -Path "./scoped_users.csv" # En-tête attendu : UserPrincipalName
foreach ($user in $TargetAccounts) { try { Set-Mailbox -Identity $user.UserPrincipalName ` -LitigationHoldEnabled $true ` -LitigationHoldDuration Unlimited ` -LitigationHoldOwner "DFIR-Urgence" -ErrorAction Stop Write-Host "[+] Gel appliqué sur : $($user.UserPrincipalName)" -ForegroundColor Green } catch { Write-Error "[-] Échec de pose du gel sur $($user.UserPrincipalName) : $($_.Exception.Message)" }}[!WARNING] Délai de synchronisation du Litigation Hold : bien que le paramètre soit immédiatement visible dans les métadonnées de l’annuaire, la propagation complète dans le magasin de stockage Exchange Online peut prendre jusqu’à 60 minutes. Ne différez jamais cette action.
Étape 2 : export d’urgence des logs d’authentification et d’annuaire entra ID
Section intitulée « Étape 2 : export d’urgence des logs d’authentification et d’annuaire entra ID »Sur un tenant Entra ID Free (7 jours de rétention) ou P1/P2 (30 jours), l’extraction immédiate des journaux de connexion est la priorité absolue.
# ==============================================================================# Hermes Codex - Extracteur d'urgence des Sign-In Logs Entra ID (Microsoft.Graph)# Exporte les connexions avec pagination par @odata.nextLink# ==============================================================================
Import-Module Microsoft.Graph.Authentication, Microsoft.Graph.Reports -ErrorAction Stop
# Connexion avec les privilèges de lecture des auditsConnect-MgGraph -Scopes "AuditLog.Read.All", "Directory.Read.All" -NoWelcome
$ExportDir = "./ForensicArtifacts_$(Get-Date -Format 'yyyyMMdd_HHmmss')"New-Item -ItemType Directory -Path $ExportDir -Force | Out-Null
$DaysToExtract = 30$StartDate = (Get-Date).AddDays(-$DaysToExtract).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")$OutputFile = "$ExportDir/Entra_SignIns_30Jours.jsonl"
Write-Host "[*] Extraction des Sign-Ins Entra depuis $StartDate vers $OutputFile..." -ForegroundColor Cyan
# Requête REST Graph avec filtre serveur et pagination$Uri = "https://graph.microsoft.com/v1.0/auditLogs/signIns?`$filter=createdDateTime ge $StartDate&`$top=1000"
$Count = 0do { try { $response = Invoke-MgGraphRequest -Method GET -Uri $Uri $records = $response.value
foreach ($record in $records) { $jsonLine = $record | ConvertTo-Json -Compress -Depth 10 Add-Content -Path $OutputFile -Value $jsonLine $Count++ }
Write-Host "[+] $Count enregistrements extraits..." -ForegroundColor Gray $Uri = $response.'@odata.nextLink'
# Pause préventive contre le throttling Start-Sleep -Milliseconds 200 } catch { if ($_.Exception.Response.StatusCode -eq 429) { $retryAfter = $_.Exception.Response.Headers.RetryAfter.Delta.TotalSeconds if (-not $retryAfter) { $retryAfter = 10 } Write-Warning "[!] Throttling détecté (HTTP 429). Attente de $retryAfter secondes..." Start-Sleep -Seconds $retryAfter } else { Write-Error "[-] Erreur critique Graph API : $($_.Exception.Message)" break } }} while ($null -ne $Uri)
# Calcul du hash SHA-256 pour la chaîne de traçabilité$hash = Get-FileHash -Path $OutputFile -Algorithm SHA256$hash | Export-Clixml -Path "$ExportDir/Entra_SignIns_30Jours.hash.xml"Write-Host "[✓] Extraction terminée : $Count événements. SHA-256 : $($hash.Hash)" -ForegroundColor GreenÉtape 3 : export d’urgence du journal d’audit unifié (UAL)
Section intitulée « Étape 3 : export d’urgence du journal d’audit unifié (UAL) »Le journal d’audit unifié regroupe les actions menées sur Exchange, SharePoint, OneDrive, Teams et Entra ID. Pour éviter la troncature à 5 000 enregistrements et les dépassements de mémoire, le requêtage doit impérativement être segmenté par fenêtres temporelles.
# ==============================================================================# Hermes Codex - Extracteur UAL segmenté par fenêtres de 6 heures# Évite la troncature des résultats et les interruptions de session# ==============================================================================
Import-Module ExchangeOnlineManagement -ErrorAction StopConnect-ExchangeOnline -ShowBanner:$false
$TargetUser = "victime@domaine.com"$StartDate = (Get-Date).AddDays(-15)$EndDate = (Get-Date)$OutputDir = "./UAL_Extract_$(Get-Date -Format 'yyyyMMdd')"New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
$CurrentStart = $StartDate$IntervalHours = 6
while ($CurrentStart -lt $EndDate) { $CurrentEnd = $CurrentStart.AddHours($IntervalHours) if ($CurrentEnd -gt $EndDate) { $CurrentEnd = $EndDate }
$TimeStr = "$($CurrentStart.ToString('yyyyMMdd_HHmm'))_a_$($CurrentEnd.ToString('yyyyMMdd_HHmm'))" $BatchFile = "$OutputDir/UAL_$TimeStr.json"
Write-Host "[*] Requêtage UAL : $CurrentStart -> $CurrentEnd..." -ForegroundColor Cyan
try { $events = Search-UnifiedAuditLog ` -StartDate $CurrentStart ` -EndDate $CurrentEnd ` -FreeText $TargetUser ` -ResultSize 5000 ` -ErrorAction Stop
if ($events.Count -gt 0) { # Parser la chaîne JSON interne AuditData $structuredEvents = $events | ForEach-Object { $rawAuditData = $_.AuditData | ConvertFrom-Json [PSCustomObject]@{ CreationDate = $_.CreationDate RecordType = $_.RecordType Operations = $_.Operations UserIds = $_.UserIds ResultStatus = $_.ResultStatus AuditData = $rawAuditData } } $structuredEvents | ConvertTo-Json -Depth 10 | Set-Content -Path $BatchFile Write-Host " [+] $BatchFile sauvegardé ($($events.Count) événements)" -ForegroundColor Green } else { Write-Host " [-] Aucun événement dans cette tranche." -ForegroundColor Gray } } catch { Write-Error " [!] Erreur sur la tranche UAL : $($_.Exception.Message)" }
$CurrentStart = $CurrentEnd Start-Sleep -Seconds 2 # Temporisation pour éviter le throttling Exchange}Étape 4 : mise en place du streaming continu vers un SIEM
Section intitulée « Étape 4 : mise en place du streaming continu vers un SIEM »L’export ponctuel fige le passé, mais si l’investigation s’étend sur plusieurs semaines, les nouveaux logs continueront de disparaître. La configuration des Paramètres de diagnostic (Diagnostic Settings) dans Entra ID permet de router tous les flux futurs vers un espace de travail Log Analytics ou un Event Hub.
# ==============================================================================# Configuration des paramètres de diagnostic Entra ID vers Azure Log Analytics# Requiert Global Administrator ou Security Administrator + Azure Contributor# ==============================================================================
# 1. Identifiant de ressource de l'espace Log Analytics cible$WorkspaceId = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-soc/providers/Microsoft.OperationalInsights/workspaces/law-retention-dfir"
# 2. Définition du payload JSON$DiagnosticPayload = @{ name = "DFIR-PreservationContinue" properties = @{ workspaceId = $WorkspaceId logs = @( @{ category = "SignInLogs"; enabled = $true }, @{ category = "NonInteractiveUserSignInLogs"; enabled = $true }, @{ category = "ServicePrincipalSignInLogs"; enabled = $true }, @{ category = "ManagedIdentitySignInLogs"; enabled = $true }, @{ category = "AuditLogs"; enabled = $true }, @{ category = "ProvisioningLogs"; enabled = $true }, @{ category = "RiskyUsers"; enabled = $true }, @{ category = "UserRiskEvents"; enabled = $true } ) }} | ConvertTo-Json -Depth 5
# 3. Envoi à l'API Diagnostic Settings de Microsoft Graph$Uri = "https://graph.microsoft.com/v1.0/reports/diagnosticSettings"Invoke-MgGraphRequest -Method POST -Uri $Uri -Body $DiagnosticPayload -ContentType "application/json"
Write-Host "[+] Streaming continu vers Log Analytics activé !" -ForegroundColor GreenÉtape 5 : gestion des quotas d’API et du throttling (HTTP 429)
Section intitulée « Étape 5 : gestion des quotas d’API et du throttling (HTTP 429) »Lors de collectes volumineuses, les analystes rencontrent inévitablement les seuils de régulation de la plateforme Microsoft :
Régulation Microsoft graph
Section intitulée « Régulation Microsoft graph »- Code retour :
HTTP 429 Too Many Requests. - En-tête clé :
Retry-After(indique le nombre de secondes à patienter avant la prochaine requête). - Quota de parallélisme : maximum de 4 requêtes concurrentes par tenant sur les flux d’audit lourds.
- Stratégie de traitement : toujours implémenter un recul exponentiel avec gigue aléatoire (jitter) :
Délai = max(Retry-After, 2^tentative + rand(0, 1))
Régulation PowerShell Exchange online
Section intitulée « Régulation PowerShell Exchange online »- Limite d’espace d’exécution (runspace) : maximum 3 sessions simultanées par compte administrateur.
- Micro-délais : insérer un
Start-Sleep -Milliseconds 500entre chaque appel àSearch-UnifiedAuditLogouGet-MessageTrace. - Plafond de résultat :
Search-UnifiedAuditLogest plafonné à 5 000 enregistrements par exécution. Ne tentez jamais d’élargir la période sans découpage temporel.
Doctrine transversale : préservation vs preuve
Section intitulée « Doctrine transversale : préservation vs preuve »Dans le rapport d’incident, l’analyste doit impérativement respecter la distinction entre ce qui est préservé et ce qui est prouvé :
+-------------------------------------------------------------------------------+| LES 7 NIVEAUX DE CERTITUDE FORENSIQUE || || 1. Possible -> L'architecture prend en charge la rétention et les gels. || 2. Configuré -> Le Litigation Hold est actif et le diagnostic configuré. || 3. Autorisé -> L'intervenant possède les rôles eDiscovery et Audit Reader.|| 4. Accessible -> Les endpoints API répondent, les jetons sont valides. || 5. Utilisé -> Les scripts d'export massif sont exécutés sur le tenant. || 6. Observé -> Les fichiers JSONL sont archivés et validés localement. || 7. Prouvé -> Certitude forensique scellée par empreinte SHA-256. |+-------------------------------------------------------------------------------+Applications directes à la préservation des preuves
Section intitulée « Applications directes à la préservation des preuves »- Configuré != observé : poser un Litigation Hold est une action de configuration. Cela garantit la conservation des modifications futures ; cela ne prouve pas que des e-mails supprimés avant la pose du gel (au-delà des 14 jours de rétention par défaut des éléments supprimés) sont récupérables.
- Observé != prouvé : un enregistrement extrait de l’API Graph constitue un fait brut observé. Pour devenir une preuve juridiquement recevable (prouvée), il doit être scellé par une empreinte cryptographique SHA-256 dès son extraction, documenté dans un registre de chaîne de traçabilité, et corrélé avec les journaux de session correspondants.
Pièges et confusions fréquentes
Section intitulée « Pièges et confusions fréquentes »| Piège | Cause technique | Conséquence pour l’enquête | Action corrective |
|---|---|---|---|
| Croire que litigation hold sauvegarde les logs | Le Litigation Hold n’agit que sur le magasin Exchange (Recoverable Items) et n’a aucun impact sur l’UAL ou Entra ID. | L’analyste néglige l’export des logs, qui disparaissent irrémédiablement au bout de 30 jours. | Extraire les logs d’authentification et l’UAL en parallèle absolu des gels de contenu. |
| Requête UAL globale en une seule passe | Exécuter Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) en bloc. | La requête plafonne à 5 000 enregistrements et tronque l’immense majorité des événements. | Découper impérativement les requêtes en tranches de 6 à 24 heures. |
| Ignorer les connexions non interactives | N’extraire que les connexions interactives standard sans collecter les jetons de rafraîchissement ni les principaux de service. | Les attaques par vol de session (AiTM) et les exfiltrations applicatives restent invisibles. | Exporter systématiquement les flux NonInteractiveUserSignInLogs et ServicePrincipalSignInLogs. |
| Absence d’empreinte cryptographique | Déposer des fichiers JSON/CSV bruts sur un poste d’analyse sans calcul de hash immédiat. | Rejet potentiel des preuves lors d’un litige ou d’une notification réglementaire. | Générer automatiquement le hash SHA-256 de chaque artefact dès l’export terminé. |
| Parallélisme agressif déclenchant un blocage | Lancer 50 threads concurrents sur Graph API. | Blocage HTTP 429 massif impactant potentiellement les applications métiers de l’entreprise. | Limiter l’extraction à 2-4 threads et respecter rigoureusement l’en-tête Retry-After. |
État de la fonctionnalité en 2026
Section intitulée « État de la fonctionnalité en 2026 »Changements récents
Section intitulée « Changements récents »- Rétention standard UAL à 180 jours : la durée de conservation par défaut du journal d’audit unifié est de 180 jours pour tous les plans d’entreprise.
- Modernisation de l’API audit dans Microsoft graph : l’extraction programmatique de l’UAL bascule sur les API Graph de conformité Purview, remplaçant progressivement l’ancienne API Office 365 Management Activity.
- Paramètres de diagnostic unifiés : la diffusion en continu prend désormais en charge l’ensemble des catégories de connexions (utilisateurs, non interactifs, principaux de service, identités managées).
Fonctionnalités dépréciées
Section intitulée « Fonctionnalités dépréciées »- Modules Exchange V1 et V2 : définitivement retirés. L’ensemble des scripts doit exploiter le module
ExchangeOnlineManagementv3+ reposant sur des appels REST. - Authentification de base : désactivée sans exception sur tous les endpoints d’administration. L’utilisation d’une application Entra avec certificat est obligatoire pour les collectes automatisées.
Limitations actuelles
Section intitulée « Limitations actuelles »- Latence d’ingestion UAL : même en réponse à incident critique, l’apparition d’un événement dans l’UAL peut nécessiter jusqu’à 60 minutes. Ne concluez pas à l’inactivité d’un attaquant sur la dernière heure sans prendre en compte cette latence.
- Portée non rétroactive du litigation hold : les éléments purgés définitivement avant l’activation du gel ne peuvent en aucun cas être restitués.
Points clés à retenir
Section intitulée « Points clés à retenir »- Prioriser selon la vitesse d’expiration : les logs Entra Free expirent à 7 jours, le suivi des messages temps réel à 10 jours et les logs Entra P1/P2 à 30 jours. Concentrer les efforts sur ces flux dans les 4 premières heures.
- Le litigation hold fige les données, pas les logs : poser immédiatement le gel sur les boîtes des victimes, mais extraire les logs d’audit séparément.
- Découper les requêtes UAL : ne jamais lancer d’interrogation massive d’un seul bloc sous peine de plafonner à 5 000 événements. Segmenter par tranches de 6 à 12 heures.
- Activer le streaming SIEM sans attendre : configurer les paramètres de diagnostic vers Log Analytics dès le premier jour pour garantir la traçabilité pendant toute la durée des investigations.
- Sceller immédiatement les preuves par empreinte SHA-256 : garantir l’intégrité et la valeur probante des artefacts extraits en calculant leur hash cryptographique dès leur écriture sur disque.
Références
Section intitulée « Références »- Microsoft Learn : gestion du Litigation Hold dans Exchange Online
- Microsoft Learn : interroger le journal d’audit unifié (Search-UnifiedAuditLog)
- Microsoft Graph : API signIns
- Microsoft Entra ID : paramètres de diagnostic dans Microsoft Entra
- Microsoft Learn : guide de régulation (throttling) de Microsoft Graph