Skip to content

Décoder les exigences de code csreq dans TCC.db

Lire les blobs csreq et indirect_object_code_identity de TCC.db : exigences compilées, clauses anchor et identifier, clients ad hoc réduits à un cdhash.

Publié le 7 min de lecture

En bref. La colonne csreq d'une ligne de TCC.db est une exigence de code compilée : un petit blob binaire qui commence par le nombre magique 0xFADE0C00 et encode une règle dans le Code Signing Requirement Language d'Apple, par exemple identifier "com.apple.Terminal" and anchor apple. tccd applique la ligne à tout code qui satisfait cette règle. indirect_object_code_identity contient le même type de blob pour la cible d'une autorisation d'Automatisation. Une exigence réduite à cdhash H"..." épingle un build précis et est typique du code signé ad hoc. Sur un Mac, csreq -r- -t décode un blob ; TCC Parser décode les deux colonnes en texte dans le navigateur.

Pourquoi l'exigence compte plus que le nom

La colonne client indique à qui s'applique la ligne : un bundle ID comme com.example.app, ou un chemin absolu comme /usr/local/bin/tool. Mais un nom se réutilise facilement. N'importe qui peut compiler une app qui revendique le bundle ID com.example.app. Ce qui empêche cet imposteur d'hériter des autorisations de la vraie app, c'est l'exigence enregistrée : quand un programme portant cet identifiant demande le service, tccd vérifie que la signature de code du programme satisfait csreq.

Pour un enquêteur, cela a deux conséquences :

  • Une ligne par bundle ID s'applique à tout code qui satisfait l'exigence. Si l'exigence est stricte (ancre Apple, ou un Team ID précis), seuls les builds correctement signés par ce développeur sont acceptés. Si elle est lâche ou absente, la protection est plus faible.
  • Le binaire présent aujourd'hui sur le disque n'est peut-être pas celui qui a été approuvé. Mises à jour, remplacements et outils supprimés rompent tous le lien entre « ligne » et « fichier ». L'exigence est l'élément de preuve qui décrit ce qui a été approuvé.

Le format du blob

Une exigence compilée, telle qu'elle est stockée dans csreq, est une structure big-endian :

PartieContenu
Nombre magique0xFADE0C00 (exigence)
LongueurLongueur totale du blob
Type1 : forme expression
ExpressionUne expression préfixée : un opérateur suivi de ses opérandes (chaînes, hachages, champs de certificat, expressions imbriquées)

Il est rarement nécessaire de parcourir l'expression à la main. Connaître la structure sert à reconnaître le blob (il commence par FA DE 0C 00 dans une vue hexadécimale) et à ne faire confiance à la sortie texte d'un décodeur qu'après avoir vérifié qu'il a consommé la totalité du blob.

Décoder sur un Mac

La méthode native de macOS passe par l'outil csreq. Extrayez le blob sous forme d'octets et fournissez-le sur l'entrée standard :

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

Pour comparer avec un binaire présent sur le disque, affichez l'exigence désignée de ce binaire :

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

Si vous n'êtes pas sur un Mac, ou si vous avez des centaines de lignes, TCC Parser décode chaque blob csreq et indirect_object_code_identity en texte d'exigence et l'affiche à côté de la ligne.

Lire le texte décodé

Les exigences sont des expressions booléennes. Les clauses que vous verrez le plus :

