Skip to content

Recuperar persistencia WMI eliminada de OBJECTS.DATA

Por qué los filtros, consumidores y enlaces WMI eliminados sobreviven en OBJECTS.DATA, índice frente a carving, y python-cim frente a PyWMIPersistenceFinder.

Publicado el 5 min de lectura

En resumen. Eliminar una suscripción WMI no la borra. Sus bytes permanecen en OBJECTS.DATA hasta que WMI reutiliza el espacio. Recorrer el índice (el enfoque de python-cim) le da lo que está activo; barrer el archivo completo (como hace con texto PyWMIPersistenceFinder, de David Pany) encuentra además lo que se eliminó. Use ambos y lleve la cuenta de qué método encontró cada cosa.

Por qué sobreviven los objetos eliminados

El repositorio es un almacén de páginas. Cuando una instancia se elimina o se reescribe, WMI actualiza INDEX.BTR y escribe una nueva generación del archivo MAPPING. El registro antiguo no se pone a cero:

  • si se libera su página completa, la página pasa a estar no asignada: ya nadie la referencia, pero sus bytes siguen intactos;
  • si quedan otros registros en la página, el espacio del registro pasa a ser slack dentro de una página que sigue en uso.

En ambos casos el registro conserva su cabecera —el SHA-256 en UTF-16 del nombre de su clase— y su heap de cadenas: la consulta, la línea de comandos, el script, las referencias del enlace. Mientras no se escriba otra cosa encima, es recuperable. Cuánto dura eso depende de la actividad de WMI en el host: recopile pronto.

Dos formas de leer un repositorio

Estructurada: seguir el índice

Así funciona python-cim, y así lo hace Windows. Las claves de INDEX.BTR como NS_…/CI_<hash("__EVENTFILTER")>/IL_….page.record.length apuntan a un registro a través del archivo MAPPING actual. Las definiciones de clase dan a cada propiedad su nombre, su tipo y su posición, de modo que cada valor se decodifica con exactitud, incluidos los valores por defecto de la clase y el espacio de nombres de cada objeto.

Solo ve lo que el índice referencia: los objetos activos.

Carving: barrer cada byte

Dos variantes:

  • Carving de registros. Buscar en OBJECTS.DATA los hashes de nombre de clase de __EventFilter, __FilterToConsumerBinding y las clases de consumidor. Cada coincidencia es el inicio de un registro de instancia, activo o no. Se decodifica con la estructura de la clase y se comprueba su coherencia: el heap del registro debe terminar exactamente donde indica su cabecera y debe empezar por el nombre de la clase.
  • Carving de texto. La idea de PyWMIPersistenceFinder: buscar __FilterToConsumerBinding seguido de …EventConsumer.Name="…" y __EventFilter.Name="…", y después la consulta del filtro y el comando del consumidor junto a sus nombres. No necesita ninguna estructura, así que sigue funcionando cuando la cabecera de un registro se ha sobrescrito, a costa de adivinar qué cadena es cuál.

El carving lo ve todo, pero por sí solo no puede decir si una coincidencia está activa. Ese veredicto lo da el archivo MAPPING: una coincidencia en una página asignada, dentro de una entrada de la tabla de contenidos, está en uso; una coincidencia en una página no asignada o en el slack está liberada.

Cómo los combina WMI Parser

WMI Parser recorre el índice cuando están presentes INDEX.BTR y un archivo MAPPING, después hace siempre carving de todo el archivo y fusiona los resultados. Cada objeto muestra cómo se encontró:

EtiquetaSignificado
ÍndiceAlcanzado a través de INDEX.BTR y el mapa actual: activo
Registro extraídoCabecera de registro hallada por barrido; decodificado con la estructura de la clase
Coincidencia de textoSolo sobrevivió el texto del enlace (al estilo de PyWMIPersistenceFinder)

Una copia recuperada idéntica a un objeto activo se fusiona con él como una ubicación adicional. Una copia recuperada que difiere se lista por separado como Recuperado y, si un objeto activo tiene la misma clave, se marca como versión anterior. El repositorio de ejemplo muestra los tres casos: un filtro de inicio de sesión eliminado y su enlace, hallados por carving de registros y de nuevo como fragmento sin cabecera en el slack de una página; y una versión anterior de un consumidor que ejecutaba un comando PowerShell codificado antes de cambiarse a C:\ProgramData\Intel\m64.exe -svc.

Leer con cuidado los objetos recuperados

  • Sin espacio de nombres. Los registros no almacenan su espacio de nombres; solo el índice lo conoce. Un enlace recuperado puede haber residido en root\subscription o en otro lugar.
  • Registros divididos. Un registro más largo que su página continúa en la siguiente página lógica, que puede estar físicamente en cualquier sitio. Una vez liberadas, las piezas son difíciles de reensamblar; WMI Parser indica entonces una lectura parcial.
  • Estructuras. Sin las definiciones de clase del repositorio (si solo se aporta OBJECTS.DATA), la decodificación se basa en la estructura integrada de las clases estándar de Windows y en las autocomprobaciones anteriores. Las clases de consumidor personalizadas solo se encuentran entonces a través del texto de su enlace.
  • Tiempo. Las cabeceras de instancia llevan dos FILETIME no documentados. A menudo siguen el momento de escritura de esa copia, lo que puede ayudar a ordenar versiones, pero no son fechas de creación documentadas.

Un enlace recuperado demuestra que la suscripción existió en algún momento, no que se ejecutara. Busque evidencias de ejecución de la carga útil del consumidor (Prefetch, Amcache, registros de eventos) y los eventos WMI-Activity de la checklist de investigación.

FAQ

¿Se puede recuperar una suscripción WMI eliminada?

A menudo, sí. Eliminar un objeto libera su página o su espacio de registro en OBJECTS.DATA sin borrarlo, así que el filtro, el consumidor o el enlace pueden recuperarse mediante carving hasta que WMI reutilice ese espacio.

¿Qué diferencia hay entre python-cim y PyWMIPersistenceFinder?

python-cim recorre INDEX.BTR y el archivo MAPPING para decodificar los objetos activos con sus estructuras de clase. PyWMIPersistenceFinder busca en OBJECTS.DATA el texto de los enlaces, lo que solo requiere ese archivo y puede alcanzar registros eliminados, pero decodifica menos.

¿Cómo sé si un objeto recuperado se eliminó o solo es una versión anterior?

Si existe un objeto activo con la misma clave y su contenido difiere, la copia recuperada es muy probablemente una versión anterior. Si ningún objeto activo tiene esa clave, se eliminó.

Artículos relacionados

Artículos relacionados

Leer CCM_RecentlyUsedApps del repositorio WMI: qué programas ejecutó cada usuario, cuándo y cuántas veces, incluidas copias antiguas de OBJECTS.DATA.
Checklist paso a paso para la persistencia WMI: consultas en vivo, el repositorio, eventos 5860 y 5861, Sysmon 19-21, evidencias de ejecución y limpieza segura.
Las dos suscripciones WMI que incluye Windows, SCM Event Log y BVTFilter/BVTConsumer: qué contienen, por qué son inofensivas y cómo se abusa de sus nombres.