Retour à tous les articles

La liste des horodatages dans un .pf est ce que la plupart des analystes lisent. La liste des fichiers touchés par l'exécutable est ce qu'ils survolent. Cet ordre est à l'envers, et j'ai construit plus d'une enquête à partir de motifs trouvés dans la liste de chargement que les horodatages seuls n'auraient jamais fait remonter.

Ce billet traite de la lecture du tableau de ressources. Ce qu'il capture. Ce qu'il ne capture pas. Et les trois ou quatre formes qui vous disent que quelque chose cloche dès que vous triez la bonne colonne dans le bon sens.

Ce que contient réellement la liste de chargement

Le service Prefetch observe les dix premières secondes de la vie d'un processus. Chaque fichier pour lequel le noyau résout un chemin durant cette fenêtre finit dans le tableau de métriques de fichiers, le chemin réel étant stocké sous forme de chaîne UTF-16LE dans la Section C. Au moment où vous lisez la sortie parsée, ces chemins résolus ressemblent à \DEVICE\HARDDISKVOLUME2\Windows\System32\kernel32.dll et \DEVICE\HARDDISKVOLUME2\Users\bob\Documents\contract.docx.

C'est plus large que « DLL chargées ». Cela inclut :

  • Toutes les DLL chargées par le processus du binaire, y compris celles en delay-load, tant que le chargement a lieu dans la fenêtre de traçage.
  • Les fichiers ouverts (au sens de CreateFile) par le processus. Les lectures en particulier, parce que Windows trace les défauts de page ; certaines écritures aussi, selon la version.
  • Les fichiers de configuration, de données, de documents, de hives de registre si le processus les ouvre directement via le système de fichiers plutôt que via l'API registre.
  • Les DLL et fichiers touchés par les processus enfants que le binaire a lancés dans ses dix premières secondes, sur certaines builds Windows.

Le plafond est d'environ 1024 entrées par .pf. Sur des binaires très bavards, on atteint le plafond et le reste est jeté. Sur la plupart des binaires, on obtient l'ensemble complet.

La fenêtre de traçage est fixée à environ dix secondes. Un binaire qui se tient tranquille trente secondes puis charge sa vraie charge utile aura une liste trompeusement petite, parce que le gros du travail s'est fait hors fenêtre.

Ce qu'elle ne contient pas

Les écritures sont partiellement enregistrées mais pas de manière fiable. Les fichiers que le processus a créés et n'a jamais rouverts peuvent ne pas figurer dans la liste. Si vous avez besoin d'un enregistrement complet des fichiers écrits, vous avez besoin de Sysmon Event ID 11 dans l'EVTX ou du journal USN.

La ligne de commande n'est pas dans la liste de chargement. Les arguments passés à l'exécutable ne figurent dans aucune partie du fichier Prefetch. Si le binaire a lu ses arguments puis a ouvert des fichiers en fonction, les chemins résultants apparaissent. Les arguments eux-mêmes, non.

Les sockets réseau ne sont pas dans la liste de chargement. Prefetch est un artefact de système de fichiers.

Les enfants lancés en dehors de la fenêtre de dix secondes ne sont pas dans la liste de chargement du parent, bien qu'ils aient leurs propres .pf (sous réserve des habituelles précautions SSD/serveur).

Motif un : détournement d'ordre de recherche DLL

Le motif de détection classique. Un binaire de confiance comme winword.exe ou mstsc.exe devrait charger ses DLL depuis \System32\ (et un petit nombre de répertoires bien connus). Un .pf dont la liste de chargement montre le binaire de confiance chargeant version.dll ou cryptbase.dll depuis \AppData\Local\Temp\ ou \Users\Public\ est un détournement d'ordre de recherche jusqu'à preuve du contraire.

Les formes à repérer :

\DEVICE\HARDDISKVOLUME2\WINDOWS\SYSTEM32\KERNEL32.DLL    <- normal
\DEVICE\HARDDISKVOLUME2\USERS\PUBLIC\VERSION.DLL          <- pas normal

En l'absence de baseline connue propre, la règle est : les DLL système qui chargent depuis ailleurs que \Windows\System32\ (ou \SysWOW64\ pour les processus 32 bits, ou \Program Files\<éditeur>\ pour les DLL redistribuées par l'éditeur) méritent un examen approfondi. Certaines seront des side-by-side assemblies légitimes. La plupart, non.

Triez la liste de chargement par préfixe de chemin, groupez tout ce qui est hors \Windows\ et \Program Files\, et regardez ce qui reste. Sur un hôte propre, l'essentiel de ce qui reste sera constitué des fichiers de données propres au binaire et des documents utilisateur. Sur un hôte compromis, les DLL déposées seront flagrantes.

Motif deux : chemins de configuration de malware

Le malware de masse a tendance à stocker sa configuration à un emplacement fixe par rapport à lui-même ou à son répertoire d'installation. Des noms comme config.bin, settings.dat, tox.lic, client.json et key.dat apparaissent dans les listes de chargement avec une régularité déprimante. Le chemin est généralement sous \AppData\Roaming\<un dossier>\, \ProgramData\<un dossier>\, ou directement à côté du binaire.

Cela vous donne deux choses. D'abord, l'existence d'un fichier de configuration à un chemin précis à un moment précis, même si le fichier a été supprimé depuis. Ensuite, un nom à chercher dans le reste de l'hôte : si \AppData\Roaming\nzhxxk\config.bin figure dans une liste de chargement .pf, vous pouvez pivoter vers la MFT, le journal USN et le registre pour savoir quand la configuration a été écrite, modifiée et supprimée.

J'ai construit des chronologies où la liste de chargement Prefetch était la seule chose à m'indiquer qu'un fichier de configuration avait existé. Le fichier avait disparu, le répertoire avait disparu, et la seule preuve survivante était la chaîne de chemin cuite dans une Section C de .pf.

