Aller au contenu

Détection forensique & investigation des attaques AiTM

Bien que les frameworks de reverse proxy Adversary-in-the-Middle (AiTM) tels qu’Evilginx parviennent à contourner l’authentification multi-facteurs (MFA) interactive, ils laissent derrière eux une signature forensique particulièrement visible et discriminante dans la télémétrie cloud. Parce que l’attaque dissocie fondamentalement la négociation d’authentification initiale des opérations cybercriminelles ultérieures, elle engendre des anomalies structurelles dans le routage IP, les identifiants de session, les attributs matériels et les flux de rafraîchissement de jetons.

Pour l’analyste forensique et l’opérateur de SOC, identifier une attaque AiTM n’exige pas de déchiffrer le flux TLS ni d’accéder au serveur proxy de l’attaquant. La détection repose sur la corrélation croisée entre les connexions interactives, les rejeux de jetons non interactifs, les alertes de risque Entra ID Protection et les altérations consécutives des services SaaS.

Ce guide expose la signature architecturale des attaques AiTM dans les journaux Microsoft Entra ID et Purview, détaille une chronologie d’intrusion réelle reconstituée, fournit des requêtes de détection KQL éprouvées et décrit le protocole d’endiguement d’urgence.


1. La signature forensique de la double IP (dual-IP ingress)

Section intitulée « 1. La signature forensique de la double IP (dual-IP ingress) »

La caractéristique structurelle déterminante d’une attaque AiTM est l’anomalie d’ingress à double adresse IP :

