Retour à tous les articles

Les attaquants connaissent Prefetch. Certains essaient de le contrer. La plupart essaient et échouent, parce que ce qu'il faut faire pour supprimer Prefetch laisse ses propres marques, et que ce qu'on peut supprimer ne compte que si l'on nettoie aussi tout ce que le binaire a touché, ce que personne ne fait complètement.

Ce billet est un parcours des techniques anti-forensiques que j'ai vues réellement utilisées contre Prefetch, par ordre de coût pour l'attaquant et de gêne pour l'enquête.

Désactiver le service Prefetcher

L'approche la plus complète. Mettez HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters\EnablePrefetcher à 0. Redémarrez. Prefetch cesse d'écrire de nouveaux fichiers .pf pour les nouveaux processus.

Trois problèmes pour l'attaquant.

Premièrement, la modification du registre elle-même est bruyante. Le LastWrite de PrefetchParameters se met à jour à l'instant où la valeur est écrite. Si vous disposez de journaux de transactions du registre, de snapshots VSC ou même d'une baseline de la valeur sur le même hôte avant l'incident, le changement est visible. La valeur forensique de « EnablePrefetcher vient d'être modifié deux heures avant le début de la fenêtre suspecte » est élevée.

Deuxièmement, la modification n'est pas immédiate. Le service Prefetcher cache son état en mémoire. De nouvelles entrées Prefetch continuent à être écrites pendant un certain temps après le changement, généralement jusqu'au redémarrage du système ou du service. Un attaquant qui bascule le registre et lance ses outils trente secondes plus tard peut malgré tout avoir produit des .pf. J'ai vu ce cas plus d'une fois.

Troisièmement, le changement n'efface pas le répertoire Prefetch existant. Tous les .pf antérieurs à la désactivation sont toujours là. Si l'attaquant ne les supprime pas aussi, vous avez la trace de tout ce qui a tourné sur l'hôte jusqu'au moment du changement.

