← Retour au blog

Alternate Data Streams : le second attribut $DATA que tout le monde oublie

· Lecture 6 min

ADS est la fonctionnalité NTFS qui continue de surprendre les analystes débutants. Un fichier peut avoir plus d'un attribut $DATA. Le non nommé est celui dont dir vous montre la taille. Tout le reste, tout ce qui contient deux-points dans son identifiant, est invisible aux outils que la plupart des gens utilisent. Les attaquants le savent. Microsoft le sait. L'auditeur qui examine votre rapport IR devrait le savoir aussi.

Le mécanisme, en bref

Dans l'enregistrement MFT, l'attribut de type 0x80 est $DATA. L'en-tête porte un nom optionnel. Un seul enregistrement peut porter de nombreux attributs $DATA : un non nommé (le flux primaire) et un nombre quelconque de nommés. Depuis l'espace utilisateur, vous y accédez avec filename:streamname.

echo payload > readme.txt:nope
type readme.txt:nope

readme.txt fait zéro octet selon toutes les mesures que montre Explorer. Le flux nommé nope contient la charge utile. Même enregistrement MFT. Même entrée d'index du répertoire parent. Deux attributs de données indépendants.

Ce n'est pas un bug. C'est une décision de conception de 1993 que NTFS a héritée de HPFS pour permettre à Services for Macintosh d'attacher des resource forks. Presque personne n'utilise plus ADS pour cela. Tous les autres, Microsoft compris, l'utilisent pour des métadonnées ad hoc.

Là où Windows lui-même dépose des ADS

Zone.Identifier est le célèbre. Edge, Chrome, Firefox et Outlook l'ajoutent à tout ce qui a franchi une frontière de sécurité. Le contenu est un fragment INI avec l'URL source, le référent et une ligne ZoneId=3 qui déclenche les protections Mark-of-the-Web dans Office et SmartScreen. Si vous lisez une MFT et qu'un binaire dans Downloads\ n'a pas de Zone.Identifier, demandez-vous pourquoi. Quelqu'un a peut-être exécuté Unblock-File ou copié le fichier à travers une archive qui supprime les flux.

D'autres flux bénis par Microsoft que vous rencontrerez :

  • $KSP sur les fichiers de disposition de clavier de langues asiatiques.
  • OECustomProperty et consorts sur les pièces jointes Outlook enregistrées sur disque.
  • Données reparse Wof sur les fichiers compressés sous WIMBoot et CompactOS.
  • SmartScreen sur les exécutables que Defender a empreintés.
  • encryptable sur les répertoires de cache ConfigMgr.

Ceux-ci apparaissent constamment. Apprenez à quoi ressemble votre baseline avant de marquer des flux comme suspects.

Ce que font réellement les attaquants avec ADS

Trois schémas se répètent :

  1. Cachette de charge utile, lanceur séparé. Le fichier visible est anodin (un document Word, un PDF, un fichier de licence). Le flux nommé contient le vrai PE. WMI, wmic process call create ou rundll32 lance legit.docx:payload.exe directement. Defender scanne effectivement les flux nommés de nos jours, mais beaucoup d'EDR ne le font toujours pas quand un flux est créé par un processus de confiance.
  2. Cachette living-off-the-land. Charges utiles PowerShell écrites dans ads:script.ps1 puis exécutées avec Get-Content -Stream. Étonnamment courant dans les rétainers red team parce que ça survit à une recherche IOC basée uniquement sur le chemin.
  3. Persistance dans des flux alternatifs de fichiers système. C:\Windows\System32\drivers\etc\hosts:backdoor est l'exemple manuel. Le fichier hosts paraît intact, l'horodatage peut même être d'origine, et la plupart des outils de surveillance d'intégrité de fichiers ne regardent jamais au-delà du flux non nommé.

La propriété partagée : vous ne pouvez pas les voir avec dir, vous ne pouvez pas les voir dans Explorer, et vous ne pouvez pas les voir en hachant le fichier visible. Vous pouvez les voir en lisant l'enregistrement MFT.

Les détecter sur un hôte en activité

dir /R énumère les flux dans cmd. Get-Item -Stream * de PowerShell fait pareil avec une sortie plus propre. streams.exe de Sysinternals parcourt un arbre. Tous les trois fonctionnent sur le volume sur lequel vous êtes. Aucun n'aide si le volume est hors ligne ou si vous ne savez pas quels fichiers vérifier.