graph TD
subgraph "Phase 1 : Authentification de la Victime (Ingress Handshake)"
V_ACT[La victime s'authentifie via Evilginx]
V_IP[IP #1 : IP du Proxy Inverse / IP Victime<br/>App : My Apps / OfficeHome<br/>ResultType = 0 (Succès)<br/>MFA Satisfied = True]
V_ACT --> V_IP
end
subgraph "Phase 2 : Extraction du Cookie de Session"
V_IP --> PROXY_EXT[Evilginx capture ESTSAUTH & ESTSAUTHPERSISTENT<br/>Export vers la base de session du pirate]
end
subgraph "Phase 3 : Rejeu de Session par l'Attaquant (Ingress Opérationnel)"
PROXY_EXT --> ATT_ACT[L'attaquant injecte les cookies dans son navigateur]
ATT_IP[IP #2 : Infrastructure de l'Attaquant<br/>Proxy Résidentiel / VPN / VPS<br/>App : Exchange Online / Graph API / SharePoint<br/>Rafraîchissement Non Interactif]
ATT_ACT --> ATT_IP
end
subgraph "Détection de l'Anomalie Forensique"
V_IP -.->|Écart Structurel :<br/>ASN / FAI / Pays différents<br/>Changement de User-Agent<br/>Perte de l'état matériel conforme| DISCREPANCY{Delta Forensique}
ATT_IP -.-> DISCREPANCY
end
  1. Décorrélation interactive vs non-interactive :
    • La première connexion s’inscrit dans SigninLogs (Interactive) sous l’IP #1 (l’adresse de sortie de la victime ou l’IP d’hébergement du reverse proxy).
    • Entre 2 et 15 minutes plus tard, NonInteractiveUserSignInLogs ou CloudAppEvents enregistre des requêtes pour le même compte sous l’IP #2 (un proxy résidentiel commercial, un VPN ou un nœud de sortie anonymisé).
  2. Dégradation instantanée de la posture matérielle :
    • La connexion initiale peut refléter un équipement d’entreprise conforme (isCompliant: true, trustType: Workplace/AzureAdJoined).
    • La session rejouée perd toute télémétrie machine (isCompliant: false, deviceId: null, trustType: null), les cookies de session ne véhiculant aucun certificat matériel TPM.
  3. Incohérence des user-agents :
    • Un utilisateur s’authentifiant depuis un navigateur Chrome/Windows moderne génère soudainement des requêtes non interactives émanant de Linux/Python-requests, de Chromium headless ou d’une version de navigateur obsolète.

2. Sources télémétriques & attributs clés de corrélation

Section intitulée « 2. Sources télémétriques & attributs clés de corrélation »

L’investigation d’une attaque AiTM nécessite de recouper plusieurs tables dans Microsoft Sentinel ou Defender XDR :

Table TélémétriqueAttributs Clés de CorrélationPreuve Forensique Apportée
SigninLogsCorrelationId, IPAddress, UserAgent, MfaDetail, ConditionalAccessStatus, AppDisplayNameIdentifie la négociation d’authentification interactive initiale relayée par le proxy.
NonInteractiveUserSignInLogsOriginalRequestId, IPAddress, UserAgent, ResourceDisplayName, AutonomousSystemNumberRévèle l’attaquant rejouant les jetons volés depuis une IP/ASN étrangère pour accéder aux services SaaS.
UserRiskEventsRiskEventType, RiskLevel, Source, IpAddress, DetectionTimingTypeEnregistre les alertes d’Entra ID Protection : Atypical travel, Unfamiliar sign-in properties, Anomalous token.
CloudAppEventsAccountDisplayName, IPAddress, ActionType, RawEventDataRetrace les actions post-compromission : MailItemsAccessed, New-InboxRule, FileDownloaded.
sequenceDiagram
autonumber
participant V as Navigateur Victime
participant P as Proxy AiTM (IP 198.51.100.10)
participant E as Entra ID (STS)
participant A as Attaquant (IP 203.0.113.50)
participant M as Exchange Online
V->>P: Saisie des identifiants + validation MFA
P->>E: Relais de la négociation d'authentification
E-->>P: Émission du cookie ESTSAUTH (Consigné dans SigninLogs : IP 198.51.100.10)
P->>A: Extraction et livraison du cookie à l'attaquant
Note over A: 4 minutes plus tard...
A->>E: Présentation d'ESTSAUTH depuis l'IP 203.0.113.50 pour obtenir un jeton Exchange
E-->>A: Émission du jeton d'accès (Consigné dans NonInteractiveUserSignInLogs : IP 203.0.113.50)
A->>M: Requête vers l'API de messagerie (Consigné dans CloudAppEvents : MailItemsAccessed)

3. Chronologie reconstituée : anatomie d’une intrusion réelle

Section intitulée « 3. Chronologie reconstituée : anatomie d’une intrusion réelle »

L’enchaînement chronologique suivant illustre une compromission BEC classique opérée via Evilginx :

Horodatage (UTC)Table TélémétriqueÉvénement Observé / ValeurDéduction Forensique
14:02:11EmailEventsDistribué : Email de phishing ayant pour objet "URGENT : Vérification Paie T1".Distribution via un tenant partenaire compromis (voir Fiche 20).
14:04:35UrlClickEventsActionType = UrlAllowed, Url = https://login.target-portal.net/auth.L’utilisateur a cliqué sur le lien ; Safe Links n’a pas bloqué le domaine récent.
14:05:18SigninLogsResultType = 0, IP = 198.51.100.10 (VPS Hetzner), App = OfficeHome, MFA = Satisfied.La victime s’est authentifiée à travers le proxy Evilginx.
14:08:42UserRiskEventsRiskEventType = atypicalTravel, RiskLevel = High.Le moteur Microsoft détecte un déplacement impossible entre le pays de la victime et le proxy.
14:09:15NonInteractiveUserSignInLogsResultType = 0, IP = 203.0.113.50 (FAI Résidentiel, Nigeria), Resource = Exchange Online.Rejeu de jeton par l’attaquant. Utilisation d’ESTSAUTH depuis son infrastructure.
14:10:02CloudAppEventsActionType = MailItemsAccessed, OperationProperties[MailAccessType] = Sync.Synchronisation massive de la boîte \Inbox via Graph API (voir Fiche 17).
14:12:30CloudAppEventsActionType = New-InboxRule, RuleName = ..., DeleteMessage = True.Persistance & évasion. Règle cachée supprimant les alertes de sécurité entrantes.

4.1 corrélation entre connexion interactive et rejeu rapide depuis une IP étrangère

Section intitulée « 4.1 corrélation entre connexion interactive et rejeu rapide depuis une IP étrangère »

Détecter les cas où une connexion interactive est suivie dans un délai de 60 minutes d’une connexion non interactive émanant d’un pays ou ASN différent :

let TimeDelta = 60m;
let InteractiveSignins = SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType == 0
| project InteractiveTime=TimeGenerated, UserPrincipalName, InteractiveIP=IPAddress,
InteractiveCountry=Location, InteractiveASN=AutonomousSystemNumber,
InteractiveUA=UserAgent, CorrelationId;
let NonInteractiveSignins = NonInteractiveUserSignInLogs
| where TimeGenerated >= ago(7d)
| where ResultType == 0
| project NonInteractiveTime=TimeGenerated, UserPrincipalName, ReplayIP=IPAddress,
ReplayCountry=Location, ReplayASN=AutonomousSystemNumber,
ReplayUA=UserAgent, ResourceDisplayName;
InteractiveSignins
| join kind=inner (NonInteractiveSignins) on UserPrincipalName
| where NonInteractiveTime between (InteractiveTime .. (InteractiveTime + TimeDelta))
| where InteractiveIP != ReplayIP and (InteractiveCountry != ReplayCountry or InteractiveASN != ReplayASN)
| project UserPrincipalName, InteractiveTime, InteractiveIP, InteractiveCountry, InteractiveASN,
NonInteractiveTime, ReplayIP, ReplayCountry, ReplayASN, ResourceDisplayName
| sort by InteractiveTime desc

4.2 détection de la perte de conformité matérielle lors du rejeu

Section intitulée « 4.2 détection de la perte de conformité matérielle lors du rejeu »

Repérer les sessions ayant débuté sur un équipement conforme Intune ou hybride qui perdent instantanément leur état de conformité :

SigninLogs
| where TimeGenerated >= ago(7d)
| where ResultType == 0
| extend DeviceState = tostring(DeviceDetail.isCompliant)
| project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName, DeviceState, UserAgent
| join kind=inner (
NonInteractiveUserSignInLogs
| where TimeGenerated >= ago(7d)
| where ResultType == 0
| extend ReplayDeviceState = tostring(DeviceDetail.isCompliant)
| project ReplayTime=TimeGenerated, UserPrincipalName, ReplayIP=IPAddress,
ReplayApp=ResourceDisplayName, ReplayDeviceState, ReplayUA=UserAgent
) on UserPrincipalName
| where DeviceState == "true" and (ReplayDeviceState == "false" or isempty(ReplayDeviceState))
| where ReplayTime between (TimeGenerated .. (TimeGenerated + 30m))
| where IPAddress != ReplayIP
| project UserPrincipalName, TimeGenerated, IPAddress, DeviceState, ReplayTime, ReplayIP, ReplayDeviceState, ReplayApp
| sort by TimeGenerated desc

4.3 chasse aux hébergeurs VPS atypiques pour les connexions utilisateurs

Section intitulée « 4.3 chasse aux hébergeurs VPS atypiques pour les connexions utilisateurs »

Repérer les authentifications interactives issues d’ASNs de fournisseurs de VPS (DigitalOcean, Hetzner, Linode, OVH) qui ne correspondent jamais aux réseaux d’entreprises ou de collaborateurs à domicile :

let KnownHostingASNs = dynamic([14061, 24940, 63949, 16276, 51167]); // DigitalOcean, Hetzner, Linode, OVH, Contabo
SigninLogs
| where TimeGenerated >= ago(14d)
| where ResultType == 0
| where AutonomousSystemNumber in (KnownHostingASNs)
| project TimeGenerated, UserPrincipalName, IPAddress, AutonomousSystemNumber, Location, AppDisplayName, UserAgent
| sort by TimeGenerated desc

5. Protocole d’endiguement rapide Face à une attaque AiTM

Section intitulée « 5. Protocole d’endiguement rapide Face à une attaque AiTM »

Lorsqu’une compromission AiTM est confirmée, la réponse technique doit être foudroyante. Une simple réinitialisation de mot de passe n’invalide pas immédiatement les cookies de session ou les refresh tokens actifs si l’évaluation continue (CAE) n’est pas strictement imposée.

graph TD
ALERT[Compromission AiTM Confirmée] --> STEP1[1. Révocation Immédiate des Jetons & Sessions<br/>Revoke-MgUserSignSession]
STEP1 --> STEP2[2. Réinitialisation du Mot de Passe<br/>Rotation des condensats d'authentification]
STEP2 --> STEP3[3. Audit & Purge des Méthodes MFA<br/>Supprimer numéros de secours et clés FIDO frauduleuses]
STEP3 --> STEP4[4. Audit des Règles de Boîte & Transferts<br/>Supprimer les redirections et règles de masquage]
STEP4 --> STEP5[5. Contrôle des Consentements OAuth Applicatifs<br/>Vérifier qu'aucune application n'a obtenu offline_access]
Fenêtre de terminal
# Prérequis : Microsoft.Graph.Users, ExchangeOnlineManagement
# Connect-MgGraph -Scopes "User.ReadWrite.All"
# Connect-ExchangeOnline
$victimUPN = "alice.dupont@target.com"
Write-Host "[!] DÉCLENCHEMENT DE L'ENDIGUEMENT D'URGENCE POUR LA VICTIME AiTM : $victimUPN" -ForegroundColor Red
# 1. Révocation immédiate de toutes les sessions actives
Revoke-MgUserSignSession -UserId $victimUPN
Write-Host "[+] Sessions Entra ID et refresh tokens RÉVOQUÉS avec succès." -ForegroundColor Green
# 2. Contrôle des méthodes MFA enregistrées
$mfaMethods = Get-MgUserAuthenticationMethod -UserId $victimUPN
Write-Host "[*] Examen des méthodes d'authentification enregistrées :" -ForegroundColor Yellow
$mfaMethods | Select-Object Id, AdditionalProperties | Format-List
# 3. Détection des règles de boîte malveillantes
$rules = Get-InboxRule -Mailbox $victimUPN
$suspiciousRules = $rules | Where-Object { $_.ForwardTo -or $_.RedirectTo -or $_.DeleteMessage }
if ($suspiciousRules) {
Write-Warning "[!] Règles de boîte suspectes détectées :"
$suspiciousRules | Format-Table Name, ForwardTo, RedirectTo, DeleteMessage
# Décommenter pour supprimer automatiquement :
# $suspiciousRules | ForEach-Object { Remove-InboxRule -Mailbox $victimUPN -Identity $_.Identity -Confirm:$false }
}
# 4. Vérification des transferts automatiques au niveau de la boîte
$mbx = Get-Mailbox -Identity $victimUPN
if ($mbx.ForwardingSmtpAddress -or $mbx.ForwardingAddress) {
Write-Error "[!] Transfert externe configuré vers : $($mbx.ForwardingSmtpAddress) / $($mbx.ForwardingAddress)"
# Set-Mailbox -Identity $victimUPN -ForwardingSmtpAddress $null -ForwardingAddress $null
}