Skip to content

Decodificar los requisitos de código csreq de TCC.db

Cómo leer los blobs csreq e indirect_object_code_identity de TCC.db: requisitos compilados, anclas, identificadores y clientes ad hoc con solo cdhash.

Publicado el 6 min de lectura

Resumen. La columna csreq de una fila de TCC.db es un requisito de código compilado: un pequeño blob binario que empieza por el número mágico 0xFADE0C00 y codifica una regla en el Code Signing Requirement Language de Apple, como identifier "com.apple.Terminal" and anchor apple. tccd aplica la fila a cualquier código que cumpla esa regla. indirect_object_code_identity contiene el mismo tipo de blob para el destino de una concesión de Automatización. Un requisito que solo es cdhash H"..." fija una compilación exacta y es típico del código con firma ad hoc. En un Mac, csreq -r- -t decodifica un blob; TCC Parser decodifica ambas columnas a texto en el navegador.

Por qué el requisito importa más que el nombre

La columna client indica para quién es la fila: un bundle ID como com.example.app o una ruta absoluta como /usr/local/bin/tool. Pero un nombre es fácil de reutilizar. Cualquiera puede compilar una app que declare el bundle ID com.example.app. Lo que impide que ese impostor herede los permisos de la app real es el requisito almacenado: cuando un programa con ese identificador pide el servicio, tccd comprueba si la firma de código del programa cumple csreq.

Para el investigador, eso tiene dos consecuencias:

  • Una fila por bundle ID se aplica a cualquier código que cumpla el requisito. Si el requisito es estricto (ancla de Apple o un Team ID concreto), solo cumplen las compilaciones de ese desarrollador firmadas correctamente. Si es laxo o no existe, la protección es más débil.
  • Puede que el binario que hay hoy en disco no sea el que se aprobó. Las actualizaciones, las sustituciones y las herramientas borradas rompen el vínculo entre "fila" y "archivo". El requisito es la evidencia que describe lo que se aprobó.

El formato del blob

Un requisito compilado, tal como se guarda en csreq, es una estructura big-endian:

ParteContenido
Número mágico0xFADE0C00 (requisito)
LongitudLongitud total del blob
Tipo1: forma de expresión
ExpresiónUna expresión prefija: un operador seguido de sus operandos (cadenas, hashes, campos de certificado, expresiones anidadas)

Rara vez tendrá que recorrer la expresión a mano. Conocer el formato sirve para reconocer el blob (en una vista hexadecimal empieza por FA DE 0C 00) y para fiarse del texto que devuelve un decodificador solo tras comprobar que ha consumido el blob entero.

Decodificar en un Mac

La forma nativa de macOS es la herramienta csreq. Extraiga el blob como bytes y páselo por la entrada estándar:

sqlite3 TCC.db "SELECT hex(csreq) FROM access
                WHERE client = 'com.apple.Terminal'
                  AND service = 'kTCCServiceSystemPolicyAllFiles';" \
  | xxd -r -p | csreq -r- -t

Para compararlo con un binario en disco, muestre el requisito designado de ese binario:

codesign -d -r- /System/Applications/Utilities/Terminal.app

Si no trabaja en un Mac, o tiene cientos de filas, TCC Parser decodifica cada blob csreq e indirect_object_code_identity a texto de requisito y lo muestra junto a la fila.

Cómo leer el texto decodificado

Los requisitos son expresiones booleanas. Las cláusulas que verá con más frecuencia:

CláusulaSignificado
identifier "com.apple.Terminal"El identificador de firma del código debe ser exactamente este
anchor appleFirmado por la propia Apple (software de Apple)
anchor apple genericEncadena con la raíz de Apple, lo que incluye las firmas Developer ID y App Store
certificate leaf[subject.OU] = TEAMIDEl certificado de firma pertenece a este Team ID
cdhash H"..."El hash del code directory debe ser exactamente este valor: una compilación concreta
and, or, paréntesisCombinan cláusulas

Tres patrones cubren la mayoría de las filas:

Software de Apple. identifier "com.apple.Terminal" and anchor apple. Solo cumple el código firmado por Apple con ese identificador.

