Saltar al contenido

Acceso a archivosRedEjecución

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

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

ArtefactoRutaNotas
Base de datos de cuarentena~/Library/Preferences/com.apple.LaunchServices.QuarantineEventsV2Una por usuario, SQLite, tabla única LSQuarantineEvent
xattr de cuarentenacom.apple.quarantine en el propio archivoSe 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 anterioresEscrito 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:

ColumnaSignificado
LSQuarantineEventIdentifierUUID (clave primaria), coincide con el último campo del xattr
LSQuarantineTimeStampHora del evento, Mac absolute time (REAL)
LSQuarantineAgentBundleIdentifierBundle ID de la app que descargó
LSQuarantineAgentNameNombre visible del agente
LSQuarantineDataURLStringURL de los datos descargados
LSQuarantineOriginURLStringPágina de referencia u origen
LSQuarantineOriginTitleTítulo del origen, cuando se registra
LSQuarantineSenderName, LSQuarantineSenderAddressRemitente, rellenado por agentes como Mail
LSQuarantineTypeNumberTipo de cuarentena de Launch Services (descarga web, adjunto de correo, etc.)
LSQuarantineOriginAliasBlob 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. Suma 978307200 para 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 QUARANTINE de mac_apt (base de datos y .LastGKReject): python mac_apt.py -o out MOUNTED /Volumes/evidence QUARANTINE.
  • Plugin ls_quarantine de 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 curl no 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 kMDItemWhereFroms en el almacén de Spotlight.
  • El cambio de flag de 0083 a 00c3 activa 0x0040 (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