利用Windows CryptoAPI漏洞:从DSA到ECDSA的参数欺骗攻击

本文深入分析了Windows CryptoAPI中椭圆曲线参数验证漏洞的技术细节,展示了攻击者如何通过操纵ECDSA参数伪造证书链,实现TLS中间人攻击和代码签名绕过,并提供了修复方案和密码学实践建议。

利用Windows CryptoAPI漏洞 - The 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的安全性依赖于素数模整数群的离散对数问题难以解决。考虑以下等式:

1
b = g^x mod p

如果只知道p、g和b,很难找到x。设置DSA时,用户需要指定素数p和生成元g。使用这两个参数,可以创建私钥x和公钥pk = g^x mod p。这些密钥使得只有私钥能创建签名,但可用公钥验证。签名伪造的难度与离散对数问题相当(非常困难)。

但DSA等数字签名算法本身不太实用,因为它们不提供用户信任特定实体公钥的机制。这就是X.509证书的作用。X.509证书是一个明确声明"该公钥属于此人"的文件,由其他人(可能是公钥所有者)签名。这些证书可以链式连接,从"根"证书开始,证明根证书颁发机构(CA)的身份。根CA签署中间证书以证明中间CA的身份,中间CA签署其他中间证书,依此类推,直到最终的"叶子"证书。

每个证书包含有关签名算法和所用参数的信息。Microsoft的证书可能如下所示(高度简化):

1
2
3
4
5
6
7
证书颁发机构: Microsoft
名称: Trail of Bits
公钥信息
算法: DSA
生成元: g
素数: p
公钥: pk

当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


页面内容
攻击的简化版本、实际漏洞、构建伪造证书、修复漏洞和经验教训

最近文章
我们构建了MCP一直需要的安全层、利用废弃硬件中的零日漏洞、Inside EthCC[8]:成为智能合约审计员、用Vendetect大规模检测代码复制、构建安全消息传递很难:对Bitchat安全辩论的细致看法

© 2025 Trail of Bits.
使用Hugo和Mainroad主题生成。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计