QuarantineEventsV2 y xattr de cuarentena en macOS
QuarantineEventsV2 y el atributo com.apple.quarantine registran qué se descargó, desde qué URL, con qué app y cuándo, a menudo aunque el archivo ya no exista.
- Ubicación
- ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2
- Prueba
- Qué archivos descargó un usuario, desde qué URL y página de origen, con qué app y cuándo
- Marcas de tiempo
- Base de datos: Mac absolute time (UTC); xattr: segundos Unix en hexadecimal (UTC)
- Acceso
- Usuario propietario o root; se recomienda Full Disk Access para la herramienta de adquisición
- Retención
- Hasta que se borra o se limpia (no hay depuración automática documentada)
- Adquisición
- Aftermath, mac_apt, UAC, Velociraptor
Herramientas
Comparar todas las herramientas- Quarantine ParserNavegador
- mac_aptCLI · código abierto
- PlasoCLI · código abierto
- VelociraptorPlataforma · código abierto
- sqlite3CLI · incluido en macOS
Qué es
Dos artefactos vinculados registran las descargas en macOS. Cuando una app que participa en la cuarentena de archivos (navegadores, Mail, Mensajes, AirDrop, apps en sandbox) escribe un archivo, macOS le añade el atributo extendido com.apple.quarantine. Launch Services escribe además una fila en una base de datos SQLite por usuario, QuarantineEventsV2, con la URL de descarga, la página de origen y el agente que descargó.
El xattr viaja con el archivo; la fila de la base de datos permanece cuando el archivo se borra. Juntos son la forma habitual de responder a "¿de dónde salió este archivo?".
Dónde se encuentra
| Artefacto | Ruta | Notas |
|---|---|---|
| Base de datos de cuarentena | ~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2 | Una por usuario, SQLite, tabla única LSQuarantineEvent |
| xattr de cuarentena | com.apple.quarantine en el propio archivo | Se guarda en archivos AppleDouble ._ en volúmenes sin xattrs nativos |
| Último rechazo de Gatekeeper | /private/var/db/SystemPolicyConfiguration/.LastGKReject en macOS actual; /private/var/db/.LastGKReject en versiones anteriores | Escrito por syspolicyd; mac_apt QUARANTINE solo busca la ruta antigua en una imagen, así que pásale el archivo actual directamente |
La base de datos ha mantenido este nombre y ubicación en las versiones modernas de macOS. Su propietario puede leerla; recopílala como root para todos los usuarios, con Full Disk Access concedido a la herramienta de adquisición.
Qué prueba
- Que un agente concreto (
com.apple.Safari,com.google.Chrome,com.apple.mail) descargó una URL en un momento dado. - La página que llevó a la descarga (
LSQuarantineOriginURLString) y, en el caso del correo, el remitente. - Que un archivo concreto del disco procede de una descarga concreta (el UUID del xattr coincide con
LSQuarantineEventIdentifier). - Si un archivo en cuarentena se abrió y se aprobó a través de Gatekeeper (flag de aprobación del usuario en el xattr).
No registra la ruta local de guardado ni el nombre del archivo, y no cubre las descargas hechas con curl, wget, scp, git u otras herramientas que no participan. La ausencia de un registro es una prueba débil.
Campos clave
Tabla LSQuarantineEvent:
| Columna | Significado |
|---|---|
LSQuarantineEventIdentifier | UUID (clave primaria), coincide con el último campo del xattr |
LSQuarantineTimeStamp | Hora del evento, Mac absolute time (REAL) |
LSQuarantineAgentBundleIdentifier | Bundle ID de la app que descargó |
LSQuarantineAgentName | Nombre visible del agente |
LSQuarantineDataURLString | URL de los datos descargados |
LSQuarantineOriginURLString | Página de referencia u origen |
LSQuarantineOriginTitle | Título del origen, cuando se registra |
LSQuarantineSenderName, LSQuarantineSenderAddress | Remitente, rellenado por agentes como Mail |
LSQuarantineTypeNumber | Tipo de cuarentena de Launch Services (descarga web, adjunto de correo, etc.) |
LSQuarantineOriginAlias | Blob de alias, normalmente vacío |
Valor del xattr flags;timestamp;agent;UUID, por ejemplo 0083;66f7c2a1;Safari;<UUID>. Los bits de flag documentados por investigadores (Apple no los documenta públicamente) incluyen 0x0001 descarga, 0x0002 sandbox, 0x0004 cuarentena estricta y 0x0040 aprobado por el usuario.
Marcas de tiempo
LSQuarantineTimeStamp: Mac absolute time, segundos desde 2001-01-01 00:00:00 UTC. Suma978307200para obtener tiempo Unix.- Marca de tiempo del xattr: segundos Unix en hexadecimal, UTC.
SELECT datetime(LSQuarantineTimeStamp + 978307200, 'unixepoch') AS event_utc,
LSQuarantineAgentBundleIdentifier, LSQuarantineDataURLString,
LSQuarantineOriginURLString, LSQuarantineEventIdentifier
FROM LSQuarantineEvent ORDER BY LSQuarantineTimeStamp;
xattr -p com.apple.quarantine ./sample.dmg
date -u -r $((16#66f7c2a1))
Retención
No hay depuración automática documentada: los registros suelen acumularse durante toda la vida del perfil de usuario, lo que los hace valiosos cuando el archivo descargado ya se ha eliminado. Usuarios, herramientas de limpieza y atacantes pueden borrar filas con sqlite3 o eliminar el archivo completo. El xattr se pierde cuando se elimina con xattr -d/xattr -c, cuando el archivo se copia a un sistema de archivos o servicio que descarta los atributos extendidos, o cuando un comprimido se extrae con una herramienta que no propaga la cuarentena.
Adquisición
# Every user's database (root, collector with Full Disk Access)
for u in /Users/*; do
f="$u/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2"
[ -f "$f" ] || continue
d="./case/qe_$(basename "$u")"
mkdir -p "$d" && sudo cp -p "$f"* "$d/"
done
# Preserve xattrs when copying suspect files
ditto --extattr ./suspect.pkg ./case/files/
- Aftermath recopila la base de datos LSQuarantine.
- UAC:
files/system/quarantine_events.yaml(base de datos por usuario). - Velociraptor:
MacOS.System.QuarantineEvents. - Análisis en frío: copia desde el volumen Data montado; calcula el hash primero y trabaja sobre copias.
Análisis
- sqlite3 con la consulta anterior.
- Plugin
QUARANTINEde mac_apt (base de datos y.LastGKReject):python mac_apt.py -o out MOUNTED /Volumes/evidence QUARANTINE. - Plugin
ls_quarantinede Plaso:log2timeline.py --parsers 'sqlite/ls_quarantine' --storage-file qe.plaso ./case. - Vincular un archivo con su registro:
SELECT * FROM LSQuarantineEvent
WHERE LSQuarantineEventIdentifier = '<UUID from xattr>';
Quarantine Parser lee en el navegador QuarantineEventsV2 con su -wal (y recupera filas borradas), los listados del xattr com.apple.quarantine y .LastGKReject, y vincula cada archivo en disco con su registro de descarga; no se sube nada.
Consejos para la investigación
- Un binario sospechoso sin xattr de cuarentena pero con un registro coincidente en la base de datos sugiere que el atributo se eliminó deliberadamente.
- Una segunda fase descargada con
curlno deja rastro de cuarentena; continúa por el historial de shell, los unified logs y FSEvents. - Correlaciona las URL de datos con el historial de Safari o de Chrome/Firefox y con
kMDItemWhereFromsen el almacén de Spotlight. - El cambio de flag de
0083a00c3activa0x0040(aprobado por el usuario): el elemento se abrió y se permitió. Trata el significado de los flags como prueba complementaria. - Huecos en una línea de tiempo por lo demás densa, o una base de datos mucho más pequeña de lo que sugiere el historial del navegador, pueden indicar una limpieza manual; revisa el WAL y las páginas libres.
- Confundir las épocas del xattr (Unix, hexadecimal) y de la base de datos (Mac absolute) produce errores de 31 años.
- Para las decisiones de Gatekeeper posteriores a la descarga, consulta Gatekeeper y XProtect y la guía de cuarentena y Gatekeeper.
Ver también
Artefactos relacionados
Guías detalladas
Glosario
- Quarantine Attribute (com.apple.quarantine)Inglés
- GatekeeperInglés
- Mac Absolute TimeInglés