
Утилита на Python для проверки, подписаны ли образы Android verified boot (vbmeta) общеизвестными тестовыми ключами, что позволяет выявлять ошибки конфигурации в релизных сборках.
Ошибка, с которой иногда сталкиваются консультанты NCC Group, — это подписание Android-сборок известными закрытыми ключами. Это делает производителей устройств (а вместе с ними и их пользователей) уязвимыми даже на устройствах с включённой безопасной загрузкой. У этого поста в блоге две цели:
Когда устройства на базе Android загружаются, сначала проверяется, что загрузчик выполняет подписанный код, затем загрузчик проверяет высокоуровневую операционную систему (HLOS). Этот пост в блоге охватывает только последнюю часть.
Каждый поставщик чипсетов может реализовывать корень доверия (RoT) по-разному, но, как правило, устройства защищаются настройкой e-fuses. Неизменяемый код ПЗУ, прошитый в чипсет, считывает эти e-fuses и интерпретирует их как биты криптографического хеша. Затем хеш используется для проверки доверенного открытого ключа, обычно включённого в двоичный файл загрузчика. После того как открытый ключ подтверждён, он впоследствии используется для криптографической проверки того, что первый изменяемый код, выполняемый на устройстве, подписан. Если этот процесс реализован корректно, любая попытка изменить загрузчик завершится неудачей. OEM-производители, выпускающие устройства на базе Android (камеры видеонаблюдения, умные розетки, датчики и т. п.), обычно используют референсный дизайн и пример кода поставщика чипов (например, Qualcomm) в качестве отправной точки для своего продукта.
AVB является частью механизма, обеспечивающего целостность программного обеспечения, работающего на устройстве. Устройства содержат раздел vbmeta, в котором находится образ, проверяемый криптографически. После успешной проверки загрузчик доверяет содержимому образа vbmeta. Образ содержит информацию, которую загрузчик впоследствии использует для проверки программного обеспечения на таких разделах, как boot, vendor или system.
Для удобства поставщики чипсетов предоставляют эталонный код, который успешно компилируется из коробки, чтобы упростить процесс первоначального запуска устройства для OEM-производителей. Изначально эти образы подписываются с использованием тестовых закрытых ключей, впервые созданных Google и присутствующих во всех ванильных сборках Android. Иногда поставщики чипов обновляют эти тестовые ключи, но закрытые ключи подписи по-прежнему присутствуют в примере кода, поэтому их необходимо считать недоверенными.
NCC Group обнаружила, что производители устройств могут правильно защищать загрузчик, настраивая e-fuses, однако не меняют тестовый закрытый ключ по умолчанию, используемый для подписания HLOS. Поэтому, хотя загрузчик невозможно изменить, злоумышленник может собрать и подписать собственный код HLOS и обновить разделы, которые будут успешно проверены процессом AVB.
NCC Group создала инструмент, который проверяет, содержит ли vbmeta.img открытую часть известного закрытого ключа. Для тестовых ключей инструмент принимает путь, указанный пользователем (задаётся переменной окружения BOARD_AVB_KEY_PATH в Android-сборке), либо использует набор известных ключей, собранных с GitHub и включённых в инструмент.
$ 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/'.
Если ПО HLOS подписано закрытым ключом по умолчанию, то проблема обнаруживается. Например, для сборки 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.
В противном случае инструмент возвращает сообщение об успехе, например для сборки 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
Разработчики Android могут использовать этот инструмент для быстрой проверки, чтобы убедиться, что сборки для релиза/продакшена не подписаны публично известными закрытыми ключами. Его также можно интегрировать в процесс сборки, чтобы гарантировать, что пользовательские сборки Android подписаны корректно, иначе сборка завершится неудачей.