Aller au contenu

Index de répertoires ($I30)

Qu'est-ce que $I30 ?

Chaque répertoire NTFS conserve un index des fichiers qu'il contient, nommé $I30. Un petit répertoire le conserve dans son enregistrement $MFT ($INDEX_ROOT) ; un répertoire plus grand possède également des enregistrements INDX, généralement de 4 096 octets chacun, dans un flux $INDEX_ALLOCATION:$I30. Chaque entrée d'index contient une copie du $FILE_NAME du fichier : son nom, sa référence MFT, son répertoire parent, quatre horodatages et deux tailles, tels qu'ils étaient lors de la dernière mise à jour de l'entrée par NTFS.

Lorsqu'un fichier est supprimé d'un répertoire ou renommé hors de celui-ci, NTFS retire son entrée et déplace les entrées qui la suivent. Les anciens octets restent dans le slack de l'enregistrement INDX, au-delà des entrées utilisées, jusqu'à ce que des entrées ultérieures les écrasent. L'index slack peut conserver le nom, les horodatages et la taille d'un fichier dont l'enregistrement $MFT a été réutilisé et dont les enregistrements du Journal USN ont été recyclés.

Meilleure conclusion : un nom trouvé dans l'index slack figurait, à un moment donné, dans l'index de ce répertoire avec les horodatages et tailles $FILE_NAME indiqués. Une entrée de slack n'indique pas quand elle a été retirée, ni si elle a été supprimée, renommée ou déplacée par un rééquilibrage.

Emplacement et collecte

C:\<directory>:$I30:$INDEX_ALLOCATION

$I30 est une métadonnée NTFS : collectez-le avec un outil forensique capable d'accès brut qui peut exporter le flux $I30 d'un répertoire (les fichiers exportés sont souvent nommés $I30). Juntei peut également rechercher des enregistrements INDX dans une image disque ou dans l'espace non alloué. Collectez aussi le $MFT et le $J du même volume, afin de déterminer à quoi correspondaient les entrées de slack.

Précautions d'analyse

  • L'index slack est partiel et non ordonné. Les entrées sont écrasées au fil des modifications du répertoire ; un nom absent ne prouve rien.
  • De nombreuses entrées de slack sont des copies d'entrées encore utilisées, laissées lors du déplacement des entrées. CopyOfEntryInUse les signale. Le même nom supprimé peut également figurer plusieurs fois dans le slack.
  • Les horodatages d'une entrée d'index sont des horodatages $FILE_NAME tels qu'ils étaient lors de la dernière mise à jour de l'entrée. Ils peuvent différer à la fois des horodatages $STANDARD_INFORMATION et $FILE_NAME de l'enregistrement $MFT du fichier.
  • AllocatedSize et RealSize correspondent également à la dernière mise à jour de l'entrée et peuvent être obsolètes.
  • Le FileEntry (ou ParentEntry) d'une entrée de slack peut être absent lorsque des octets ultérieurs l'ont écrasé. Lorsqu'il est présent, l'enregistrement MFT qu'il désigne a pu être réutilisé depuis : comparez le numéro de séquence.
  • parse-ntfs i30 lit les enregistrements INDX. L'index d'un petit répertoire se trouve uniquement dans son enregistrement $MFT ($INDEX_ROOT) ; ses fichiers figurent dans le $MFT.

Analyser avec Juntei

Usage: juntei parse-ntfs i30 <INPUT> [OPTIONS]

Input:
  -d, --directory <DIR>  Recursively find $I30 files (with $I30 in their name, or starting with an INDX record)
  -f, --file <FILE>      Parse one $I30 stream, or any file holding INDX records (a disk image, unallocated space)

Filtering:
      --slack-only  Only the entries found in slack
      --no-copies   Leave out the slack entries that copy an entry in use

Output:
  -o, --output <FILE>       Save every entry
  -t, --output-type <TYPE>  csv, json, or jsonl
juntei parse-ntfs i30 -f 'Users_$I30'
juntei parse-ntfs i30 -d evidence/ -o i30.csv
juntei parse-ntfs i30 -f 'Users_$I30' --slack-only --no-copies -t jsonl
juntei parse-ntfs i30 -f disk.raw -o carved-i30.csv

