Windows ECDSA FAIL 釋疑 CVE-2020–0601

中文的大家讀得比較快。

Jerry Ho
Jerry Ho
9 min readJan 19, 2020

--

其實Chain of Fools那篇已經寫得超級清楚了…不過畢竟是英文的。

以下簡單整理一下時間軸、出問題的lib、出問題的數學式、微軟patch過的function、PoC、以及可以串的exploit

Disclaimer: 沒有一個思路是我原創的。因為英文大概有些人會看得很累,稍微整理個tl;dr給大家而已 — 有講錯請不吝修正,因為那代表大概原本逆的人搞錯了 XD

時間軸

起先是NSA…大概用了很久的0day,2020/01/14的時候跟微軟跟媒體記者¹同步disclose。

NSA從DoD的網域那邊發了一篇 “Patch Critical Cryptographic Vulnerability in Microsoft Windows Clients and Servers”²,然後微軟也從善如流的上了KB4528760³,cert.org也給了描述⁴。

除此之外,一些據說很好繞的防毒⁵啦,很好繞的defender⁵啦,都同步上線了偵測,可以抓到用這招造假的cert。

這個patch優先權滿高的,所以各位應該週三週四都有被推patch。如果你們沒有其他的major patch一起排著,更新一下其實只多花30秒,滿快的。

出問題的lib

出問題的lib是crypt32.dll。而且還要大於特定版號才有問題。

這邊我沒特別逆,給各位兩個樣本,一個2020/01/03 patch過的,一個2019/11/02還沒patch過的(簽章日期)。

各位可以自行逆一下,看看下面其他研究者說的跟你看到的有沒有一樣 XD

https://mega.nz/#F!jjBF3CID!NegRPwHxG1NYdt3oyHzs8w

此漏洞存在於crypt32.dll 特定版本,並非所有版本。根據NSA的說法,要是2015之後有上patch的Windows,或是Windows 10才會中招。筆者看起來是要支援CNG (Cryptography API: Next Generation)⁶的Windows版本才有這個洞。

原因:原先的Windows crypto API只支援NIST suite-B中的一小部分曲線,不支援user-supplied arbitrary curve。

但是,在上述提到的API更新後(exact date undocumented⁷ ,加入了可以自己supply更多常見named curve的功能。

相關reference:

https://docs.microsoft.com/en-us/windows/win32/seccng/cng-reference

https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-identifiers

https://docs.microsoft.com/en-us/windows/win32/seccrypto/cryptography-functions

https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/

然後,問題就出在這裡啦…※細節還沒逆,可能有錯

你餵給他cert的時候,Windows會很天兵的相信你cert裡面的domain parameter。你說這條是named curve,是P-256,他就信;你說P-256的base point是cert裡面寫的這個值,他也信⁸。

值得一提的是,有人”預言“了這個攻擊…

Vaudenay, Serge. “Digital signature schemes with domain parameters.” Australasian Conference on Information Security and Privacy. Springer, Berlin, Heidelberg, 2004.

先知4 ni !

出問題的數學式

我建議大家直接看數學啦,沒什麼英文。聽我重述不是很精確。

什麼?你說沒有英文可是是日文?沒關係啦看符號就好 (X

真的想看英文的話也可以看這個,不過沒有很完整。credits to tptacek @ hackernews

簡單來說,Trapdoor function就是正算很簡單,逆算很難的一種東西。
(以下舉例全部省略值域條件..)

要在橢圓曲線上找點的話,k*G = Q,Q當public key,G當base point,k當..private key好了。(很不嚴謹)

給你一個G(=知道G),隨意乘一個k,算出Q沒有難度;可4如果你只知道Q跟G,你要回推k是多少,那個難度就不太trivial了(O(sqrt(n))。這就是trapdoor function,也是ECC目前安全的原因。

但在這次的CVE裡面,因為windows不驗證你給的parameter嘛..問題就出在這邊啦。

你就可以拿一個”你要偽造的對象組織憑證”,拿出該憑證指定的named curve的domain parameter(p, a, b, G, n, h),然後把base G換掉,換成一個你自己產生的的G’。

之後很開心的生一個Q = G’ * k’,反正k’ G’都是我的人,要符合Q也是很簡單的噹噹。(Q為原組織/憑證public key,從頭到尾不會變 — 因為你就是想偽裝該組織)

這樣Windows因為不檢查G的關係,他就會覺得你拿k’簽出來的東西哎呀驗起來對啊揪咪,你是Q組織來的,安全性就就死掉了。

那k’G’怎麽生?

讓Q =k’*G’ 成立的方法很簡單,https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication

既然Q是G的k倍,可是你死都不知道k;那我們把Q除一下總可以了吧,手動退回去。

看你要把k’搞成1/2個Q還是1/3的Q都可以…遵照ECC點乘法,然後就生出一把新的k’,可以拿來簽了,揪咪。

為什麼驗證會過ㄋ,因為

G’ =(1/k’) * Q

=> k’ * (1/k’ * Q)= Q

直接對消掉ㄌ,94這麼樸實無華且枯燥。

實際上請參照課本,謝謝你Stallings讓我不用打數學式!

微軟patch過的function

https://twitter.com/esizkur/status/1217162360072425478

直接加了一條確認用的function。

不過還是請大家自己開樣本自己看看前後的call比較準。

PoC

https://github.com/kudelskisecurity/chainoffools/blob/master/gen-key.py

https://github.com/saleemrashid/badecparams

不然就是openssl自己生。

其實網路上已經到處流竄ㄌ,大家自己挑個順眼的來看!

可以串的exploit

RDP(CVE-2020–0609, 0610)

Authenticode spoofing(我外行,這算RCE? CVE-2020–0611)

And, 任何你覺得需要簽章需要CertGetCertificateChain的東西(chrome好像就會調windows crypto api..就死掉了。Firefox沒死!)

這邊有個人家整理的看起來會更新的清單 https://gist.github.com/SwitHak/62fa7f8df378cae3a459670e3a18742d

不過我建議各位web黑黑還是可以善用自己的想像力…XD

寫在最後

第一次追CVEs,滿好玩的,可惜目前能力還沒辦法逆crypt32.dll,無法知道精確的到底是哪個function實作出問題。

歡迎留言補充你自己寫的或其他人的write-up!

--

--

Jerry Ho
Jerry Ho

A cryptographer, rigorous defender of civil liberties on blockchain. Trilingual in Mandarin, Japanese and English, I firmly believe in self-sovereign identity.