说一说Windows严重安全漏洞CVE-2020-0601的原理

1. 背景

这是第一个由美国国安局(NSA)所发现并主动提交给微软的安全漏洞。算法

过去外界曾抨击NSA隐匿安全漏洞,只为追求网络间谍与攻击的作法罔顾广大用户的权益,才使得此次NSA主动向微软通报安全漏洞的事件跃上媒体标题。安全

CVE-2020-0601漏洞位于Window的加密组件CryptoAPI。 CryptoAPI是微软提供给开发人员的Windows安全服务应用程序接口,可用于加密的应用程序,实现数据加密、解密、签名及验证等功能。网络

由Crypt32.dll提供的Microsoft Windows CryptoAPI没法以正确验证ECC证书的信任链。攻击者能够利用该漏洞伪造受信任的根证书签发证书。Crypt32.dll中的CertGetCertificateChain()函数用来验证X.509的合法性,跟踪到受信任的根CA签发的证书,因为函数中存在漏洞,可使证书,包括第三方非Microsoft的根证书,都不能获得正确的验证。函数

360对该漏洞分析:https://cert.360.cn/report/detail?id=082c39952ca78152857c31e35e9af6d5加密

2. 原理

2.1 ECC/椭圆曲线密码

ECC椭圆曲线加密(Elliptic curve cryptography)于1985年由Neal Koblitz和Victor Miller分别独立提出的公钥密码算法。spa

优点:使用更小的密钥(对比RSA)来提供至关或更高等级的安全。.net

ECC核心离散对数问题:3d

设G为曲线上一点G=(Gx, Gy),d为一个整数, 点Q = d*G。blog

给定d和G,很容易求Q。接口

给定G和Q,很难求出d。

ECC中Q为公钥,公开;d为私钥,用户本身秘密掌握。

2.2 CVE-2020-0601漏洞原理

CVE-2020-0601漏洞原理在于 win10 增长了对带参数ECC密钥的支持,但在 crypt32.dll 中作签名验证时,只检查匹配的公钥 Q,而没有检查生成元 G。

假设合法用户A,分别取基点G、私钥d、公钥 Q,Q = dG。

因为 win10 支持自定义生成元 G',攻击者能够取基点 G' = Q,私钥d' = e(单位元),公钥任然为Q,Q = dG = d'G'。

此时合法用户A的公钥和攻击者的公钥相同,都是Q。

因为验证缺陷,只检测 公钥Q。 从而,攻击者用本身的私钥d' = e(单位元),会被验证经过,认为是用户A的私钥d 作出的签名。

我的认为,攻击者能够取随机数x为本身的私钥, 选基点为inv(x)Q,这样他的公钥仍然为Q=x*inv(x)Q,即便检查用户的基点是否是为G,也能执行此攻击。不知这样的理解是否正确。

2.3 攻击(简化)

简单地讲,伪造的Q = d'G'在验证签名时过程以下:

假设exe文件 A 的hash值是 X,用伪造的私钥 d' 对X签出的值是 Y,验证时,用公钥Q 验证X和签名值Y会认证经过,系统认为签名正确,完成绕过。

利用此漏洞可使用伪造的证书对恶意的可执行文件进行签名,使文件看起来来自可信的来源,或者进行中间人攻击并解密用户链接到受影响软件的机密信息。

3. 解法

在ECDSA中,基点是随域参数一块儿发布的。我的以为不该该由用户自定义基点(生成元),而应该固定选择使用域参数中的基点,或者对自定义参数的曲线进行更加严格的管控,好比参数检测,严禁自定义曲线和标准曲线之间可能存在的交叉等。

附录 ECDSA签名流程

点击图解漏洞CVE-2020-0601中涉及的ECC签名算法ECDSA