Recuperar evidencia de archivos eliminados con el USN journal

Cuando un archivo ha sido eliminado, sacado de la papelera y la entrada MFT reciclada — el USN journal a menudo aún tiene su nombre, padre y línea temporal. Una guía para extraer esa evidencia.

Por 8 min de lectura

La pregunta más común que los analistas forenses reciben de stakeholders no técnicos es una variante de "¿puedes probar que este archivo existió?". Cuando el archivo ha sido eliminado del disco, la papelera vaciada, y ha pasado suficiente tiempo para que la entrada $MFT haya sido reutilizada para otra cosa, la respuesta casi siempre depende de lo que el USN journal aún recuerde. El journal es, en mi experiencia, el testigo más duradero para "¿alguna vez existió este archivo?" una vez todo lo demás ha sido borrado.

Este post recorre lo que el journal preserva sobre archivos eliminados, cómo extraer esa evidencia, y los casos en los que el journal es tu última línea.

Lo que el journal guarda tras la eliminación

Cuando un archivo se elimina en NTFS, suceden tres cosas:

  1. La entrada $FILE_NAME en el directorio padre se desvincula. La INDEX_ALLOCATION del directorio se reescribe sin ella.
  2. La entrada MFT se marca como no usada pero no se pone a cero. El siguiente archivo asignado a esa entrada sobrescribe los data runs, atributos y timestamps.
  3. El USN journal recibe un registro FileDelete | Close que nombra el archivo, su referencia padre, su número y secuencia de entrada MFT, y el timestamp de eliminación.

El registro del journal es el más resiliente de los tres. La entrada de directorio desaparece en el momento en que el padre se reescribe — a veces en segundos en un volumen activo. La entrada MFT puede reutilizarse en cuanto se cree un archivo nuevo — a veces en minutos. El registro del journal vive en un ring buffer que solo da la vuelta tras días o semanas.

Para archivos eliminados hace días, el journal típicamente te da:

  • El nombre de archivo como hoja UTF-16 LE. Solo la hoja, sin ruta.
  • El número de referencia MFT del directorio padre. Combinado con una $MFT parseada se resuelve a una ruta.
  • El timestamp de eliminación en FILETIME UTC.
  • El número y secuencia de entrada MFT que ocupaba el archivo. Útil para cruzar artefactos extraídos e imágenes anteriores de $LogFile.
  • Una traza de ciclo de vida. Los registros FileCreate, DataExtend, BasicInfoChange y rename en la misma FileReferenceNumber te dicen cuándo se creó el archivo, cómo se escribió y si sus timestamps fueron modificados antes de la eliminación.

Una tupla de cuatro campos — referencia MFT, nombre de archivo, referencia padre, FILETIME de eliminación — más un evento de creación de antes en el mismo journal suele bastar para satisfacer un legal hold o anclar una investigación más profunda. La mayoría de las veces también obtienes el registro FileCreate del mismo $J, lo que te da la edad del archivo y un timestamp de creación independiente de $STANDARD_INFORMATION.

Un flujo de recuperación mínimo

Con un journal parseado y una $MFT parseada (mira la guía de extracción para ambos):

  1. Filtra por FileDelete en la ventana de tiempo de interés. Ordena por timestamp. Esta es tu lista maestra de eliminaciones a triagear.
  2. Agrupa por FileReferenceNumber para cualquier eliminación que importe. Obtienes la historia completa del archivo: creación, escrituras, pares de rename, cambios de atributo y finalmente la eliminación.
  3. Resuelve la ruta padre vía $MFT. El parser de esta página lo hace automáticamente cuando se suministran ambos archivos. Sin $MFT te paras en el nombre hoja.
  4. Cruza $LogFile si la eliminación es muy reciente. Puede aún contener la imagen "anterior" de la entrada de directorio, dando un segundo testigo independiente de la existencia del archivo.

La combinación "referencia MFT, nombre de archivo, ruta padre, timestamp de creación, timestamp de eliminación, traza de ciclo de vida completa" suele bastar para escribir un informe defendible.

Cuando la ruta padre no se puede resolver

A veces la entrada MFT padre ha sido a su vez reciclada para cuando miras — común en hosts ocupados de filesystem, en particular file servers y runners de CI. El journal aún te da el nombre del archivo y el número de referencia padre, pero $MFT ya no sabe a qué carpeta apuntaba esa referencia.

Tres fallbacks suelen destrabar la ruta:

Registros RenameNewName anteriores sobre la misma referencia padre. Agrupa todos los registros del journal por referencia padre. Cualquier RenameNewName anterior cuyo padre nuevo coincida con tu referencia no resuelta, y cuya propia ruta se resuelva, te dice qué carpeta solía ser esa referencia.

