MS11-083(CVE-2011-2013)の実証コードを試してみた

2011年11月、Microsoftから修正プログラムMS11-083が提供されました。MS11-083が公開された当初、MS11-083で修正されたCVE-2011-2013は、オープンしていないUDPポートにパケットを送信することで悪用できることから気になりました。しかし、その脆弱性の公表からしばらく経つと、「2^32だけUDPパケットを送信する必要がある」とか「脆弱性の悪用まで52日かかる*1」などの情報がでてきました。その後、実証コードがリリースされたことから、「実際にどんなものか」と思い、試してみました。

実証結果

5 日間と 10 時間、実証コードを実行し続けましたが、DoS 状態(ここでは Blue Screen of Death を想定)が再現しませんでした。ですが、実証コードを実行し続ける間、Victim には負荷がかかり続けます。またExploit Shopのブログ記事で書かれている Step1 から Step3 までを 2 回試みましたが、DoS 状態が再現しませんでした。

実証結果からの感想

僕の実証環境では、2^32 だけ UDP パケットを送信すること自体、1日弱で達成できました(「netstat -s -p udp」の結果から判断)。ただ、UDP クローズポートのパケット受信数が 0 に wrap around したときに、ICMP ECHO REQUEST を Victim に送り込むのは相当難しいと感じます。実証コードでは、何度も何度も wrap around させて、そのタイミングを狙えるように、250 スレッドで UDP パケットを送り続けると同時に ICMP ECHO REQUEST を送るよう書かれていると理解しました。


以降、実証環境、実証手順および実証時の Victim の様子をまとめます。興味がある方はどうぞ。

実証環境

実証環境は下図の通りです。Attacker で実証コードを実行して、Victim の 80/udp に対してパケットを送信しました。

実証コードには、PacketStorm で公開されている こちらを使用しました。シェルスクリプトで書かれているため、まず実行して winnuke2011, ping.sh を作成し、実際には winnuke2011 を実行することとしました。この日記で特に補足なく「実証コード」と書いた場合、この winnuke2011 を指します。

./winnuke2011 192.168.0.102 80

実証手順

実証コードを使って、「実証コードを実行し続けるだけの実証」(実証1)と「脆弱性が再現すると思われる状況を意図的に作る実証」(実証2)の 2 通りを実施しました。
最初は実証1だけ実施していましたが、「netstat -s -p udp」により Victim が受信したクローズポート宛の UDP パケット数を観測できそうだった*2ので、実証2も試してみました。

実証1:実証コードを実行し続ける

まず試しに Attacker で実証コードを実行して、Victim で tshark を使い 1 秒間に受信できた UDP パケット数を確認しました。この確認の結果、1 秒間に受信できた(tshark でパケットキャプチャできた)UDP パケット数は、約 10,000 程度でした。この値を基に、Exploit Shopのブログ記事 の Step1 に該当する INT_MAX(4294967295)に達するまで、単純に計算して、約 5 日間程度かかると概算しました。この概算は、あくまで tshark で取得できたパケット数に基づいているため、参考程度にしかなりませんでしたが。

あとは、実証コードを実行するだけです。2011年11月14日(月) 0時過ぎに実証コードを実行して、2011年11月20日(日) 10時40分頃まで実行し続けました。結果、Victim が DoS 状態となることはありませんでした。約 5 日間と 10 時間、実証コードを実行しても再現に成功しなかったことになります。

実証2:脆弱性が再現すると思われる状況を意図的に作る

この実証では、Exploit Shopのブログ記事の Step1 から Step3 の手順を実行しました。具体的には次の手順を実施します。

  1. netstat -s -p udp」出力結果の「ポートなし」を適宜確認しながら、実証コードで INT_MAX(4294967295) 近くまでパケットを送信する。その値が INT_MAX(4294967295)に近づいたら、実証コードを停止する。
  2. INT_MAX(4294967295)+1 となる残りのパケット数だけ、「hping3」コマンドで UDP パケットを送信する*3
  3. netstat -s -p udp」出力結果の「ポートなし」が 0 に wrap around したことを確認して、「ping」コマンドで ICMP ECHO REQUEST を送信する。

上記手順1 が完了するまで大体 1日と1,2時間程度かかりました。手順3 を実行するときの「netstat -s -p udp」出力結果は、下図の通りです。

上記手順1から手順3までを 2 回実施してみましたが、Victim が DoS 状態となることはなく、そのまま動作していました。Microsoft TechNet Blog の記事によると、この動作もあり得るシナリオになります。この実証手順が正しいか疑問もありますが--;

実証時の Victim の様子

実証コードを実行しているとき、Victim では CPU 使用率が定常的に高くなりました。下図は、実証コード実行中の Victim における「Process Explorer」のスクリーンショットです。きちんと確認していないため断言できませんが、ネットワークインターフェイスのドライバ周りの処理に負荷がかかっているとと理解しています(関連:Wikipedia:デバイスドライバ)。

*1:PacketStorm で公開された実証コードのコメントに書かれています。

*2:Microsoftnetstat の説明には、「netstat -s -p udp」の具体的な説明がありませんでしたが、80/udp にパケットを送信していると、「ポートなし」の値が増加していったので妥当と判断しました。

*3:例えば、859108 パケットだと「hping3 -c 859108 --faster --udp --destport 80 192.168.0.102」。