Le résumé répertorie les enregistrements INDX (et combien ont été partiellement écrits), les entrées utilisées et celles présentes dans le slack, ainsi que les noms des entrées de slack qui ne sont pas des copies exactes d'entrées utilisées. Ces noms sont des candidats de fichiers supprimés ou renommés, et non un verdict en soi.

Champs de sortie CSV

Champ Interprétation
SourcePath Fichier d'entrée ; distingue les hôtes et les répertoires.
RecordOffset, EntryOffset Décalages en octets de l'enregistrement INDX et de l'entrée dans l'entrée analysée. Essentiels pour la validation et pour les enregistrements trouvés dans des images disque.
RecordVCN, RecordLSN La position de l'enregistrement dans le flux d'index et son numéro de séquence $LogFile.
FromSlack True pour une entrée trouvée au-delà des entrées utilisées.
CopyOfEntryInUse Entrée de slack ayant le même nom, le même espace de noms, le même fichier (lorsqu'il est connu), le même parent et les mêmes horodatages qu'une entrée utilisée du même index de répertoire. Généralement un reste du déplacement d'entrées, et non un fichier supprimé.
Filename Le nom dans le répertoire.
Namespace win32, dos (nom court 8.3), win32_and_dos ou posix.
FileEntry, FileSequence La référence MFT du fichier. Vide pour une entrée de slack dont l'en-tête a été écrasé.
ParentEntry, ParentSequence La référence MFT du répertoire. Vide lorsque d'autres octets l'ont écrasée.
CreatedUTC, ModifiedUTC, MFT-ModifiedUTC, AccessedUTC Horodatages $FILE_NAME, à 100 ns près, tels qu'ils étaient lors de la dernière mise à jour de l'entrée.
AllocatedSize, RealSize Tailles copiées par NTFS dans l'entrée ; voir les mises en garde ci-dessus.
FileAttributes Noms d'attributs joints par | (hidden|archive) ; is_directory pour un sous-répertoire. Les bits que cette version de Juntei ne nomme pas sont conservés en hexadécimal (0x00800000).
ReparseValue Balise d'analyse (reparse tag) ou taille des attributs étendus provenant de $FILE_NAME.
Problems Dommages dans l'enregistrement, tels que des secteurs partiellement écrits. Les entrées d'un enregistrement endommagé méritent tout de même d'être examinées, avec prudence.

Les formats JSON/JSONL contiennent les mêmes champs en snake_case, avec problems sous forme de liste et null pour les valeurs inconnues.

Comment les entrées de slack sont trouvées

Le slack est parcouru à chaque limite de 8 octets, là où commencent les entrées, à la recherche d'entrées complètes, d'attributs $FILE_NAME dont l'en-tête d'entrée a été écrasé et, au début du slack, d'un $FILE_NAME dont la référence parente a été écrasée par la fin des entrées utilisées. Un candidat doit ressembler à ce qu'écrit Windows : un nom UTF-16 valide sans caractères de contrôle ni séparateurs de chemin, quatre horodatages compris entre 1980 et 2100, un espace de noms connu et des indicateurs d'attributs connus. Une référence parente dépassant 32 bits correspond à des octets qui l'ont écrasée et est laissée vide.

Le tableau de séquence de mise à jour (update sequence array) de chaque enregistrement est appliqué. Un secteur qui ne se termine pas par la valeur de séquence de mise à jour a été partiellement écrit ; Juntei lit l'enregistrement tel quel et nomme les secteurs dans Problems.

Stratégie d'investigation

  1. Commencez par les noms du slack qui ne sont pas des copies, indiqués dans le résumé, puis filtrez avec --slack-only --no-copies.
  2. Recherchez le FileEntry dans le $MFT. Un même FileSequence signifie le même fichier ; un numéro plus élevé signifie que l'enregistrement a été libéré depuis, et peut-être réutilisé.
  3. Recherchez le nom dans le Journal USN pour savoir quand il a été supprimé ou renommé.
  4. Comparez les horodatages $FILE_NAME avec les horodatages $STANDARD_INFORMATION du $MFT pour détecter le timestomping.
  5. Corrélez avec Prefetch, LNK, les Jump Lists et les journaux d'événements pour déterminer comment le fichier a été utilisé.

Plus de détails