コンテンツにスキップ
ビジネスとIT
パッチが適用されていないサーバーからキーを抽出するにはスキルが必要ですが、十分に実行可能です。
クレジット: Aurich Lawson / Thinkstock
クレジット: Aurich Lawson / Thinkstock
OpenSSLのHeartbleed脆弱性については、今や誰もが知っています。最も普及しているTLS実装の一つに境界チェックの不備があり、数百万台(あるいはそれ以上)のWebサーバーでメモリからあらゆる種類の機密情報が漏洩しました。これにより、ログイン認証情報、認証Cookie、そしてWebトラフィックが攻撃者に漏洩する可能性があります。しかし、この脆弱性を利用してサイトのTLS秘密鍵を復元することは可能でしょうか?もしこの脆弱性が利用されれば、PFS(Perfect Forward Secrecy)が当時ネゴシエートされていなかった場合、以前に記録されたトラフィックを完全に復号化できてしまう可能性があります。もしそうでなかった場合、将来のすべてのTLSセッションに対して中間者攻撃を仕掛けられる可能性があります。
これはHeartbleedのより深刻な影響である可能性があるため、調査することにしました。結果は良好で、数日間の作業でテスト用のNginxサーバーから秘密鍵を抽出することができました。その後、この技術をCloudFlare Challengeの解決に適用しました。他のセキュリティ研究者数名と共同で、RSA秘密鍵が実際に危険にさらされていることを独自に実証しました。それでは、秘密鍵の抽出方法と、なぜ攻撃が可能なのかについて、詳しく説明しましょう。
秘密鍵の抽出方法
RSA に詳しくない読者は、こちらで説明を読むことができます。少し単純化すると、ランダムに生成された 2 つの大きな素数pとqを掛け合わせることで、大きな (2048 ビット) 数Nが作成されます。Nは公開されますが、pとq は秘密にされます。 pまたはq を見つけることで、秘密鍵を復元できます。一般的な攻撃はN を因数分解するだけですが、これは難しいと考えられています。ただし、Heartbleed のような脆弱性がある場合、攻撃ははるかに簡単になります。Web サーバーは TLS ハンドシェイクに署名するためにメモリ内に秘密鍵が必要なので、pとq はメモリ内にある必要があり、Heartbleed パケットを使用してそれらを取得しようとすることができます。問題は、返されたデータでそれらをどのように識別するかになります。pとqは 1024 ビット (128 バイト) の長さであり、OpenSSL はメモリ内で大きな数をリトルエンディアンで表すため、これは簡単です。 Heartbleedパケット内の連続する128バイトをリトルエンディアンの数値として扱い、それがNを割り切れるかどうかをテストする総当たり攻撃のアプローチは、潜在的なリークを見つけるのに十分です。ほとんどの人は、この方法でCloudFlareチャレンジを解決しました。
銅細工の改善
でも待ってください、私たちのシナリオはコールドブート攻撃に似ているのではないでしょうか? 部分的な情報から RSA 秘密鍵を復元する方法については、多くの研究が行われてきました。Coppersmith の最も有名な論文の 1 つでは、関連メッセージや不十分なパディングに対するメッセージ復元攻撃、および格子基底簡約を利用した部分的な知識による因数分解が紹介されています。Coppersmith 攻撃では、pの上位または下位半分のビットがわかっていれば、 N を効率的に因数分解できます。これを文脈に当てはめると、128 バイトすべてを必要とする単純なブルートフォース攻撃と比較して、秘密鍵を計算するために必要なのはpの上位/下位 64 バイトだけです。実際には、Coppersmith の限界に達するのは計算コストが高いですが (それでも因数分解よりははるかにマシですが)、77 バイト (60%) がわかっていると仮定すると、Heartbleed パケットをくまなく調べて潜在的な秘密鍵セグメントを非常に迅速に見つけることができます。
振り返ってみると、私が収集した10,000パケット(各64KB)のうち、Coppersmith攻撃に適した秘密鍵の残骸は242個ありました。Sageの包括的なコンピュータ代数ビルディングブロックのおかげで、Coppersmith攻撃の実装は容易になりました(ただし、後にSageは既にCoppersmithを実装していることを知りました)。
もっと良いことはできないでしょうか? openssl rsa -text -in server.keyを使用して RSA 秘密鍵を表示したことがあれば、2 つの素因数pとqの他にもかなりの数の数値があることに気付くでしょう。実際、これらは RSA の中国剰余定理の最適化のために事前に計算された値です。その一部が漏洩した場合、p を推測するためにも使用できます。では、OpenSSL が高速乗算に使用するpとqのモンゴメリ表現はどうでしょうか? これらには Coppersmith のバリアントも含まれるため、部分ビットも役立ちます。これを念頭に置いて、これらの値がすべてわかっているテスト サーバーから収集したパケットでそれらを探すことにしました。しかし、データセットには部分的に (16 バイト超) 表示されたものは 1 つもありません。どうしてこんなことが可能なのでしょうか?
注:私の実験とCloudFlareチャレンジはすべてシングルスレッドのNginxを対象としています。マルチスレッドのwWbサーバーでは、より多くのリークが観測される可能性があります。
なぜpだけが漏れるのか
Heartbleedが初めて公表された際、RSA秘密鍵は漏洩すべきではないという議論が巻き起こりました。結局のところ、RSA秘密鍵はWebサーバーの起動時に読み込まれるため、メモリアドレスの低い領域を占有するからです。そして、ヒープ領域が大きくなるにつれて、Heartbleedによって後から割り当てられたバッファが漏洩しても、RSA秘密鍵には到達しないはずです。この議論は、私がCRT事前計算値を見つけられなかったことと一貫しています。ただし、 pは何らかの形で確実に漏洩しています。この議論が正しいと仮定すると、疑問が生じます。なぜpは漏洩したのでしょうか?
謎をさらに深めるのは、OpenSSLが使用した一時的なBigNumをすべて削除しているように見えることです。一時的な値を動的に割り当てるオーバーヘッドを削減するため、OpenSSLはスタック(LIFO)方式で動作するBigNumプールであるBN_CTXを提供しています。処理が完了すると、コンテキストは破棄され、割り当てられたバッファはすべて削除されます。つまり、Heartbleedパケットが構築される時点では、BN_CTXはすでに解放されているため、メモリ内に一時的な値は残っていないはずです(これもシングルスレッドを前提としています)。
原因を特定するために私が経験した苦労をここでお話しするのはやめておこうと思います。BigNum がより大きなバッファ サイズに拡張される場合、元のバッファは解放される前にゼロ化されません。p の漏洩につながる制御フロー パスのチェーンは、さらに微妙です。最初の TLS ハンドシェイク中に、サーバーの鍵交換は秘密鍵で署名されます。CRT 署名はモジュロp演算を実行し、その結果、p <<BN_BITS2 が BN_CTX プールから割り当てられた一時変数に格納されます。その後の CRT フォールト インジェクション チェックで、その一時変数は val[0] として再利用されます (BN_CTX はスタックのように動作することを思い出してください)。興味深い点は、再割り当てされた一時変数では最下位ニブルのみがゼロ化され、 p <<BN_BITS2の場合は何も破壊されないことです。val[0]はすぐにモンゴメリ縮約された値を受け取りますが、元のバッファは新しい値を収容できないため、拡張され、pはヒープ領域を解放して取得を待機します。これはTLSハンドシェイクが発生するたびに発生するため、あらゆる場所に流出する可能性があります。
どのBigNumが静的に拡張されリークされる可能性があるかを特定するのは困難なため、OpenSSLをインストルメント化して少し実験してみました。リークポイントではpのモンゴメリ表現のシフト版も解放されることが判明しましたが、これはモンゴメリコンテキストが初期化される最初のRSA累乗演算時にのみ発生しました。この値は低位メモリアドレスに存在し、収集したパケットでは見つけることができませんでした。
OpenSSLチームは上記の漏洩について通知を受けています。ただし、公平を期すために言うと、OpenSSLは機密データのヒープへの漏洩を明示的に防止するように設計されていないため、これはそれ自体がセキュリティバグというわけではありません。
ルービン・シューは、ケンブリッジ大学コンピュータ研究所のセキュリティグループに所属する博士課程の学生です。彼の論文はモバイルセキュリティに関するものですが、暗号学にも関心を持っています。彼は、ウェブサイトの重要な情報源である秘密暗号鍵を盗むという壊滅的な脆弱性「Heartbleed」を悪用する公開チャレンジで優勝した4人のうちの1人です。この記事はLight Blue Touchpaperブログで最初に公開されました。シューは、有益なコメントと校正をしてくださったジョセフ・ボノー氏に感謝の意を表します。
リスト画像: Aurich Lawson / Thinkstock
39件のコメント