Detectar timestomping y anti-forense en el USN journal

Los atacantes que editan timestamps de MFT no pueden esconderse del change journal. Cómo las discrepancias $STANDARD_INFORMATION vs $FILE_NAME y los registros BasicInfoChange inesperados delatan la actividad anti-forense.

Por 8 min de lectura

Los operadores que se preocupan por su oficio no solo borran evidencia. Camuflan lo que dejan atrás. El movimiento más común es el timestomping — reescribir los timestamps de un archivo NTFS para que el archivo parezca inocente, o para que envejezca fuera de la ventana de investigación. Solía funcionar de forma fiable. Con el USN journal activado, como lo está por defecto en cada host Windows moderno, deja una firma tan distintiva que un solo filtro y una resolución de ruta padre lo sacarán a la luz.

Este post recorre lo que el timestomping hace al disco, cómo lo expone el journal y qué otros movimientos anti-forenses puedes pillar con el mismo artefacto gratis.

Un repaso rápido a los timestamps NTFS

Cada entrada MFT lleva timestamps en dos atributos:

  • $STANDARD_INFORMATION (SI). Los timestamps que las herramientas de espacio de usuario y la mayoría de las APIs leen y escriben. dir, Explorer, Get-ChildItem, os.stat, GetFileTime — todos devuelven SI. Microsoft documenta el layout en la referencia de NTFS file times.
  • $FILE_NAME (FN). Los timestamps que NTFS establece internamente para cada atributo $FILE_NAME (un archivo puede tener múltiples nombres si tiene hard links). Los valores FN son mucho más difíciles de cambiar: solo se actualizan en operaciones específicas y el kernel no expone una API limpia para reescribirlos.

Las herramientas de timestomping apuntan a SI por defecto. El viejo timestomp.exe de Metasploit, SetMACE y docenas de implantes personalizados escritos por operadores con incluso un oficio modesto reescriben $STANDARD_INFORMATION vía NtSetInformationFile con una payload FileBasicInformation. Los implantes modernos (el comando timestomp de Cobalt Strike entre ellos) también pueden reescribir FN manipulando la MFT directamente, lo cual es más involucrado y produce evidencia adicional en $LogFile.

De una forma u otra, el acto de escribir la entrada MFT enciende el journal.

Lo que el journal registra para una edición de timestamp

Cuando se escriben timestamps SI, NTFS emite un registro BasicInfoChange | Close sobre la FileReferenceNumber del archivo. Ese registro es el diagnóstico:

  • Un toque legítimo produce BasicInfoChange | Close junto con un DataExtend o DataOverwrite de la escritura real que disparó la actualización del timestamp.
  • Un timestomp produce un BasicInfoChange | Close desnudo sin escritura previa en la misma FileReferenceNumber.

Cuando ves BasicInfoChange | Close sin DataOverwrite, DataExtend, FileCreate o rename en la misma sesión de handle, estás viendo manipulación de metadatos. La gran mayoría son timestomping; el resto son conmutaciones de atributos (+H, +R, compresión on/off) y cambios de estado EFS.

La comparación SI vs FN

La detección más autoritativa de timestomping compara los timestamps SI de cada archivo con sus timestamps FN. El patrón data de la investigación forense temprana de Mandiant sobre Windows y está cubierto en File System Forensic Analysis de Brian Carrier. Las formas que te deben hacer parar:

  • SI anterior a FN. Un archivo no puede haber sido modificado legítimamente antes de que existiera su nombre. Esta es la pistola humeante canónica.
  • SI en el futuro de FN por un margen poco realista. Operador empujando la edad aparente hacia adelante para parecer un archivo del sistema de una instalación limpia.
  • Tanto SI como FN parecen imposiblemente limpios — segundos redondos, valores M/A/C/B idénticos, todos coincidiendo con una fecha de instalación de Windows conocida. Vale la pena mirar más de cerca incluso cuando ningún par individual marca.

El journal complementa la comparación en vez de reemplazarla. La comparación MFT te dice que algo manipuló timestamps. El journal te dice exactamente cuándo ocurrió la reescritura de SI, que es el timestamp que pones en el informe. Empareja los dos y el caso se escribe solo:

  1. La comparación MFT marca SI < FN en \Windows\System32\drivers\suspicious.sys.
  2. El journal tiene un BasicInfoChange | Close en la FileReferenceNumber del archivo en 2026-04-12 03:08:14Z sin escrituras alrededor.
  3. Ese timestamp es cuando el operador corrió su comando timestomp. Correla con Sysmon evento 1 y tienes el proceso.

$LogFile y el journal deberían coincidir

El journal registra escrituras a nivel de archivo. $LogFile registra las transacciones MFT subyacentes a nivel de escritura de metadatos. Un timestomp produce:

  • Una transacción de escritura MFT en $LogFile, modificando el atributo $STANDARD_INFORMATION de la entrada objetivo.
  • Un BasicInfoChange | Close en el journal.

Si $LogFile muestra una transacción de actualización MFT en un archivo sin BasicInfoChange | Close correspondiente en el journal, el operador puede haber borrado el registro del journal limpiando $UsnJrnl y creando uno nuevo. Esa maniobra es posible (fsutil usn deletejournal /D /N C: seguido de fsutil usn createjournal /m ... /a ... C:), pero es ruidosa de por sí.

Otros movimientos anti-forenses que pilla el journal

Deshabilitar o limpiar el journal