Software de terceros firmado. anchor apple generic and identifier "com.example.app" and certificate leaf[subject.OU] = TEAMID, a menudo con cláusulas adicionales sobre campos del certificado. Solo cumplen las compilaciones firmadas por ese Team ID. El Team ID es un buen punto de pivote: búsquelo en su flota, en otras filas TCC y en los datos de firma de código de los binarios en disco.

Código ad hoc o fijado. cdhash H"4b6a..." a secas. No hay más identidad que el hash de una compilación. Es lo que suele verse en los binarios con firma ad hoc (sin certificado de desarrollador) y en muchos clientes identificados por ruta. No es malicioso por sí mismo: las compilaciones propias de los desarrolladores, algunas herramientas de código abierto y los scripts compilados localmente tienen el mismo aspecto. Pero es inusual en un servicio de alto impacto, y significa que la aprobación está ligada a una sola compilación: si el archivo en disco tiene otro cdhash, no es la compilación que se aprobó.

Un requisito ausente (csreq nulo o vacío) también merece una nota. Puede ser legítimo en algunas filas fijadas por el sistema, pero en una concesión visible para el usuario elimina la comprobación de identidad que la fila llevaría normalmente.

indirect_object_code_identity: el otro lado de la Automatización

En la automatización mediante Apple Events (kTCCServiceAppleEvents), una fila tiene dos partes: el client que envía los eventos y el destino en indirect_object_identifier (por ejemplo, com.apple.finder o com.apple.systemevents). indirect_object_code_identity es el requisito compilado de ese destino, en el mismo formato que csreq. Se decodifica igual. Para destinos de Apple cabe esperar requisitos anchor apple; cualquier otra cosa merece una lectura atenta.

Ejemplo práctico

En la muestra ficticia FIN-MBP-03 que incluye TCC Parser, la base de datos del sistema contiene una fila de Accesibilidad para un cliente identificado por ruta:

CampoValor
servicekTCCServiceAccessibility
client/Users/dana.whitlock/Library/Caches/.sync/sync-helper
client_type1 (ruta absoluta)
csreq (decodificado)solo cdhash H"..."

Leído en conjunto: un binario en una carpeta oculta dentro de Caches del usuario, identificado por ruta y no por bundle ID, con un requisito que fija una única compilación ad hoc, y con una capacidad que permite controlar la interfaz de usuario. Cada elemento por separado tiene explicaciones inocentes; juntos son motivo para adquirir ese archivo, calcular su hash, comparar su cdhash con el requisito y averiguar cómo llegó. Compárelo con la fila de acceso total al disco de com.apple.Terminal en la misma base de datos, cuyo requisito es un ancla de Apple: la identidad es correcta, y la pregunta pasa a ser quién usó Terminal y para qué. Ese es el tema de investigar el abuso de permisos TCC.

Cómo usa TCC Parser el requisito

En la pestaña Permissions (permisos), haga clic en una fila para ver su requisito decodificado en el panel de detalle, y la pestaña Findings (hallazgos) marca las filas cuyo requisito es ad hoc (solo cdhash) o no existe. La marca es una invitación a mirar, no un veredicto. El mismo texto decodificado aparece en la exportación JSON, así que puede conservarlo con el caso.

Errores frecuentes

  • Decodificar no es verificar. Leer el requisito indica lo que se aprobó. Saber si un archivo concreto lo cumple requiere el archivo y codesign.
  • Los identificadores no prueban el origen. identifier "com.example.app" sin una cláusula de ancla o de Team ID es débil.
  • Las actualizaciones cambian los cdhash. Una fila con solo cdhash deja de coincidir tras una recompilación, y una nueva solicitud crea un nuevo estado de la fila.
  • El csreq de expired y de MDMOverrides.plist. Las filas caducadas conservan su csreq, y las entradas MDM llevan CodeRequirement (texto) y CodeRequirementData (blob). Compárelos con las filas activas.

Artículos relacionados

Artículos relacionados

Paso a paso: cargue los TCC.db de macOS y su WAL en un parser gratuito en el navegador, lea los hallazgos, revise permisos e historial, y exporte.
Cómo cambió la tabla access de TCC.db de Mojave a Big Sur y Sonoma: allowed y prompt_count, auth_value y auth_reason, pid y last_reminded, y las demás tablas.
Qué registra la base de datos TCC de macOS, qué prueba y qué no, qué servicios importan y un flujo de trabajo repetible para revisar TCC.db en un caso.