2019-07-02 (Tue) [長年日記]

_ IP ID によるカーネルアドレスのリーク (翻訳)

tedu flak の "random ip id comments" を勝手に翻訳してみました。リンク先の論文は一切見ていませんし、記事内容もすべて理解しているとは言えませんが、興味深い内容だったので。

以前の記事 "KARL"に関連しています。

ランダムな IP ID について一言

最近「IP ID をデバイスの ID、そして KASLR 回避に」という論文があり、気に入った。この論文が位置するのはネットワークと、古くても現役な標準規格と、乱数、セキュリティ、そして実装依存の挙動のすべてが交わった場所だ。どうか、何とかして原文を読んでほしい。ただ、本当に短くまとめると、著者たちは次の二つのことを成し遂げたと言える。彼らは Windows と Linux のネットワーク トラフィックから、ホスト固有の乱数シードをリバース エンジニア解析することにより、フィンガープリンティング (非匿名化) を可能にした。そして、さらに驚くことに、これを Linux の KASLR 突破にまで発展させた。ワイルドだろぉ?

ムカシ

IP ID は IP パケット内のフィールドの一つで、フラグメンテーション (断片化) を扱う。パケットが断片化されていると、受け手側ホストは、どの断片がどのパケットに属するかを知る必要がある。パケットを識別するときに使う IP アドレス (と、おそらくポートも) みたいなものだ。とはいえ、IP ID は 16 ビットしかないフィールドだから、衝突を避ける工夫は大切だ。さもないと、断片を正しく組み直せない。昔の、いちばん単純な方法では、単に断片化のたびにカウンタをインクリメントしていた。想定としては、カウンタがゼロに戻る頃には古い断片がすべて相手に届いているだろうということだ。

これは単純すぎたため、いくつかのワザを許してしまった。初期の論文に「NAT 下のホスト数を知るテクニック」があり、これはグローバルでリニアに増える IP ID を使ってホストを数えている。それより後の論文「TCP/IP フィールドの挙動を観察することによる NAT 下ホストの計数」は、これにもっと多くのフィールドを含めることで改良を加えた。最後に「現場での IP-ID 動作に対する詳細な観察」がある。これは各種の IP ID 生成技術を駆使してホスト数を測定した。

OpenBSD は乱数生成技術に後述のヒネリを加えて使っている。他のシステムではカウンタの亜種を使っているが、前述の検出テクニックその他の残念な結果にならないよう、単純なグローバル カウンタではなく、その接続に由来するオフセットを計算している。

アルゴ

論文において、IP ID 生成のアルゴリズムは三つ説明されている。グローバル カウンタ、ローカル オフセット付きのグローバル カウンタ、そしてルックバック付きの乱数だ。

最後のテクニックは Apple が使っているもので、最近使われた ID のキューを保持しつつ、新しい乱数を生成し、それが重複していないかチェックする。これにより問題のいくつかが解決される。元情報につながるグローバル カウンタやオフセットがなくなる。純粋な乱数アルゴリズムと異なり、重複の確率は減る。

OpenBSD は、Dragonfly を起源とするアルゴリズムを使って、この第三のアルゴリズムの亜種を実行している。存在しうる 64K 個の ID すべてを入れた配列があり、これはシャッフルされている。隣のアイテムを選んだら、それを 32K ほどオフセットしたあたりに混ぜ戻しておく。(訳注: 訳者が誤解しているかもしれないので知りたい人は https://github.com/openbsd/src/blob/master/sys/netinet/ip_id.c 参照) こうして、それほど早く再使用されないようにしているのだ。

デレズ

Klein と Pinkas は論文で、様々な接続から IP ID を取り出して、なんかすごい数学で元のグローバル カウンタを算出している。そうしたらまたあの、1999年みたいなパーティの始まりだ。(訳注: de-rez というのは映画 TRON の用語で de-resolve のこと、つまり分解消滅みたいな意味らしい)

ここでさらにまた興味深いのは、Linux で使っている計算の一部にはグローバル変数のアドレスが含まれており、それゆえにグローバル シードを計算すればカーネルのロード アドレスも分かってしまうということだ。

KASLR

ASLR には粗挽き vs 細挽き、それぞれの利点に関する議論がある。粗挽きなら、プログラム (やカーネル) のロード アドレスだけをランダマイズする。細挽きならプログラムを複数に分割し、それらをすべてランダマイズする。そうすれば攻撃するために当てる必要のあるアドレスが増えるからだ。しかし、ひとつリーク源があれば好きなだけ繰り返してアドレスを知ることができるのだから複雑にしても無意味だという意見もある。

今回のバグは、そういった意見に対して興味深い反論を提供する。ここでは一つのアドレスしかリークしないのだ。攻撃者がさらにパケットを送っても、さらに多くのアドレスを知ることはできない。

つまり、Android デバイスの種類が分かればカーネル レイアウトが分かるし、今回の IP ID derezzing テクを使えば、ロード アドレスまで分かってしまうということだが、一方で、同じカーネルでもデバイスごとに異なるリンク方法を使って、シンボルを異なるレイアウトに配置していたら、一つカーネル アドレスがリークしたところで大して役に立たないはずだった。

16bits

ちょっとした脚注として言っておくと、DNS も 16 bit ID で要求を識別している。

Posted 01 Jul 2019 01:23 by tedu Updated: 01 Jul 2019 01:23
本日のツッコミ(全1件) [ツッコミを入れる]
_ tamo (2019-07-16 (Tue) 11:24)

random は IP ID じゃなくて comments にかかってるのかもしれないな。comments が複数形なのに「一言」っていうのも気持ち悪いし。もうちょっとどうにかならなかったのか。


«前の日記(2018-12-12 (Wed)) 最新 次の日記(2019-07-15 (Mon))»