fsutil usn deletejournal /D /N C: elimina el journal por completo. Después de ejecutarse:

  • El archivo del journal se reconstruye vacío. Los registros previos a la llamada se han ido para siempre.
  • La entrada MFT de $UsnJrnl se reescribe nueva, lo que $LogFile registra.
  • El log de Security registra un evento Sensitive Privilege Use para SeRestorePrivilege o SeManageVolumePrivilege, si las SACLs estaban configuradas (lo que normalmente no estaban).

El journal no te puede decir lo que solía contener, pero el acto de deshabilitarlo es en sí mismo una fuerte señal anti-forense. Microsoft documenta los comandos de gestión en la referencia de fsutil usn.

Los operadores que saben que el journal existe tienden a hacer una de dos cosas: limpiarlo al irse (ruidoso) o evitar selectivamente dejar evidencia en él (más difícil, requiere mantenerse fuera del disco). En un host donde el journal está sospechosamente vacío alrededor de una ventana de incidente conocida, trata eso como una hipótesis que vale la pena testear.

Flujos de datos alternativos

Esconder cosas en ADS es más viejo que yo, y el journal lo registra limpiamente. El bit Reason StreamChange se dispara cuando un flujo de datos alternativo se añade, renombra o elimina en un archivo. Filtra por StreamChange y cada evento de creación/modificación de ADS en el volumen aparece.

Falsos positivos esperados: flujos Zone.Identifier legítimos de descargas del navegador (emparejados con el FileCreate del archivo host), flujos Mark-of-the-Web de clientes de correo, y estado de SmartScreen. Cualquier otra cosa que produzca registros StreamChange sobre binarios del sistema firmados, sobre archivos en \Windows\System32\, o sobre binarios de perfil de usuario fuera del flujo normal de descarga de navegador, merece una mirada.

HardLinkChange se dispara cuando se añaden o eliminan hard links. Los operadores a veces usan hard links para hacer accesible un binario malicioso vía dos padres, lo que puede derrotar reglas de AppLocker y controles EDR basados en ruta. Pivota sobre FileReferenceNumber para ver todos los padres para un inode dado.

Abuso de reparse-point

ReparsePointChange se enciende cuando se añade, modifica o elimina un reparse point — junction, symbolic link, mount point. Busca reparse points siendo creados en \$Recycle.Bin\, \Users\Default\, \ProgramData\ u otros lugares donde normalmente no existirían. El parser de papelera de reciclaje es el artefacto complementario para el lado de $Recycle.Bin.

Cambios de seguridad y Object ID

SecurityChange expone reescrituras de ACL y owner. ObjectIdChange expone las manipulaciones más raras de Object ID. Ambos son silenciosos en un host sano. Las ráfagas de cualquiera de los dos sobre binarios de perfil de usuario o sobre archivos del sistema vale la pena investigarlas.

Un procedimiento de scan práctico

El cribado más rápido para timestomping usando un journal parseado:

  1. Filtra a registros cuya máscara Reason sea exactamente BasicInfoChange | Close. La mayoría de parsers usan por defecto "contiene el bit"; tú quieres coincidencia exacta para este scan.
  2. Para cada candidato, mira los cinco minutos previos de registros sobre la misma FileReferenceNumber. Si no hay DataOverwrite, DataExtend, FileCreate o rename, marca el registro.
  3. Para los registros marcados, calcula el delta SI vs FN en la MFT. Ordena por delta absoluto.

La cima de la lista es tu timestomping. Las entradas marcadas restantes suelen ser invocaciones attrib +H o attrib +R, o scripts conmutando read-only — dependientes del contexto, raramente interesantes para una investigación IR típica, pero vale la pena mantenerlas en la salida rankeada por completitud.

El parser de esta página expone filtrado por máscara exacta. Para el paso 3, necesitas un $MFT parseado abierto al lado — la mayoría de analistas usan MFTECmd de Eric Zimmerman para el export CSV y pivotan en una hoja de cálculo.

Lo que no puedes pillar por esta vía

Una lista corta de movimientos anti-forenses que esquivan el journal por completo:

  • Arrancar desde medios externos y reescribir el disco. Nunca tocó el SO vivo, nunca escribió al journal.
  • Reescrituras de archivo en userland que preservan el tamaño del contenido en el mismo offset sin actualización SI. Produce registros DataOverwrite pero pierde el contenido original. El journal ve la escritura, no lo que había antes.
  • Deshabilitar el journal antes de hacer cualquier otra cosa. El journal solo puede registrar lo que sucedió mientras estaba corriendo.

Para esos, necesitas $LogFile, Volume Shadow Copies, telemetría off-host, o un dump de RAM adquirido lo bastante cerca del incidente para aún contener el estado relevante.

Lecturas adicionales

  • Microsoft Learn — File Times y la referencia de la API NtSetInformationFile. Esta última es la syscall a la que toda herramienta de timestomping acaba llamando.
  • MFTECmd de Eric Zimmerman — el parser offline canónico para timestamps SI y FN en un CSV plano.
  • Documentación de libfsntfs de Joachim Metz — la referencia abierta más exhaustiva sobre los internos de $LogFile, que es el segundo testigo cuando el journal solo no basta.
  • Brian Carrier, File System Forensic Analysis — el capítulo sobre atributos de metadatos NTFS sigue siendo la referencia canónica sobre cómo se comportan SI y FN bajo distintas operaciones.