仙豆のレシピ

ちょっとしたことでも書いていく姿勢で

第1フラグメント便乗攻撃を(僕が)成功させられない理由

以前、第1フラグメント便乗攻撃についてのエントリを書きましたが、そのエントリではUDPチェックサムをうまくあわせることができず最終的に毒入れを成功させることができませんでした。その後いろいろアドバイスをいただいたりしてチェックサムをあわせようと努力しましたが、(僕程度のレベルでは)やっぱり無理 or 超難しくね…?という結論に達したので、その辺のことを書いておきたいと思います。

(2014/5/7)場合によっては攻撃が成功しやすくなる可能性があることがわかったので追記しました。

問題整理

そもそもなにがうまくいかないのかを整理。

第1フラグメント便乗攻撃ではDNS応答の第2フラグメントを偽装しますが、その第2フラグメントのペイロードはどんなものでもいいわけではなく第1フラグメントのUDPヘッダ内のチェックサムと整合性がとれている必要があります。このため、偽装する第2フラグメントのペイロードチェックサムを本来の第2フラグメントのペイロードチェックサムと一致させる必要がありますが、ポート番号がランダマイズされているためなのかチェックサムの値が毎回微妙に変わってしまいうまく合わせられないのが問題です。

f:id:senz:20140506002156p:plain
チェックサムがあっていないとWiresharkに怒られている図

チェックサムが合わない理由?

はじめはポートがランダマイズされてるからチェックサムが変わると思っていましたが、アドバイスをいただいてよく考えてみた結果別に第2フラグメントにポート番号関係ないやんということに気がつきました。

以下はペイロードのイメージ図です。かなりアバウトです。これでなにかが伝わるかはわかりませんが未来の自分には伝わるはず…
f:id:senz:20140506011119p:plain

しかし、何度も試してみると毎回第2フラグメントのペイロードチェックサムの値が異なっているので、なにかがランダムに変化している…と仮定して調べてみました。

チェックサムが合わない理由

調べた結果、いちおう原因らしきものに突き当たりました。それは返ってくるレコードの順番がばらばらということです。

今回の環境では.kmbの権威サーバに.sonya.kmbを問い合わせ、その応答がns0.sonya.kmb~ns9.sonya.kmbのAレコードとAAAAレコードであるために大きくなりフラグメントされることを利用して毒入れを試みるのですが、その応答が0から順番ではないです。すなわち、以下のようになります。

f:id:senz:20140506020759p:plain

これがランダムだとなぜうまくいかないかを説明するには、あと2つの事項を説明しなくてはなりません。

1つ目は応答がフラグメントによって分割される位置です。

f:id:senz:20140506021524p:plain

若干見づらいですが、Additional sectionの途中で分割されています。これは意図的ではなくたまたまです。

2つ目はAdditional sectionの記述の方法です。DNS応答を手書きしたことのある人なら誰でも知っていると思いますが、パケット内ではサーバ名を、1度目は普通に記述しますが2度目は1度目の部分を参照します。(詳しい説明

以下はDNS応答のパケットの一部です。一度目のAuthority部分ではサーバ名が記述されているのに対し二度目となるAdditional部分では一度目の部分を参照しています。(赤字部分)参照の記述ルールは上のリンクをたどれば書いてありますが、まああるルールに則って場所を指定しているだけです。
f:id:senz:20140506030451p:plain

これらの知識を組み合わせると、なぜ毎回第2フラグメントのチェックサムの値が変わったかが説明できます。それは、サーバ名を参照している部分の一部分しか第2フラグメントに含まれていない+参照先がランダムであるからです。すなわち上図の赤字部分が毎回変わってしまうことによって第2フラグメントが毎回変わってしまうということです。

攻撃を成功させるために

とはいえなんとか攻撃を成功させたいので(攻撃者視点)、いろいろ考えてみました。

まず、チェックサムとは総和であるので上図の赤字部分が変わろうと第2フラグメントにAdditional部分がすべて含まれれば問題ないのでは、と考えました。そのために、攻撃の前段階で行うICMP too Bigの偽装でnext MTUの値を(552以上の)任意の値に変えられることを利用してAuthority部分がちょうど終わるような部分でフラグメントされるように調整してみました。

そのために.kmbのゾーンファイルにns10.sonya.kmb~ns16.sonya.kmbを追加することでAuthority部分を増やし、MTUの値を微調整してみたのですが…

以下はDNS応答の一部です。オレンジ色の部分が第1フラグメント、その下が第2フラグメントです。

MTUが小さい場合↓
f:id:senz:20140506165358p:plain
第1パケットにAuthority部分がすべて入っていません。なのでMTUを少し大きくしてみます。

f:id:senz:20140506165448p:plain
今度は第1フラグメントにAdditional部分が3byte入ってしまっています。しかし、どうMTUを微調整してもぴったりにならなかったので、しょうがなく.kmbのゾーンファイルのns16.sonya.kmbをns16aaa.sonya.kmbと3byte増やしてみました。

f:id:senz:20140506165737p:plain
ぴったりになってる!これで第2フラグメント全体のチェックサムのゆれがなくなって、毒入れが成功するのでは?!

…と思ったのですが、何度か試してみたところ前部分を参照する値が毎回微妙に違いました。なぜなのか考えてみましたが、おそらく.sonya.kmbの前のns*の文字数がすべて同じではないからではないかと思いました。この部分が3バイトのものと4バイトのものの順番が入り乱れることによって参照先の位置がゆれてしまうという。

それならと、次はns00~ns16と文字数を合わせてみましたが、やはりMTUの調整だけではぴったりにならず(1バイト足りなかった)。この辺で「ちょうどぴったりになる状況なんて実際にはほとんどねえよ!!!」という感じに心が折れたのでした。

結論

いちおう理論上では

  • DNS応答のAuthority部分(もしくはAnswer部分)が十分に大きい
  • そこに含まれる文字数がすべて同じ(今回だとns*.sonya.kmbの文字数)
  • MTUの調節でちょうどいい部分でフラグメントさせることができる

のすべてを満たす環境があれば毒入れが可能であるという気がしますが、未検証です。とにかく、第2フラグメントのペイロードチェックサムが毎回変わらないようにしなくては偽装第2フラグメントのチェックサムも決めることができないので攻撃できないと思います。

なんか深みにはまりすぎて必要以上に難しく考えてないことを祈る。

<2014/5/7追記>
帰ってくるレコードの順番(RRsetというらしい)をランダムではなくすオプションがあるらしいです。
また、ランダムにする機能がデフォルトでついたのはBIND9.9からなのでそれより前のバージョンを使っているとランダムにならないそうです。

もしランダムではないと、とてもありがたいです(攻撃者視点)。ランダムでない場合結論であげた攻撃を成功させるための3つの条件のうち2つ目と3つ目は関係なくなる気がします。この弱い頭で脳内シミュレーションしてみただけなので正しいかわかりませんが。

とにかく少しでも攻撃されるリスクを減らすため、

  • RRsetがランダムになるのを無効にするオプションを設定するのをやめる
  • 古いバージョンのBINDを使わない

をしたほうがよいと思います。

情報提供ありがとうございました。

意見・ご指摘あったらお願いします→@senz1024(↓もしくはコメント)