ClauseSignification
identifier "com.apple.Terminal"L'identifiant de signature du code doit être exactement celui-ci
anchor appleSigné par Apple elle-même (logiciels d'Apple)
anchor apple genericChaîne jusqu'à la racine d'Apple, ce qui inclut les signatures Developer ID et App Store
certificate leaf[subject.OU] = TEAMIDLe certificat de signature appartient à ce Team ID
cdhash H"..."Le hachage du code directory doit valoir exactement cette valeur : un build précis
and, or, parenthèsesCombinent les clauses

Trois motifs couvrent la plupart des lignes :

Logiciels Apple. identifier "com.apple.Terminal" and anchor apple. Seul du code signé par Apple avec cet identifiant est accepté.

Logiciels tiers signés. anchor apple generic and identifier "com.example.app" and certificate leaf[subject.OU] = TEAMID, souvent avec des clauses supplémentaires sur des champs de certificat. Seuls les builds signés par ce Team ID sont acceptés. Le Team ID est un point de pivot solide : recherchez-le dans votre parc, dans d'autres lignes TCC et dans les données de signature de code des binaires présents sur disque.

Code ad hoc ou épinglé. cdhash H"4b6a..." seul. Il n'y a aucune identité au-delà du hachage d'un build. C'est ce que l'on voit en général pour les binaires signés ad hoc (sans certificat de développeur) et pour de nombreux clients identifiés par chemin. Ce n'est pas malveillant en soi : les builds personnels des développeurs, certains outils open source et des scripts compilés localement présentent le même aspect. Mais c'est inhabituel pour un service à fort impact, et cela signifie que l'approbation est liée à un seul build : si le fichier sur le disque a un cdhash différent, ce n'est pas le build qui a été approuvé.

Une exigence absente (csreq nul ou vide) mérite aussi une note. Elle peut être légitime pour certaines lignes définies par le système, mais pour une autorisation visible par l'utilisateur, elle supprime le contrôle d'identité que la ligne porterait normalement.

indirect_object_code_identity : l'autre versant de l'Automatisation

Pour l'automatisation Apple Events (kTCCServiceAppleEvents), une ligne implique deux parties : le client qui envoie les événements et la cible dans indirect_object_identifier (par exemple com.apple.finder ou com.apple.systemevents). indirect_object_code_identity est l'exigence compilée de cette cible, au même format que csreq. Décodez-la de la même façon. Pour des cibles Apple, on attend des exigences anchor apple ; tout le reste mérite une lecture attentive.

Exemple commenté

Dans l'échantillon fictif FIN-MBP-03 fourni avec TCC Parser, la base système contient une ligne Accessibilité pour un client identifié par chemin :

ChampValeur
servicekTCCServiceAccessibility
client/Users/dana.whitlock/Library/Caches/.sync/sync-helper
client_type1 (chemin absolu)
csreq (décodé)cdhash H"..." uniquement

Pris ensemble : un binaire situé dans un dossier caché sous les Caches de l'utilisateur, identifié par son chemin plutôt que par un bundle ID, avec une exigence qui épingle un unique build ad hoc, et qui détient une capacité permettant de piloter l'interface utilisateur. Chaque élément pris isolément a des explications anodines ; réunis, ils justifient d'acquérir ce fichier, d'en calculer l'empreinte, de comparer son cdhash avec l'exigence et de chercher comment il est arrivé là. Comparez avec la ligne d'accès complet au disque de com.apple.Terminal dans la même base, dont l'exigence est une ancre Apple : l'identité ne pose pas de problème, et la question devient qui a utilisé Terminal, et pour quoi faire. C'est le sujet de l'article Enquêter sur l'abus des autorisations TCC.

Comment TCC Parser utilise l'exigence

Dans l'onglet Permissions (autorisations), cliquez sur une ligne pour voir son exigence décodée dans le panneau de détail ; l'onglet Findings (constats) signale les lignes dont l'exigence est ad hoc (cdhash seul) ou absente. Ce signalement invite à regarder de plus près, ce n'est pas un verdict. Le même texte décodé figure dans l'export JSON, ce qui permet de le conserver avec le dossier.

Pièges

  • Décoder n'est pas vérifier. Lire l'exigence indique ce qui a été approuvé. Savoir si un fichier donné la satisfait nécessite le fichier et codesign.
  • Un identifiant ne prouve pas l'origine. identifier "com.example.app" sans clause d'ancre ou de Team ID est faible.
  • Les mises à jour changent les cdhash. Une ligne réduite à un cdhash ne correspond plus après une recompilation, et une nouvelle invite crée un nouvel état de la ligne.
  • Le csreq dans expired et MDMOverrides.plist. Les lignes expirées conservent leur csreq, et les entrées MDM portent CodeRequirement (texte) et CodeRequirementData (blob). Comparez-les avec les lignes actives.

Articles liés

Articles liés

Pas à pas : charger les TCC.db de macOS et leur WAL dans un parseur gratuit, lire constats, autorisations et historique, filtrer une période, exporter.
L'évolution de la table access de TCC.db de Mojave à Big Sur et Sonoma : allowed, auth_value, auth_reason, pid, last_reminded et les autres tables.
Ce que la base TCC de macOS enregistre, ce qu'elle prouve ou non, les services qui comptent et une méthode reproductible pour analyser TCC.db.