2016-01-17 (Sun) [長年日記]

_ [obsd][sec]tedu の outrageous roaming fees の適当訳

翻訳は適当なので、ちゃんと原文を見てください。

海外で予想外の電話料金になってしまうのって最低ですよね。のんびり快適な旅行のつもりが、ガーン! 1メガバイト 20 ドル!? ちゃんと契約書を読んでおけばよかったですね。もちろん、契約書を読む程度の情報強者なら、海外ローミング料金のことも知っていて、契約書を読む必要もなかったでしょうけど。まあそんなもんですよ人生も ssh も。

えっ、ssh にローミングが関係あるのかって? ちゃんと書面を読んでおくべきでしたね。Qualys のセキュリティアドバイザリ (https://www.qualys.com/2016/01/14/cve-2016-0777-cve-2016-0778/openssh-cve-2016-0777-cve-2016-0778.txt ) は、完壁どころじゃない最高の出来栄えです。さて、アドバイザリを読んだ我々 (訳注: OpenBSD 開発者たち) は、どうすればいいのでしょうか。

最大のバグは (とりあえず二番目のオーバーフローのやつは無視して)、秘密データのメモリが再利用されて漏れたことです。これが起こる可能性は前から知られていますし、対策も用意されていますが、頭を使わずに対策されるようにはなっていません。

まず、stdio はバッファを free しても中身をクリアしません。その選択は理解できます。stdio は秘密じゃないデータにもたくさん使われますから、パフォーマンスが重要なのですよね。あれ? そうかな。ファイルを閉じたりバッファを解放するのって、おそらく速度を稼ぐ必要のある場所ではありません。じゃあ、もうちょっときれいに掃除してもいいかもしれませんね。あるいは glibc のように mmap/munmap を使うか。やる価値はあるかもしれませんが、私は libc のサブシステムがそれぞれ独自のミニ malloc を開発するのを見たいとは思いません。今でも結構な数があって、それぞれにクセやバグがあるんです。

一段低レベルの話。free 自体はもう既定で (5.6 から) 冒頭 2k をクリアしています。これは別種の use-after-free バグに対する緩和策として設計されましたので、私としては、大きなバッファを毎回クリアするのはパフォーマンス低下に見合うほどの価値がないと見なしました。この検討過程で、バッファ内のデータとしても、ほとんどの鍵は 2048 バイトより小さいことを確認しました。

私の実験では、既定の動作で十分に鍵の暴露を防げるはずでした。どうやって Qualys が 5.8 で鍵をリークさせたのか、私はよくわかっていません。stdio バッファの中身を fclose の前と後で出力させるよう ssh にセットして中に鍵データがないことを確認したのですが、あまり時間がなかったので、今度は exploit を使ってもっと時間をかける必要がありますね。

OpenBSD の free には、攻撃者がデータの「お手入れ」をしにくくするよう邪魔するランダム化機能もいくつかありますが、その多くは小さめのチャンクのほうが効果を発揮するものです。free ページリストの挙動は今でもほぼ予測可能です。それでももちろん、攻撃者に一撃のチャンスしかないのか無限に試行できるのかによって事情は異なります。roaming バグの悪用は (訳注: 「connection suspended, press return to resume」と表示されるので) ごちゃごちゃ表示されますが、おそらく気付かれずに消えますよね? (訳注: ssh に ls をパイプしたりする例が Qualys の Mitigating Factors のところにある)

一段レベルを上げます。ssh は鍵の読み取りに stdio を使わないようにすべきか? 独自にメモリを mmap してそこに読み出すか? という問題、それをやれば分離はできますが、ちょっと私にはわかりません。Heartbleed の後に Akamai が同じようなことを提案していましたが、ちゃんとしたものになるまで何度か試行錯誤が必要でしたし、stdio の再発明は新しいバグを招き入れる良い方法でもありますから。使っている道具が信頼できないなら、もっと良い道具か何かを入手しましょう。余談ですが signify は stdio を使っていません。それが先見の明によるものだとは言えませんけどね。

ssh のあちらこちらに explicit_bzero を振りかけてまわった苦労が実際に功を奏して、潜在的な exploit vector をひとつつぶしていたのは嬉しいことです。それで、いつまでたってもどこか (stdio) にリークがあるように思える一方で、ふさぎ続けていれば全部ふさげるかもしれない、とも思えます。

メモリ統合の緩和策に関して (訳注: 断片化したリーク情報から鍵を再構成しにくくすることか?) は、よくやっていると考えています。バグをその正体がわからないうちに防ぐのは大変なことですし、チップが思ったとおりにランドしないことだってありますから (訳注: IC を乗せる余地がないという意味??)。確かに、stdio の中で何が起こっているかを非常に注意深く検討する必要はあるでしょう。何か変更を加える前にまず exploit を再現させる必要がありますけれども。

今回のリークは ssh-agent を使っていれば緩和できるものでした。その場合には暗号化された鍵しか漏れないからです。ひとつ思いついたのは、ssh が常に小さな agent を起動して暗号化された鍵を処理させ、メインプロセスでリークがあっても何も外に出ないようにできるのでは、というアイディアです。権限分離は残念ながらリモートからのコード実行による影響の軽減に重きを置いており、他の種類のバグを見過ごしてきました。

どちらかを選ばなければいけないとしたら、自分の実験的機能で情報漏れが起こるなら認証前のサーバサイドよりも認証後のクライアントサイドにあってほしいと言うしかありませんが、頭の悪い実験を減らすという選択肢があれば大喜びでそちらにします (訳注: 利用者の少ない機能やプログラムを削除することを「tedu する」と呼ぶほど、筆者は OpenBSD 開発者たちにコード断捨離の人として知られている)。とは言うものの、ローミングは、完成していれば皆に便利がられる機能だったでしょうね。mosh ユーザも何人か改宗させることができたでしょうに。

あと気に入ったのは、ssh が git で開発されればバグがなくなるだろうという提案です。

ところで、念のために鍵を更新しておこうという方もそうでない方も、そろそろ暗号化された鍵のパスワードクラックに対して大幅に改善された防御を提供する新しい秘密鍵フォーマット (http://www.tedunangst.com/flak/post/new-openssh-key-format-and-bcrypt-pbkdf ) の利用を今一度考慮してみてはいかがでしょうか。


«前の日記(2015-11-22 (Sun)) 最新