どさにっき IoT 〜2016年2月中旬〜

by やまや
<< = >>

2016年2月19日(金)

CVE-2015-7547

_ glibc の getaddrinfo() にリモートから任意コード実行の穴とな。

_ JPRS からの重複に、

   glibcの名前解決ライブラリでは、512バイトを超える応答をUDPで取り扱う
   ための拡張機能であるEDNS0がデフォルトで有効にされておらず、通常の場
   合クライアントがフルリゾルバー(キャッシュDNSサーバー)から512バイ
   トを超えるDNS応答をUDPで受け取ることはありません(*1)。

   (*1)対象となる機器の/etc/resolv.confでoptions edns0が設定されてい
         た場合、削除またはコメントアウトする必要があります
とあるんだけど、うーん。以下、Linux で options edns0 を有効にした状態のクエリのパケットキャプチャ。
12:52:31.163096 IP 127.0.0.1.47948 > 127.0.0.1.53: 46243+ [1au] AAAA? www.google.com. (43)
        0x0000:  4500 0047 e58d 4000 4011 0119 a9fe 0002  E..G..@.@.......
        0x0010:  a9fe 0001 bb4c 0035 0033 5444 b4a3 0100  .....L.5.3TD....
        0x0020:  0001 0000 0000 0001 0377 7777 0667 6f6f  .........www.goo
        0x0030:  676c 6503 636f 6d00 001c 0001 0000 2904  gle.com.......).
        0x0040:  0000 0000 0000 00
0x003d からの2バイト(0x0029)が TYPE OPT、ちょっと離れた 0x0042 の 0x00 がバージョンで、合わせて EDNS0 を意味する。この間にある 0x003f からの2バイト(0x0400 == 1024) が UDP のペイロードサイズ。ちうことで、glibc は options edns0 を設定した状態でも EDNS0 の最大サイズは 1024 バイトなんだよね。実際に大きな応答を返す名前を聞いてみると、edns0 が有効でも1KB以上は TCP にフォールバックするのが観察できる。NetBSD はちょっと前までこのサイズが 0x0000 になっていてなんだそりゃ、ってのが 以前見つけたバグ(今は修正済み)。FreeBSD や修正後の NetBSD のように 65535 バイトまでおっけー、というクエリを投げるのであれば、options edns0 をはずせ、という指摘は意味があるんだけど、もともと 1024 バイト上限の glibc では、options edns0 があろうとなかろうと今回の穴を踏むような 2048 バイト以上の応答を UDP で受けることはないんじゃないかなぁ。もちろん、このサイズを無視して巨大な応答を返すような腐ったキャッシュサーバ(そんなものが実在するかどうかは知らん)を使ってたり、信頼できない経路から偽造応答を注入されたりすればその限りではないけど、それは option edns0 の有無に関係ないことだし。

_ もひとつ。

   (*3)フルリゾルバー/権威DNSサーバーにおけるメッセージバッファサイ
         ズの設定、例えばBINDのmax-udp-sizeやedns-udp-sizeはUDPの応答
         サイズのみを変更するものであり、TCPの応答サイズには影響を及ぼ
         しません。また、Unboundではmsg-buffer-sizeオプションでUDP/TCP
         双方のメッセージバッファサイズを設定できますが、設定可能な最
         小値は4096となっており、本脆弱性の影響軽減策とはなりません。
ということで、unbound の msg-buffer-size に 4096 より小さい値を指定できるようにするパッチ。
--- util/configparser.y.orig    2014-08-05 16:57:52.000000000 +0900
+++ util/configparser.y 2016-02-18 19:10:48.537437043 +0900
@@ -635,8 +635,6 @@
                OUTYY(("P(server_msg_buffer_size:%s)\n", $2));
                if(atoi($2) == 0)
                        yyerror("number expected");
-               else if (atoi($2) < 4096)
-                       yyerror("message buffer size too small (use 4096)");
                else cfg_parser->cfg->msg_buffer_size = atoi($2);
                free($2);
        }
で、パッチ対象のファイル名をからもわかるとおり、値をチェックしてるのは設定ファイルの parser の中なので、ここを通らないように設定をいじってやれば修正なしでいけるんじゃね、と、試しにパッチなし設定変更なしの unbound を起動してから
# unbound-control set_option msg-buffer-size: 1024
と叩いてみたところ、エラーにはならず get_option でもちゃんと 1024 が戻ってくるんだけど、残念ながら実際の挙動は変わらずふつーにデカい応答が返ってきた。どうも初期化時のみ参照される値で、起動後の変更はムリっぽい。なお、msg-buffer-size はクライアントに返す応答の上限サイズであるだけでなく、権威サーバから受け取る応答の上限でもあるので、あまり小さくすると名前解決できないドメインが出てきて、事実上使いものにならなくなるので注意。


<< = >>
やまや