dir /R C:\Users\bob\Documents\
Get-ChildItem -Recurse | ForEach-Object { Get-Item $_.FullName -Stream * } |
  Where-Object Stream -ne ':$DATA'

Cette deuxième ligne énumère chaque flux non par défaut dans une arborescence. Exécutez-la sur une installation Windows fraîche et vous aurez déjà des centaines de résultats, surtout Zone.Identifier. Filtrez sur les flux plus grands que quelques centaines d'octets et le bruit chute rapidement.

Pourquoi la MFT est la meilleure loupe

Les commandes sur l'hôte énumèrent par fichier. Elles manquent ce que vous n'avez pas pensé à vérifier. La MFT, non. Chaque attribut $DATA, nommé ou non, est écrit dans l'enregistrement au type d'attribut 0x80. Parcourez la table, listez les attributs $DATA de chaque enregistrement avec leurs noms et tailles, et vous avez un inventaire exhaustif de tous les flux du volume en une seule passe.

Quelques avantages que cela vous apporte par rapport à l'énumération par fichier :

  • Des flux sur des fichiers dans des répertoires que vous n'auriez jamais regardés, y compris C:\Windows\Temp\ et C:\$Recycle.Bin\.
  • Des flux sur des fichiers supprimés. L'enregistrement MFT survit à la suppression ; l'ADS reste listé dans le flux d'attributs. fls et istat du Sleuth Kit les montreront ; MFTECmd et la CLI omerbenamram/mft aussi.
  • Des flux résidents dont le contenu se trouve inline dans l'enregistrement MFT. De petites charges (loaders PowerShell, blobs base64, configs encodées) tiennent fréquemment dans le slack d'un enregistrement de 1 024 octets. Vous pouvez les lire directement depuis l'extrait MFT sans jamais toucher la zone de données. Voir données résidentes pour le seuil de taille.
  • Des noms de flux. La MFT préserve le nom choisi par l'attaquant. :payload.exe paraît anodin dans une liste de tailles de fichiers ; il devient bruyant quand vous grep'ez un dump d'attributs pour exe.

Le filtre de triage que j'utilise vraiment

Après avoir parsé la MFT avec MFTECmd ou mft_dump, j'exporte chaque enregistrement avec plus d'un attribut $DATA. Puis j'élimine :

  • Tout ce dont le nom de flux supplémentaire est Zone.Identifier et qui fait moins de 1 Ko.
  • Tout ce qui est dans \Windows\WinSxS\ (le magasin des manifestes, plein de flux légitimes).
  • Tout ce qui est sous un répertoire d'application signée par un éditeur dont le flux est une miniature ou clé de métadonnées connue.

Ce qui reste est l'ensemble de travail. Sur un poste propre, c'est généralement moins d'une centaine d'enregistrements. Sur un hôte où s'est passé quelque chose d'intéressant, les écarts apparaissent immédiatement.

Recoupez les survivants avec le journal USN pour voir quand chaque flux a été créé ou modifié pour la dernière fois. Un attribut $DATA nommé apparu à 02:14 et non touché depuis mérite un examen plus poussé. Associez avec Sysmon et les journaux d'événements de sécurité si vous les avez : Sysmon Event ID 15 (FileCreateStreamHash) est le seul ID d'événement qui capture la création d'ADS avec le hash du contenu du flux.

Une note sur Defender

Le Defender moderne scanne les ADS par défaut. Il est vraiment bon pour le schéma brute-force "déposer un PE connu mauvais dans un flux". Il est moins bon avec un petit PowerShell obfusqué caché dans des flux, et il ne touche pas toujours les flux sur les chemins exclus. Ne supposez pas que le silence de Defender soit la preuve d'une absence.

Lectures complémentaires

  • Microsoft, File Streams. La mécanique officielle, y compris l'API BackupRead/BackupWrite qui copie tous les flux.
  • istat et fls du Sleuth Kit pour l'énumération hors ligne qui révèle les ADS.
  • Documentation Mark of the Web de Microsoft sur ce que fait vraiment Zone.Identifier et comment Office l'utilise.

Ressources externes