
Utilitaire Python pour vérifier si les images Android Verified Boot (vbmeta) sont signées avec des clés de test publiquement connues, identifiant ainsi les mauvaises configurations dans les builds de release.
Une erreur parfois rencontrée par les consultants de NCC Group consiste à signer des builds Android avec des clés privées connues. Cela rend les fabricants d'appareils (et par conséquent leurs utilisateurs) vulnérables, même sur les appareils où le démarrage sécurisé est activé. Cet article de blog poursuit deux objectifs :
Lorsque les appareils basés sur Android démarrent, le bootloader est d'abord vérifié pour s'assurer qu'il exécute du code signé, puis il vérifie le système d'exploitation de haut niveau (HLOS). Cet article ne couvre que cette dernière partie.
Chaque fournisseur de chipset peut implémenter la racine de confiance (RoT) différemment, mais généralement, les appareils sont sécurisés en configurant des e-fuses. Le code ROM immuable, gravé sur le chipset, lit ces e-fuses et les interprète comme des bits d'un hash cryptographique. Ce hash est ensuite utilisé pour vérifier une clé publique de confiance, généralement incluse dans le binaire du bootloader. Une fois la clé publique validée, elle est ensuite utilisée pour vérifier cryptographiquement que le premier code modifiable qui s'exécute sur l'appareil est signé. Si ce processus est correctement implémenté, toute tentative de modification du bootloader échouera. Les OEM qui fabriquent des appareils basés sur Android (caméras de sécurité, prises connectées, capteurs, etc.) utilisent généralement la conception de référence et le code d'exemple du fournisseur de puces (c'est-à-dire Qualcomm) comme point de départ de leur produit.
AVB fait partie du mécanisme utilisé pour garantir l'intégrité du logiciel exécuté sur un appareil. Les appareils contiennent une partition appelée vbmeta qui contient une image vérifiée cryptographiquement. Après vérification réussie par le bootloader, l'appareil fait confiance au contenu de l'image vbmeta. L'image contient des informations que le bootloader utilise ensuite pour valider les logiciels présents sur des partitions telles que boot, vendor ou system.
Par commodité, les fournisseurs de chipsets fournissent un code de référence qui compile correctement dès sa sortie de boîte, afin de simplifier le processus d'intégration des appareils pour les OEM. Initialement, ces images sont signées à l'aide de clés privées de test, générées à l'origine par Google, et présentes sur tous les builds Android d'origine. Parfois, les fournisseurs de puces mettent à jour ces clés de test, mais les clés privées de signature restent présentes dans le code d'exemple et doivent donc être considérées comme non fiables.
NCC Group a constaté que les fabricants d'appareils peuvent sécuriser correctement le bootloader en configurant les fusibles, mais qu'ils ne modifient pas la clé privée de test par défaut utilisée pour signer le HLOS. Par conséquent, même si le bootloader ne peut pas être modifié, un attaquant pourrait compiler et signer un code HLOS personnalisé, puis mettre à jour des partitions qui seront vérifiées avec succès par le processus AVB.
NCC Group a créé un outil qui vérifie si vbmeta.img contient la partie publique d'une clé privée connue. Pour les clés de test, l'outil accepte un chemin fourni par l'utilisateur (indiqué par la variable d'environnement BOARD_AVB_KEY_PATH dans le build Android), ou il utilise une collection de clés connues collectées depuis GitHub et incluses avec l'outil.
$ python3 test_avb_key.py --help
Usage:
python test_avb_key.py [VBMETA.IMG] [PATH_PRIVATE_KEY]
Parameters:
* Parameter 'VBMETA.IMG' points to a user or userdebug file from an Android build.
Note: the userdebug image fails this test, it is expected.
* Grep Android build for 'BOARD_AVB_KEY_PATH' to obtain path of signing file,
and leave only the path, i.e. 'external/avb/test/data/'.
Si le logiciel HLOS a été signé avec une clé privée par défaut, le problème est signalé. Par exemple, pour le build LineageOS :
$ python test_avb_key.py ./sample/vbmeta/lineage/vbmeta.img ./sample/aosp/external/avb/test/data/
Opening vbmeta file: ./sample/vbmeta/lineage/vbmeta.img
Using known private key for verification: ./sample/aosp/external/avb/test/data/sign_key.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_pik.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_prk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_psk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_puk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048_gsi.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048_oneplus.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa4096.pem. Public key found at index: 945
If the script was executed on a vbmeta.img file from an Android user build, there is a problem.
Sinon, l'outil renvoie un message de succès, comme par exemple pour le build Pixel9 :
$ python test_avb_key.py ./sample/vbmeta/pixel9/vbmeta.img ./sample/aosp/external/avb/test/data/
Opening vbmeta file: ./sample/vbmeta/pixel9/vbmeta.img
Using known private key for verification: ./sample/aosp/external/avb/test/data/sign_key.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_pik.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_prk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_psk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_atx_puk.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048_gsi.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa2048_oneplus.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa4096.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa4096_oneplus.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa4096_realtek.pem. Public key not found in vbmeta.img file. That's good.
Using known private key for verification: ./sample/aosp/external/avb/test/data/testkey_rsa8192.pem. Public key not found in vbmeta.img file. That's good.
No issues were found with ./sample/vbmeta/pixel9/vbmeta.img
Les développeurs Android peuvent utiliser cet outil comme une vérification rapide, pour s'assurer que les builds de release/production ne sont pas signés à l'aide de clés privées publiquement connues. Il pourrait également être intégré au processus de build afin de garantir que les builds Android de type user soient correctement signés, sinon le build échouera.