Entradas de índice de $LogFile. El log de recuperación de crash contiene imágenes anteriores de actualizaciones de INDEX_ALLOCATION. libfsntfs de Joachim Metz y el LogFileParser de Jonas Schicht las extraen. En una eliminación lo bastante reciente, la imagen anterior de la entrada de directorio sigue en $LogFile y se resuelve a una ruta.

Archivos hermanos en la misma referencia padre. Agrupa todos los registros del journal por referencia padre. Si uno de los hermanos fue renombrado dentro de un directorio cuya entrada MFT sigue válida, pivota por él: el padre antiguo en el momento del rename es tu carpeta desconocida.

Cuando ninguno funciona, el parser sacará a la luz el archivo como "nombre: notes.docx, padre: 1234-5" sin ruta resuelta. Eso es intencional. Inventar una ruta que no puedes verificar es peor que admitir que falta una.

"Borrado" no significa desaparecido

Las herramientas de trituración de archivos — borrado seguro de CCleaner, Eraser, BleachBit, sdelete — sobrescriben el contenido del archivo y luego lo eliminan. Dejan una traza de journal más ruidosa, no más silenciosa:

  • Múltiples registros DataOverwrite | Close sobre el archivo antes de su FileDelete | Close indican sobrescritura intencional de contenido. La eliminación normal no produce sobrescritura.
  • Un FileCreate más DataOverwrite más FileDelete sobre el mismo archivo en segundos es la firma canónica de destrucción de evidencia.
  • Donde el triturador también borró espacio libre escribiendo y luego eliminando archivos de relleno, esos archivos de relleno tienen sus propias secuencias create/extend/overwrite/delete — un enjambre de registros alrededor del momento de la destrucción.

El mapeo MITRE ATT&CK es T1485 Data Destruction para la sobrescritura de contenido y T1070.004 File Deletion para la eliminación en sí. En un host donde sospechas destrucción deliberada de evidencia, el journal a menudo te da un timestamp más estrecho que cualquier otro artefacto.

Y el contenido del archivo

El USN journal nunca lleva contenido. Solo metadatos sobre operaciones. Si necesitas los bytes de vuelta, el journal te apunta a los lugares donde mirar:

  • El número de entrada MFT del archivo eliminado. Si la entrada no ha sido reutilizada, $MFT aún tiene los data runs y el contenido puede ser recuperable vía icat de The Sleuth Kit o X-Ways.
  • Las imágenes anteriores de $LogFile para eliminaciones muy recientes.
  • Volume Shadow Copies (VSS) si existen en el host. El archivo eliminado puede vivir en un snapshot anterior. vssadmin list shadows en un host vivo o vshadowmount de libyal en una imagen los sacarán a la luz.
  • Almacenes específicos de aplicación. La papelera online de OneDrive, la carpeta "Autosaved" de Office bajo \Users\<u>\AppData\Roaming\Microsoft\Office\UnsavedFiles\, cachés de navegador (el tooling de forense de navegador cubre esto), copias staged de Outlook OST/PST.
  • El pagefile y un dump de RAM si el archivo se abrió lo bastante recientemente.

El papel del journal es decirte que un archivo existió y cuándo fue eliminado. La recuperación de contenido es aguas abajo.

Límites prácticos

Ventana del ring buffer. Los archivos eliminados antes de que el journal pasara por encima del registro más viejo que puedes ver están perdidos para este artefacto. Saca $LogFile y shadow copies como complementos.

Operaciones que no llegan al journal. Cambios de cifrado a nivel filesystem que solo actualizan atributos, escrituras de regiones sparse que solo tocan el mapa de asignación, y algunas manipulaciones de reparse-point NTFS pueden no producir registros DataExtend o DataOverwrite. El journal ve lo que NTFS elige loguear.

FileDelete sin FileCreate precedente. Significa que el archivo fue creado antes del registro más antiguo actual del journal. Su ciclo de vida en $J es parcial, pero el timestamp de eliminación y la referencia padre aún anclan un informe.

Recursos compartidos bind-mount o volume-mount. Si los datos viven en un filesystem remoto, el journal en tu host solo conoce los handles locales. Saca el journal del filesystem alojador real.

Lecturas adicionales

  • Microsoft Learn — Change Journals cubre la superficie de API y el ciclo de vida que produce registros FileDelete.
  • Man pages de The Sleuth Kit — icat y fls para recuperación de contenido contra entradas MFT aún asignadas.
  • SANS DFIR — el Windows Forensic Analysis poster pone el journal en contexto con $LogFile, Volume Shadow Copies y otros artefactos de recuperación de eliminación en una sola página.
  • libfsntfs de Joachim Metz — la referencia abierta para extracción de imágenes anteriores de $LogFile cuando la eliminación es fresca y la entrada de directorio aún no ha sido sobrescrita en otro sitio.