Motif trois : ouvertures de documents

Si la question est « cet utilisateur a-t-il ouvert ce document », Prefetch peut corroborer. Un .pf pour winword.exe ou acrord32.exe dont la liste de chargement contient \Users\<utilisateur>\Documents\<docname> ou \Users\<utilisateur>\Downloads\<docname> dit que l'application a ouvert ce fichier durant une de ses exécutions tracées.

Les réserves : la liste de chargement ne vous dit pas quelle exécution a ouvert quel fichier. Si le .pf montre huit horaires d'exécution et la liste trois documents, vous ne pouvez pas mapper directement « document X a été ouvert pendant l'exécution Y ». La liste est cumulative sur la fenêtre de traçage des exécutions les plus récentes, les anciennes entrées étant écrasées au fur et à mesure que le binaire est re-tracé.

Pour des ouvertures de documents par instance, combinez les preuves Prefetch avec les fichiers LNK, les jump lists et les propres listes MRU d'Office dans le registre. L'entrée Prefetch corrobore que le chemin a été résolu par le processus ; les artefacts par utilisateur disent quand et d'où l'utilisateur l'a invoqué.

Motif quatre : divulgation de configuration par des binaires légitimes

Celui-ci ressort davantage dans les affaires de menace interne et propriété intellectuelle que dans les affaires de malware, mais il mérite d'être signalé.

Quand un processus touche un fichier, ce chemin va dans la liste de chargement, que le fichier soit sensible ou non. Si un script a fait tourner findstr.exe sur un répertoire RH, le .pf de findstr.exe enregistre les chemins résolus des fichiers réellement ouverts. Idem pour tar.exe, 7z.exe, xcopy.exe, et tout autre outil d'archivage ou de copie.

Ce que cela signifie en pratique : quand vous soupçonnez une exfiltration de données impliquant un utilitaire connu, sortez le .pf de cet utilitaire et regardez sa liste de chargement. Les fichiers que l'utilitaire a touchés y seront. Vous n'aurez pas les arguments de ligne de commande, mais vous aurez une énumération partielle des fichiers impliqués.

Ce motif est aussi utile pour détecter de la reconnaissance. Un .pf pour whoami.exe ou net.exe est normal sur la plupart des hôtes ; un .pf pour nltest.exe avec des chemins \Windows\debug\ dans sa liste de chargement est de la reconnaissance jusqu'à preuve du contraire. La liste de chargement vous dit ce que l'outil a réellement interrogé.

Motif cinq : archéologie du répertoire temp

Les répertoires \AppData\Local\Temp\ et \Windows\Temp\ accumulent des exécutables et DLL que les attaquants laissent derrière eux. Beaucoup sont supprimés, parfois en quelques secondes après usage. Les .pf des binaires qui les ont lus, eux, survivent.

Une liste de chargement Prefetch pour rundll32.exe montrant \AppData\Local\Temp\evil.dll vous dit que cette DLL a été chargée par rundll32.exe, que la DLL était à ce chemin à ce moment, et (puisque le .pf de rundll32.exe est mis à jour à chaque exécution) qu'une exécution récente de rundll32 a précisément fait cela. Si le fichier n'est plus là, vous avez la preuve de son existence et de son usage antérieurs.

Combinez avec les horodatages de résolution de chemins de la liste de chargement (champs début/durée de la Section A) et vous pouvez parfois ordonner les chargements dans la fenêtre de traçage. La granularité n'est pas formidable mais elle suffit à distinguer « chargé immédiatement au démarrage » de « chargé en fin de fenêtre de traçage ».

Travailler la liste de chargement efficacement

Un workflow qui paie :

  1. Parsez le .pf vers un CSV plat avec colonnes : exécutable, chemin de l'exécutable, compteur d'exécutions, dernier run, chemin chargé. Une ligne par paire (exécutable, chemin chargé).
  2. Filtrez les chemins commençant par \Windows\, \Program Files\, \Program Files (x86)\. C'est surtout du bruit sur un hôte où vous n'avez pas encore identifié d'anomalies.
  3. Triez le reste par exécutable, puis par chemin. Regardez ce que chaque binaire a touché en dehors des répertoires standards.
  4. Pour les binaires qui ont touché des répertoires inscriptibles par l'utilisateur (\AppData\, \ProgramData\, \Users\Public\, \Temp\), vérifiez si les fichiers sont encore là. Couplez avec la MFT.
  5. Pour les hits intéressants, sortez les entrées correspondantes Sysmon EID 11 (file create) ou EID 7 (image load) dans l'EVTX pour corroborer.

L'étape 2 est ce qui rend la liste de chargement traitable. Un dump brut de liste de chargement pour un hôte chargé peut comporter des centaines de milliers de lignes. Filtrer vers des chemins non-système ramène ça à quelque chose qu'on peut vraiment lire.

Ce que la liste de chargement n'est pas

La liste de chargement n'est pas un journal du comportement du processus. C'est un instantané de chemins que Windows a résolus durant une courte fenêtre de traçage. Traitez-la comme une vue à fort rappel et faible précision de « fichiers que ce processus a touchés ». Certaines entrées seront accessoires. Certaines seront des preuves. Le talent consiste à savoir lesquelles sont lesquelles.

La bonne nouvelle est que les motifs ci-dessus tiennent pour la plupart des binaires et acteurs de menace que j'ai vus en pratique. Une fois que vous avez passé une après-midi à regarder des listes de chargement sur quelques dizaines de fichiers Prefetch issus d'une vraie intrusion, vous commencerez à repérer les anomalies avant même de pouvoir expliquer pourquoi.

Pour aller plus loin