CVE-2020-0601漏洞详细分析

来源:岁月联盟 编辑:猪蛋儿 时间:2020-01-29

2020年1月15日,微软公布了1月份的补丁更新列表,其中存在一个位于CryptoAPI椭圆曲线密码(ECC)证书检测绕过相关的漏洞(CVE-2020-0601),该漏洞为NSA发现并汇报给微软。攻击者可以利用这个漏洞,使用伪造的代码签名证书对恶意的可执行文件进行签名,并以此恶意文件来进行攻击。
0×01 补丁分析
从微软的官方介绍上可知,此漏洞存在于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)。
0×02 椭圆曲线数字签名算法(ECDSA)
在2009年修订的FIPS 186加入了基于椭圆曲线密码的数字签名方法,称其为椭圆曲线数字签名算法(ECDSA)。由于椭圆曲线密码效率方面的优势,ECDSA的应用越来越广泛。
ECDSA算法过程如下:
参与数字签名的所有方都使用相同的全局域参数,用于定义椭圆曲线以及曲线上的基点。
签名者首先需要生成一对公钥、私钥。签名者可以选择一个随机数作为私钥,使用随机数和基点,可以计算椭圆曲线上的另一个解点,作为公钥。
对于待签名的消息计算其Hash值。签名者使用私钥、全局域参数、Hash值产生签名,包括两个整数r和s。
验证者使用签名者的公钥、全局域参数、整数s作为输入,计算v,并与r比较。如果两者相等,则签名通过。
0×03 漏洞原理
通常,签名者产生一对公私钥后,要去证书中心(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,从而完成攻击。
0×04 漏洞验证
提取ECC根证书公钥信息

生成伪造的ECC根证书

生成代码签名用的证书,并用伪造的ECC根证书做签名

打包数字签名证书

对可执行文件CVE20200601.exe签名

[1] [2]  下一页