2020年1月15日,微软公布了1月份的补丁更新列表,其中存在一个位于CryptoAPI椭圆曲线密码(ECC)证书检测绕过相关的漏洞(CVE-2020-0601),该漏洞为NSA发现并汇报给微软。攻击者可以利用这个漏洞,使用伪造的代码签名证书对恶意的可执行文件进行签名,并以此恶意文件来进行攻击。
从微软的官方介绍上可知,此漏洞存在于crypt32.dll文件。在官方网站下载了补丁文件升级更新后,新的crypt32.dll与未更新的版本对比如下:
从图中可以看出,CertDllVerifyMicrosoftRootCertificateChainPolicy函数存在改动,查看引用该函数的地方:
从图可知,函数CertVerifyCertificateChainPolicy中有两处调用了CertDllVerifyMicrosoftRootCertificateChainPolicy函数,查看CertVerifyCertificateChainPolicy的代码:
从上图代码可知,函数CertVerifyCertificateChainPolicy将四个参数pszPolicyOID, pChainContext, pPolicyPara, pPolicyStatus直接传递给了CertDllVerifyMicrosoftRootCertificateChainPolicy,并未做处理。接着查看CertDllVerifyMicrosoftRootCertificateChainPolicy的代码。
注意到CertDllVerifyMicrosoftRootCertificateChainPolicy函数中有多处形如memcmp(v16, &pbComputedHash, 0x20u)的内存对比代码,其中v16是crypt32.dll某处固定的数据,pbComputedHash是由CryptHashCertificate2函数计算过的hash值,0x20u是指对比的内存长度,刚好是ECC数字签名证书的指纹hash长度,这可以通过查看ECC根证书的详细信息可知。
而CryptHashCertificate2函数传入的值由CertDllVerifyMicrosoftRootCertificateChainPolicy的参数解析而来,并且只包含了公钥信息。由此可以判断,虽然函数CertVerifyCertificateChainPolicy将参数pszPolicyOID, pChainContext, pPolicyPara, pPolicyStatus都传递给了CertDllVerifyMicrosoftRootCertificateChainPolicy函数,但CertDllVerifyMicrosoftRootCertificateChainPolicy函数只利用了其中的公钥信息,存在参数校验不全的逻辑缺陷。至于为什么只校验公钥信息就会被伪造的数字签名绕过检查,在介绍CVE-2020-0601漏洞原理之前,我们先来简单介绍下椭圆曲线数字签名算法(ECDSA)。
在2009年修订的FIPS 186加入了基于椭圆曲线密码的数字签名方法,称其为椭圆曲线数字签名算法(ECDSA)。由于椭圆曲线密码效率方面的优势,ECDSA的应用越来越广泛。
ECDSA算法过程如下:
参与数字签名的所有方都使用相同的全局域参数,用于定义椭圆曲线以及曲线上的基点。
签名者首先需要生成一对公钥、私钥。签名者可以选择一个随机数作为私钥,使用随机数和基点,可以计算椭圆曲线上的另一个解点,作为公钥。
对于待签名的消息计算其Hash值。签名者使用私钥、全局域参数、Hash值产生签名,包括两个整数r和s。
验证者使用签名者的公钥、全局域参数、整数s作为输入,计算v,并与r比较。如果两者相等,则签名通过。
通常,签名者产生一对公私钥后,要去证书中心(certificate authority,简称CA),为公钥做认证,以此来证明签名者本身身份。证书中心用自己的私钥,对签名者的公钥和一些相关信息一起做签名,生成数字证书(DigitalCertificate)。由补丁分析部分可知,微软在对数字签名做合法校验时,支持椭圆曲线参数的自定义输入,又只对公钥信息做校验,存在严重缺陷。
攻击者可以传入自定义的全局域参数、签名信息s,只需要公钥信息与系统ECC根证书Microsoft ECC Product Root Certificate Authority 2018的公钥保持一致,就可以绕过校验逻辑,让数字签名信息看起来就是ECC根证书签发的一样。而这,是很容易做到的。
假设ECC根证书的私钥是d(对攻击者未知),基点是G,公钥是Q=dG。攻击者可以选择跟ECC根证书一样的椭圆曲线,只需d’=1(单位元),G‘=Q,则Q‘=d’G'=Q,从而完成攻击。
提取ECC根证书公钥信息
生成伪造的ECC根证书
生成代码签名用的证书,并用伪造的ECC根证书做签名
打包数字签名证书
对可执行文件CVE20200601.exe签名
在未打补丁的机器上,可执行文件CVE20200601.exe的数字签名校验通过
打完补丁后,可执行文件CVE20200601.exe的数字签名信息无法验证。
https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/CVE-2020-0601
《密码编码学与网络安全——原理与实践(第六版)》
http://www.ruanyifeng.com/blog/2011/08/what_is_a_digital_signature.html
https://github.com/ollypwn/cve-2020-0601
https://medium.com/hackernoon/bluetooth-hacking-cheating-in-elliptic-curve-billiards-c092fdf70aae
*本文作者:奇安信代码卫士,转载请注明来自FreeBuf.COM