Récupérer des clés de registre supprimées et survivre au rejeu des journaux
9 min de lecture
La première fois que vous rejouez le journal de transactions d'une ruche et que vous regardez se matérialiser une valeur de registre qui ne devrait pas exister, vous comprenez pourquoi c'est une étape non optionnelle. Le registre vivant tel que Windows vous le montre est une vue des données. Le fichier de ruche en est une autre. Rejouer les journaux en donne une troisième. Comparer avec VSS en donne une quatrième. Les attaquants anti-forensiques comptent sur le fait que la plupart des analystes ne regardent que la première.
Cet article est le flux de récupération qui attrape le reste.
Ce que « supprimé » signifie en termes de registre
Le registre est un arbre copy-on-write à l'intérieur d'un fichier regf. Quand une clé ou une valeur est "supprimée", Windows ne met pas les octets à zéro. Il bascule le signe du champ taille de la cellule de négatif à positif, la marquant libre. Le bloc HBIN continue de contenir les anciens octets jusqu'à ce qu'une allocation ultérieure réutilise l'espace.
Cela s'applique aux valeurs supprimées, aux clés supprimées (dont
les cellules nk et enfants sont toutes marquées libres), et aux
cellules libérées pendant une réallocation quand une valeur dépasse
sa taille d'origine. Un analyseur regf qui parcourt les cellules
libres de la même façon que les cellules allouées fera remonter les
enregistrements supprimés avec leurs noms, types et données intacts.
La passe de récupération sur cellules non allouées
Les analyseurs matures font cela automatiquement :
- Parcourir chaque bloc HBIN.
- Pour chaque cellule libre, tenter de l'analyser comme un
enregistrement typé (
nk,vk,sk,lh,db, ...). - Valider contre les contraintes de format : longueur de nom sensée, comptes d'enfants raisonnables, horodatages plausibles, décalages embarqués pointant vers des cibles du type attendu.
- Faire remonter tout enregistrement qui valide.
La validation sépare une passe utile d'une passe qui crache des
détritus. Des octets aléatoires passent occasionnellement la
vérification du magique. Implémentations à connaître : yarp
(stricte, conservative), regipy (plus lâche, faux positifs
occasionnels, plus facile à scripter), et le plugin del de
RegRipper (parcourt la ruche et reconstruit les chemins quand
possible).
La sortie inclut typiquement les valeurs récupérées avec leurs noms,
types et données ; les clés récupérées avec leurs LastWrite ; et les
cellules "orphelines" qui valident mais ne peuvent pas être rattachées
à un chemin parce que le nk parent a disparu. Les orphelins ne sont
pas inutiles : une cellule vk pour une valeur nommée Debugger
contenant C:\Windows\Temp\evil.exe est informative même sans savoir
sous quelle sous-clé IFEO elle se trouvait.
Rejeu de journaux de transactions, fait correctement
Chaque ruche primaire sur Windows moderne est livrée avec .LOG1 et
.LOG2. Le schéma à double journal protège contre une perte de
courant pendant les écritures. Les rejouer n'est pas optionnel.
Les journaux contiennent des entrées de pages sales décrivant les modifications validées dans le journal mais pas encore flushées dans la ruche primaire. Chaque entrée dit "au décalage N, écrire ces M octets". Le rejeu les applique dans l'ordre.
Ce que le rejeu fait remonter :
Écritures en cours. Changements journalisés mais jamais persistés dans le fichier primaire. Ils apparaissent dans la ruche rejouée et nulle part ailleurs.
Séquences récemment validées. Même quand la primaire a été flushée, le journal peut encore contenir les écritures les plus récentes. Comparer la ruche post-rejeu à la primaire non rejouée vous dit ce qui a changé dans la dernière fenêtre de synchro.
Résidus de crash. Si le système a planté entre l'écriture du journal et le flush de la primaire, les journaux peuvent contenir des enregistrements que le registre vivant n'a jamais vus. Exactement les enregistrements que les attaquants ne s'attendent pas à ce que vous trouviez.
Numéros de séquence, bitmaps de pages sales, validation par entrée :
faites le rejeu correctement ou utilisez une bibliothèque qui le fait
déjà. Outils qui le gèrent automatiquement : yarp (--recover),
regipy (--apply_transaction_logs), RegRipper quand les
journaux sont dans le même répertoire, et l'analyseur de ce site.
Vérifiez que l'outil signale réellement avoir rejoué les journaux.
Certains sautent silencieusement le rejeu si les journaux semblent
propres.
Snapshots VSS : diffs de registre dans le temps
Volume Shadow Copy Service stocke des snapshots périodiques du volume entier, ruches incluses. Une installation par défaut en garde quelques-uns ; un système bien géré en garde une à deux semaines. Le mouvement : extraire chaque snapshot, extraire les ruches, lancer la récupération sur chaque, comparer.
Ce que le diff fait remonter :
Persistance qui apparaît dans la ruche vivante mais pas dans le
snapshot d'hier. Si le SOFTWARE d'hier n'avait pas de valeur à
Run\evil et celui d'aujourd'hui en a une, la persistance a été
installée entre ces deux moments.
Persistance qui apparaît et disparaît. Un snapshot d'il y a trois jours a une valeur Run ; celui d'hier non ; la ruche vivante non. L'attaquant a ajouté la persistance, exécuté la charge utile et nettoyé. Le snapshot s'en souvient.
Modifications à des valeurs existantes. Valeurs ImagePath de
services modifiées. Valeurs IFEO Debugger ajoutées et retirées.
Changements de permissions. Descripteurs de sécurité modifiés pour cacher du contenu. Le descripteur pré-modification vit dans le snapshot.
VSS est la meilleure défense unique contre le schéma anti-forensique
"éditer et annuler". vssadmin list shadows et Copy-Item contre le
chemin GLOBALROOT de chaque snapshot vous donneront les ruches.
shadowcopyview de NirSoft offre une interface plus conviviale pour
la même chose.
Ce que les attaquants peuvent et ne peuvent pas nettoyer
La réponse honnête : un attaquant déterminé avec droits admin peut nettoyer presque n'importe quoi. La réponse malhonnête est celle qui rassure. Restons honnêtes.
Ce que les attaquants font couramment :
Supprimer la valeur, espérer pour le mieux. La plupart font cela. La récupération depuis les cellules non allouées la ramène.
Supprimer la valeur et forcer un flush. reg flush ou
RegFlushKey. Les écritures suivantes dans le même HBIN peuvent
écraser la cellule libérée. Le taux de récupération chute mais n'est
pas nul.
Supprimer la valeur, flusher, et désactiver VSS.
vssadmin delete shadows /all. Efface les snapshots qui tiennent
l'état d'origine. La désactivation elle-même apparaît dans le journal
système EVTX (event ID 8224). Le signal
est "VSS a été effacé à l'heure T", et ce qui s'est passé juste avant
T est maintenant votre investigation.
Écraser le contenu de la cellule délibérément. Écrire une grosse valeur de détritus, forçant la réallocation, puis la supprimer. Nettoie la cellule libérée. Rare parce que cela nécessite de comprendre le format regf.
Effacement en mode noyau. Possible mais exotique. Si votre attaquant a cette capacité, vous avez de plus gros problèmes.
Ce que les attaquants ne peuvent pas nettoyer facilement : les snapshots VSS pris avant qu'ils n'aient obtenu admin, les journaux de transactions déjà flushés et intacts, les enregistrements Sysmon/EVTX des éditions registre, l'entrée MFT du fichier de ruche, le contenu d'une image RAM prise entre l'édition et le nettoyage, et les pages de registre qui ont basculé dans le swap dans le pagefile.
Un flux de récupération pratique
Pour toute question "l'attaquant a-t-il modifié et annulé" :
- Tout acquérir. Ruche primaire,
.LOG1,.LOG2, chaque copie VSS des mêmes, ruches de chaque profil disponible (y compris ceux périmés). - Rejouer les journaux sur chaque ruche. Utilisez un outil qui rapporte explicitement le statut de rejeu. Si l'outil dit qu'il a sauté le rejeu parce que les numéros de séquence correspondent, vérifiez en essayant un autre outil avec des vérifications plus lâches.
- Lancer la récupération sur cellules non allouées sur chaque.
yarp, regipy,
delde RegRipper. Capturez les enregistrements orphelins aussi bien que ceux dont le chemin est reconstructible. - Comparer entre VSS. Comparez les clés de persistance,
services, IFEO, tâches planifiées entre chaque snapshot. Des
outils comme
regdiffd'Eric Zimmerman fonctionnent ; un script personnalisé qui hashe le contenu de chaque sous-clé aussi. - Recouper avec EVTX. Cherchez les événements
Registry value set(Sysmon event 13) etRegistry object added or deleted(Sysmon event 12). Si Sysmon enregistrait le registre, vous obtenez les événements de changement avec horodatages. - Recouper avec les horodatages du fichier ruche. L'enregistrement MFT du fichier ruche a l'horodatage de modification du fichier. Des clusters soudains de modifications dans la chronologie sont des pistes.
- Pivoter vers mémoire et pagefile. Si vous avez une image
mémoire de la fenêtre pertinente, les pages registre en mémoire
peuvent porter l'état pré-nettoyage. Les plugins
registryde Volatility extraient cela. Le parseur pagefile gère les pages de ruches swappées.
La combinaison rejeu de journaux + diff VSS + récupération sur cellules non allouées attrape la vaste majorité des tentatives de nettoyage. Tout ce qui survit aux trois est un adversaire sophistiqué, et votre investigation doit escalader en conséquence.
Un piège courant
Les outils qui "récupèrent" des clés supprimées montrent parfois le même enregistrement depuis plusieurs sources sans vous le dire. Une valeur présente dans la ruche vivante, dans le rejeu de journal de transactions, et dans le snapshot VSS est une valeur, pas trois conclusions. Triez avec la déduplication en tête.
L'inverse compte aussi. Une conclusion qui apparaît dans exactement
une source est parfois la conclusion la plus intéressante précisément
parce qu'elle n'apparaît que dans une source. Une valeur IFEO
Debugger supprimée visible uniquement dans le rejeu LOG1 est le
genre de preuve qui clôt une affaire.
Pour aller plus loin
- Maxim Suhanov, documentation et exemples yarp : l'implémentation de référence pour les opérations regf de bas niveau y compris le rejeu de journal de transactions.
- Martin Korman, regipy : bibliothèque Python avec support de récupération et rejeu de journaux.
- Microsoft, Registry Hives and Transaction Logs : documentation du fournisseur, légère sur les détails.
- Willi Ballenthin, notes de recherche sur les journaux de transactions registre : récits historiques qui ont informé plusieurs implémentations open source.
Le registre est un artefact indulgent pour les analystes qui le traitent comme un ensemble à quatre sources (ruche vivante + journaux
- cellules non allouées + VSS) et impitoyable pour les analystes qui le traitent comme un fichier unique. L'approche à quatre sources prend plus de temps sur le premier dossier. Après cela, c'est la seule que vous utiliserez.