В наборе криптографических библиотек NSS (Network Security Services), развиваемых компанией Mozilla, выявлена критическая уязвимость (CVE-2021-43527), которая может привести к выполнению кода злоумышленника при обработке цифровых подписей DSA или RSA-PSS, заданных с использованием метода кодирования DER (Distinguished Encoding Rules). Проблема, которой присвоено кодовое имя BigSig, устранена в выпусках NSS 3.73 и NSS ESR 3.68.1. Обновления пакетов в дистрибутивах доступны для Debian, RHEL, Ubuntu, Fedora, SUSE, Arch Linux.
Проблема проявляется в приложениях, использующих NSS для обработки цифровых подписей CMS, S/MIME, PKCS #7 и PKCS #12, или при верификации сертификатов в реализациях TLS, X.509, OCSP и CRL. При этом уязвимость не проявляется в Firefox, Thunderbird и Tor Browser, в которых для верификации используется отдельная библиотека mozilla::pkix, а также не затрагивает браузеры на основе Chromium (с 2015 года переведены на BoringSSL). При этом уязвимость может всплыть в различных клиентских и серверных приложениях с поддержкой TLS, DTLS и S/MIME, почтовых клиентах и PDF-просмотрщиках, использующих NSS-вызов CERT_VerifyCertificate() для проверки цифровых подписей. В качестве примера уязвимых приложений упоминаются LibreOffice, Evolution и Evince.
Уязвимость вызвана ошибкой в коде проверки верификации сертификатов в функции vfy_CreateContext из файла secvfy.c. Ошибка проявляется как при чтении клиентом сертификата с сервера, так и при обработке сервером сертификатов клиентов. В процессе проверки цифровой подписи, закодированной методом DER, NSS декодирует подпись в буфер, имеющий фиксированный размер, и передаёт данный буфер в модуль PKCS #11. При дальнейшей обработке, для подписей DSA и RSA-PSS некорректно проверяется размер, что приводит к переполнению буфера, выделенного под структуру VFYContextStr, если размер цифровой подписи превышает 16384 бит (под буфер выделяется 2048 байт, но не проверяется, что подпись может быть большего размера).
Содержащий уязвимость код прослеживается с 2003 года, но он не представлял угрозы до рефакторинга, проведённого в 2012 году. В 2017 году при реализации поддержки RSA-PSS была допущена та же ошибка. Для совершения атаки не требуется ресурсоёмкая генерация определённых ключей для получения нужных данных, так как переполнение происходит на стадии до проверки корректности цифровой подписи. Выходящая за границы часть данных записывается в область памяти, содержащую указатели на функции, что упрощает создание рабочих эксплоитов.
Уязвимость была выявлена исследователями из Google Project Zero в ходе экспериментов с новыми методами fuzzing-тестирования и является хорошей демонстрации того, как в широко протестированном известном проекте могут длительное время оставаться незамеченными тривиальные уязвимости:
- Код NSS сопровождается опытной командой, отвечающей за безопасность, применяющей современные методы тестирования и анализа ошибок. Действует несколько программ по выплате существенных вознаграждений за выявление уязвимостей в NSS.
- NSS был одним из первых проектов подключившихся в инициативе Google oss-fuzz и также проверялся в развиваемой Mozilla системе fuzzing-тестирования на базе libFuzzer.
- Код библиотеки многократно проверялся в различных статических анализаторах, в том числе с 2008 года отслеживался сервисом Coverity.
- До 2015 года NSS использовался в Google Chrome и независимо от Mozilla проверялся командой Google (с 2015 года Chrome перешёл на BoringSSL, но поддержка порта на базе NSS сохраняется).
Основные проблемы, из-за которых проблема долгое время оставалась незамеченной:
- NSS модульная библиотека и fuzzing-тестирование проводилось не в целом, а на уровне отдельных компонентов. Например, отдельно проверялся код декодирования DER и обработки сертификатов – в ходе fuzzing-а вполне мог был получен сертификат, приводящий к рассматриваемой уязвимости, но его проверка не доходила до кода верификации и проблема не проявляла себя.
- При fuzzing-тестировании задавались жёсткие ограничения на размер вывода (10000 байт) при отсутствии подобных ограничений в NSS (многие структуры в штатном режиме могли иметь размер больше 10000 байт, поэтому для выявления проблем требовался больший объём входных данных). Для полноценной проверки лимит должен был быть 224-1 байт (16 МБ), что соответствует максимальному размеру сертификата, допустимого в TLS.
- Неверное представление об охвате кода fuzzing-тестированием. Уязвимый код активно тестировался, но с использованием fuzzer-ов, не способных сгенерировать необходимые входные данные. Например, fuzzer tls_server_target использовал предопределённый набор готовых сертификатов, что ограничивало проверку кода верификации сертификата только TLS-сообщениями и изменениями состояния протокола.