利用Windows CryptoAPI漏洞 - Trail of Bits博客
Ben Perez
2020年1月16日
密码学, 漏洞利用
周二,NSA宣布在Windows 10和Windows Server 2016/2019的证书验证功能中发现了一个严重漏洞。该漏洞允许攻击者在多种场景(如HTTPS和代码签名)中破坏信任验证。担心受影响?请访问 https://whosecurve.com/ 获取重要详情并检查您的系统是否易受攻击。然后返回本文继续阅读,了解该漏洞的具体原理和工作方式。
如果没有logo,为什么要打补丁?https://whosecurve.com
从高层次看,该漏洞利用了Crypt32.dll未能正确检查提供的根证书中指定的椭圆曲线参数是否与Microsoft已知参数匹配的事实。有趣的是,该漏洞并未利用椭圆曲线特有的任何数学属性——完全相同的漏洞也可能出现在普通的DSA签名验证库中。因此我们首先回顾如果Crypto32.dll使用普通DSA时这个漏洞会如何工作。
攻击的简化版本
DSA的安全性依赖于素数模整数群上的离散对数问题难以解决。考虑以下等式:
|
|
如果只知道p、g和b,很难找到x。为了建立DSA,用户需要指定素数p和生成元g。使用这两个参数,他们可以创建私钥x和公钥pk = g^x mod p。这些密钥使得只有私钥能创建签名,但可以用公钥验证签名。签名伪造的难度因此与离散对数问题相当(非常困难)。
但像DSA这样的数字签名算法本身不太实用,因为它们没有提供用户信任特定实体关联公钥的机制。这就是X.509证书的用武之地。X.509证书是一个明确声明"此公钥属于此人"的文件,由其他人(可能是该公钥的所有者)签名。这些证书可以链式连接,从"根"证书开始,证明根证书颁发机构(CA)的身份。根CA签署中间证书以证明中间CA的身份,中间CA签署其他中间证书,依此类推,直到最后的"叶子"证书。
每个证书包含有关签名算法和所用参数的信息。Microsoft的证书可能如下所示(高度简化):
|
|
当Windows用户收到X.509证书链时,他们会检查确保其根部的CA是Microsoft信任的。但如果Windows只检查确保证书的公钥与受信任实体匹配,而不检查相关的系统参数,会发生什么?换句话说,当攻击者可以更改与给定公钥pk关联的p或g值而Windows未察觉时,会发生什么?实际上,省略此检查会完全破坏DSA的安全性。
利用此漏洞的一种潜在方法是简单地将g = p设置并使私钥x = 1。这允许攻击者签署任何消息,仿佛他们是pk的合法所有者,因为他们现在知道了私钥(它是1)。但事情可能变得更有趣:我们可以选择一个新的私钥y,并将恶意生成元设置为g’ = y^–1 * pk,而不是简单地将新生成元设置为目标的公钥。这意味着证书仍然有效拥有密钥,但只有攻击者知道,而不是原始颁发者。
重要的是,此攻击无需任何人解决离散对数问题即可工作。本质上,如果与给定公钥关联的参数真实性未建立,攻击者可以选择任何他们想要的私钥。此利用场景最初由Vaudenay在2004年概述,并称为域参数移位攻击,但直到现在才在野外被发现。
实际漏洞
利用Crypt32.dll中的漏洞涉及调整先前的攻击,使签名者使用椭圆曲线变体ECDSA而不是DSA。实际上,您不需要对椭圆曲线了解太多就能理解其工作原理。您只需要知道椭圆曲线在数学上大致等同于整数模p,除了不是乘以数字,而是几何操作曲线上的点。在本文中,曲线点用粗体大写字母表示,将点P自身加n次写作n * P。
图1. 您见过无数次的展示椭圆曲线加法的图表
椭圆曲线与点加法一起创建了另一个离散对数问题难以解决的结构。此外,与普通DSA情况一样,ECDSA需要在生成私钥/公钥对之前选择一组公共参数,包括生成元。通常这些参数通过命名曲线来指定,例如椭圆曲线secp256r1 (1.2.840.10045.3.1.7),但用户可以手动指定它们。在这种情况下,用户必须提供定义椭圆曲线(A,B)的常数、进行算术运算的素数p、群的生成元G以及关于该群大小的信息(阶、辅因子)。对于此攻击,我们只关心G。
现在我们有了椭圆曲线的一些背景知识,不难看出攻击的工作原理与DSA基本相同:更改指定ECDSA的参数,使生成元对应于您知道的私钥,但具有与您试图欺骗的证书颁发机构相同的公钥。通过编辑参数,我们可以控制证书的有效密钥,并用它来证明我们想要的任何身份。
在现实生活中,参数验证绕过也稍微复杂一些。Microsoft确实检查大多数证书中使用的参数是否有效,但当呈现它已缓存的根证书时,如果证书使用椭圆曲线密码学且公钥与缓存匹配,它将跳过参数验证。这意味着对于大多数用户可能见过的常见根CA,我们的攻击是可行的。实际上,这意味着我们可以为几乎任何网站生成有效的TLS证书,绕过代码签名限制,或伪造文件和电子邮件的签名。为了解释目的,让我们看看如何中间人攻击某个网站的https流量。
构建伪造证书
首先我们需要选择一个受信任的根证书。Microsoft在此处维护列表。出于我们的目的,我们选择了Microsoft EV ECC Root Certificate Authority 2017。这是一个secp384r1证书,因此公钥是由secp384r1曲线给定参数定义的曲线上的一个点。
图2. 带有公钥的受信任证书
接下来我们需要为我们的恶意证书生成一个新的私钥,定义在不同的曲线上,使用显式参数。此对象具有特定的ASN.1密钥编码,我们使用OpenSSL生成。记住从上一节,我们希望保持公钥与私钥相同以绕过验证。一旦我们有了新证书的公钥和私钥,我们就可以用它们计算一个生成元使它们对应。更准确地说,我们需要计算G’ = x^{-1} * P,其中x是我们的私钥标量,P是来自MS证书的公钥点(这对应于上一节中的第二个攻击场景)。
现在我们有了一个新的变异密钥,我们可以用它来生成CA证书:
图3: 我们坏根的解析视图
生成该证书后,我们可以用它为我们想要的任何东西签署叶子证书。此密钥/证书仅由"坏"根签名——不需要自定义参数或任何魔法。
图4: whosecurve.com的证书
最后,我们确保将"完整链"作为TLS连接的一部分发送。在正常TLS中,您发送叶子证书以及任何中间证书,但不发送根本身。在这种情况下,我们需要发送该根以触发缓存错误。瞧!
图5. 非真实TLS证书
修复漏洞和经验教训
对Microsoft来说幸运的是,修复此错误只需要在签名验证期间添加几个检查以确保ECDSA参数是真实的。对其他人来说不幸的是,此漏洞绝对是毁灭性的,要求所有运行Windows 10的系统立即打补丁。在此之前,攻击者可以伪造TLS、代码、文件或电子邮件的签名。
在密码学上,此错误是一个很好的例子,说明增加参数选择的数量如何增加系统脆弱性。多年来我们已经知道显式指定曲线(与命名曲线相对)是一个坏主意,这是又一个证据。它也是一个很好的提醒,处理数字签名时需要验证所有密码信息。
虽然我们未提供此漏洞的PoC,但我们强烈建议人们打补丁,因为公共利用代码已于今天可用!我们还建立了一个网站演示此缺陷,供任何有兴趣检查其系统是否未打补丁的人使用:去找出 Whose Curve Is It Anyway?
参考文献:
- HN推测
- Scott的CT绕过建议
- Saleem Rashid的PoC
如果您喜欢这篇文章,请分享:
Twitter LinkedIn GitHub Mastodon Hacker News
页面内容
- 攻击的简化版本
- 实际漏洞
- 构建伪造证书
- 修复漏洞和经验教训
最近文章
- 构建安全消息传递很难:对Bitchat安全辩论的细致看法
- 使用Deptective调查您的依赖项
- 系好安全带,Buttercup,AIxCC的评分回合正在进行中!
- 使您的智能合约超越私钥风险成熟
- Go解析器中意外的安全隐患
© 2025 Trail of Bits.
使用Hugo和Mainroad主题生成。