Détection : cherchez dans la hive SYSTEM le LastWrite de PrefetchParameters et comparez à votre chronologie. Si la valeur est à 0 ou 1 (alors que la politique de l'hôte dit 3), vérifiez les snapshots VSC pour savoir quand le changement a eu lieu. Si vous trouvez un changement dans la fenêtre suspecte, c'est en soi un événement à instruire, indépendamment de ce qui a été fait ensuite.

Supprimer des fichiers .pf individuels

La technique la plus courante, et de loin. Après avoir exécuté un outil, l'attaquant supprime simplement C:\Windows\Prefetch\TOOLNAME-XXXXXXXX.pf. Cela nécessite des droits administrateur (le répertoire Prefetch est protégé), mais quiconque exécute des outils d'attaque les a généralement.

La suppression réussit. Le .pf a disparu. L'évidence aussi.

Ce qui survit :

  • La MFT. Chaque .pf supprimé laisse une entrée MFT qui persiste jusqu'à la réutilisation du slot. L'entrée conserve le nom de fichier, la taille, les horodatages et (si l'entrée est encore résidente ou peu après la suppression) parfois le contenu. Une suppression ciblée d'un seul .pf restera visible dans la MFT comme « fichier supprimé, nom PREFETCH/EVIL-AABBCCDD.pf » jusqu'à ce qu'autre chose réclame l'entrée.
  • Le journal USN. La suppression produit un enregistrement USN FILE_DELETE|CLOSE portant le nom du .pf. Sur un hôte chargé le journal tourne, mais sur la plupart des hôtes vous voyez des semaines d'historique USN. La suppression y figure.
  • Les horodatages NTFS propres au répertoire Prefetch. L'heure Modified du répertoire se met à jour à chaque ajout ou suppression de fichier. Avec une baseline, la suppression est visible. Avec des VSC, vous voyez l'état du répertoire d'avant.
  • Les autres artefacts qui référençaient le même binaire. AmCache a encore le hash. Shimcache a encore le nom du binaire. La MFT a encore le binaire s'il n'a pas été effacé aussi. L'historique d'exécution utilisateur du registre a encore le programme dans UserAssist ou RunMRU. Prefetch est l'un de plusieurs.

Détection : énumérez les entrées MFT supprimées du répertoire Prefetch. Tout nom de .pf dans la liste des entrées supprimées qui n'existe pas dans le répertoire vivant est une suppression. Combinez avec les enregistrements USN. Le nom donne en général le nom de l'exécutable ; de là, vous pivotez vers AmCache, Shimcache et le reste.

J'ai clos des dossiers dans lesquels le seul artefact direct d'un outil d'attaquant connu était l'entrée MFT d'un .pf supprimé. Le .pf lui-même avait disparu, mais le résidu de la suppression nommait l'outil sans ambiguïté.

Effacer l'ensemble du répertoire Prefetch

Une version plus agressive : supprimer tout C:\Windows\Prefetch\. Certains attaquants le font systématiquement dans leur nettoyage.

Les mêmes résidus survivent. La MFT montre maintenant des dizaines ou des centaines de noms de .pf supprimés. Le journal USN affiche les suppressions en séquence, souvent à quelques secondes d'intervalle. Les horodatages NTFS du répertoire passent à l'heure du wipe.

Un répertoire Prefetch vide (ou ne contenant que NTOSBOOT-XXXXXXXX.pf, régénéré au boot) sur une station qui fonctionne depuis des mois est un drapeau rouge évident. L'état naturel du répertoire sur un hôte qui tourne depuis longtemps est de plusieurs centaines de fichiers. Vide signifie que quelqu'un l'a vidé.

Détection : comptez les entrées dans le répertoire vivant et comparez au compte attendu pour l'âge et l'usage de l'hôte. Des répertoires Prefetch vides ou presque vides sur des hôtes anciens sont une anomalie à expliquer, pas un constat à accepter.

Le truc du « renommer avant exécution »

L'attaque maligne. Copiez votre outil sur disque, renommez-le en quelque chose d'innocent, exécutez-le, puis renommez-le ou supprimez-le. L'idée : le nom du .pf embarque le nom du binaire de l'exécutable, donc un binaire nommé update.exe produit UPDATE.EXE-XXXXXXXX.pf. En vous mêlant aux entrées Prefetch existantes de update.exe de l'hôte, vous vous cachez à découvert.

C'est partiellement efficace, et très détectable.

Ce qui marche pour l'attaquant : le nom du .pf n'est effectivement que le nom de l'exécutable au moment de l'exécution. Renommez mimikatz.exe en update.exe avant exécution et vous obtenez UPDATE.EXE-XXXXXXXX.pf, pas MIMIKATZ.EXE-XXXXXXXX.pf. Un analyste qui grepe MIMI dans la liste du répertoire Prefetch ne trouvera rien.

Ce qui ne marche pas pour l'attaquant :

  • Le hash dans le nom encode toujours le chemin. Une mimikatz renommée dans C:\Users\Public\update.exe produit un hash différent de la update.exe légitime dans C:\Program Files\<éditeur>\update.exe. Vous pouvez repérer le nom dupliqué avec deux hashes différents.
  • La liste de chargement trahit toujours le binaire. La mimikatz renommée charge toujours les DLL de la famille sekurlsa.dll et touche des chemins voisins de LSASS. La Section C du .pf montrera ces chemins quel que soit le nom de l'exécutable.
  • Le chemin de l'exécutable que Prefetch enregistre reste le vrai chemin d'où le binaire a tourné. Même renommé, le binaire vit quelque part, et le .pf sait où. C:\Users\Public\update.exe comme chemin Prefetch sur un hôte où update.exe devrait vivre sous Program Files est en soi une anomalie.

Détection : ne cherchez jamais par nom d'exécutable seul. Cherchez dans le répertoire Prefetch tout binaire dont le chemin enregistré est en dehors des répertoires standards système ou de programme, quel que soit le nom. L'ensemble des « binaires aux chemins inscriptibles par l'utilisateur » sur un hôte normal est petit. Le truc du renommage s'ajoute à cet ensemble ; il ne s'y fond pas.

Modifier les fichiers .pf in-place

L'approche avancée. Certains attaquants ont écrit des outils qui éditent des fichiers Prefetch : réduire le compteur d'exécutions, supprimer un horodatage d'exécution, retirer un chemin de la liste de chargement. J'ai vu cela tenté deux fois en sept ans de pratique.

C'est très fragile. Le format Prefetch a des offsets internes, des champs de taille de section, et des sommes de contrôle (sur certaines versions). Éditer le compteur sans réécrire le reste de la structure est faisable. Éditer la liste de chargement nécessite de recalculer les offsets à travers la Section A et la Section C et est rarement fait correctement.

Détection : validation structurelle. Faites passer le fichier dans un parser strict qui vérifie chaque offset et chaque longueur contre les tailles déclarées par le fichier. Des outils comme PECmd signalent les fichiers incohérents, sans toujours refuser de les parser. Un .pf dont les tailles internes ne s'additionnent pas à la taille sur disque, ou dont la Section A référence des offsets de chaînes en dehors de la Section C, est soit corrompu, soit altéré.

Je n'ai pas personnellement attrapé de tampering in-place réussi sur une enquête réelle. Les tentatives que j'ai vues produisaient des fichiers qui cassaient des invariants évidents. Cela dit, la technique est plausible pour un attaquant sophistiqué, et je ne ferais pas l'hypothèse qu'un .pf est canonique seulement parce qu'il parse.

Pourquoi Prefetch survit plus que Shimcache

Shimcache n'écrit qu'à l'arrêt. Un attaquant qui sait ce qu'il fait peut faire disparaître Shimcache en arrêtant le système sale, ou en écrasant la valeur de registre AppCompatCache avant l'arrêt.

Prefetch écrit en continu, comme effet secondaire du fonctionnement normal. Il n'y a pas de « flush à l'arrêt » que vous pouvez sauter. Pour empêcher l'écriture d'un .pf, il faut arrêter le service Prefetch avant que le binaire ne tourne, ce qui demande la modification de registre ci-dessus, qui est en soi bruyante. Pour retirer un .pf après écriture, il faut le supprimer, ce qui laisse des résidus MFT et USN.

C'est pourquoi je fais davantage confiance à Prefetch qu'à Shimcache pour les affirmations d'exécution. Non parce que Prefetch est plus précis (Shimcache couvre plus de binaires sous certains angles), mais parce que Prefetch est plus difficile à supprimer sans laisser de traces.

Contre-mesures du défenseur

Si vous êtes en défense, ce qui suit complique la vie d'un attaquant qui essaie de nettoyer Prefetch :

  1. Faites suivre le journal USN à un SIEM. Même un flux échantillonné détecte les suppressions massives de .pf en quelques secondes.
  2. Auditez les écritures de registre dans PrefetchParameters via la politique d'audit registre EVTX ou Sysmon EID 13. Tout changement à EnablePrefetcher ou EnableSuperfetch mérite une alerte.
  3. Snapshotez la liste du répertoire Prefetch chaque nuit. Un diff de hier soir à ce matin attrape les suppressions massives et les créations en masse.
  4. Snapshotez aussi les bases SRUM et AmCache. Défense en profondeur sur les artefacts d'exécution signifie qu'un attaquant doit nettoyer quatre choses, pas une.
  5. Bloquez les écritures dans C:\Windows\Prefetch\ depuis des contextes non-SYSTEM via WDAC ou AppLocker. La plupart des attaquants tourneront en SYSTEM et contourneront, mais relever la barre est rarement gaspillé.

Ce que je dis aux clients

Prefetch est l'artefact que les attaquants pensent le plus souvent avoir nettoyé et qu'ils ont le plus souvent laissé. La technique qui marche réellement (désactiver, exécuter, réactiver) est la plus coûteuse opérationnellement, demande un timing de redémarrage, et est la plus détectable via le suivi des changements de registre. La plus populaire (supprimer le .pf après exécution) laisse le résidu sur lequel vous pivotez dans MFT, USN et artefacts voisins.

Traitez un répertoire Prefetch vide ou récemment élagué non comme l'absence de preuve, mais comme la preuve d'une intervention. Puis trouvez l'intervention.

Pour aller plus loin