読者です 読者をやめる 読者になる 読者になる

タオルケット体操

サツバツいんたーねっと

GHOST脆弱性の問題を緩和する要素について( GHOST脆弱性勧告書の一部を翻訳)

つい数時間前に存在を知りました。

某ニュースサイトとかで「マジやべえ今すぐ対処しないと死ぬぞ」みたいなことを書かれていたので超焦っていたのですが、かくかくしかじかの理由で独自パッチの作成を検討するために https://www.qualys.com/research/security-advisories/GHOST-CVE-2015-0235.txt の報告書を読んでいたところ、そこまで超ヤバい急ぎの要件でもなくね? みたいな感じになったので共有します。

なお、私の英語力がヤムチャレベルであること、ネットワークやLinuxシステムに関わる知識がチャオズレベルであること、急ぎの翻訳なので他の節はほとんど読めていないこと、あくまで2014年1月28日時点での情報であること、などの理由から誤解、誤訳が含まれている可能性があります。
参照するのはあくまで元の報告書をベースにして、あとは自己責任でよろしくお願いします。なお公開していることで悪影響があるような誤訳、誤解は随時修正していくつもりなので間違いはバンバン指摘してもらえるとありがたいです。

以下、"GHOST: glibc gethostbyname buffer overflow"の"3 - Mitigating factors"の節の翻訳です。

ChangeLog

  • id:miau氏による誤訳への指摘の対処 2015/1/28 18:02

  • 脆弱性の原因そのものへの補足を追加 2015/1/28 18:02

3 - 問題を緩和する要素

このバグの影響は、以下の理由で大幅に軽減されます。

理由:

  • 2013年5月21日時点でパッチがすでに存在している(2013年8月12日にリリースされたglibc-2.18)。そしてそのパッチはすでに2013年の8月12日の適用以降から、テスト(ユーザに利用)されているということ。
       [BZ #15014]
       * nss/getXXbyYY_r.c (INTERNAL (REENTRANT_NAME))
       [HANDLE_DIGITS_DOTS]: Set any_service when digits-dots parsing was
       successful.
       * nss/digits_dots.c (__nss_hostname_digits_dots): Remove
       redundant variable declarations and reallocation of buffer when
       parsing as IPv6 address.  Always set NSS status when called from
       reentrant functions.  Use NETDB_INTERNAL instead of TRY_AGAIN when
       buffer too small.  Correct computation of needed size.
       * nss/Makefile (tests): Add test-digits-dots.
       * nss/test-digits-dots.c: New test.
  • IPv6アドレスの出現によって、gethostbyname*() 関数はすでに非推奨です。
    最近のアプリケーションは、getaddrinfo()を代わりに使用しています。

  • ローカル到達可能な多くのプログラム、特にSUIDバイナリですが、gethostbyname()はinet_aton()が失敗した場合にだけ予備的に呼ばれます。
    しかしながら、バッファオーバーフロー(訳注: 今回の脆弱性の引き金)を引き起こすためには、(__nss_hostname_digits_dots内部で呼ばれている)inet_atonを成功("inet-aton requirement(訳注: 第2節を参照)"を満たす)必要があります。
    これは不可能です。したがってこれらのプログラムは、安全です。

  • リモートから到達可能な他のプログラムのほとんど、特にサーバーですが、forward-comfirmedな逆引きDNS(FCrDNS: "full-circle reverse DNS" として知られる)を実行するためにgethostbyname()を使っています。
    これらのプログラムは基本的に安全です。何故なら、このgethostbyname()に渡されたホスト名は、通常DNSのソフトウェアによって事前に値をチェックされているからです。

    • 『ラベル(訳注: ドメインのピリオドで区切られた部分)の文字列は、63の8ビットオクテットで構成され、最大長255バイトでなければいけない。また、それぞれはドット(ピリオド)で区切られていなければならない』
      上記の条件を"1-KB制限"を満たしつつ達成するのは不可能です。

    • 実際には、glibcDNSリゾルバは(おおむね)1025文字(ビット列のラベル、または非印刷可能文字の場合)までのホスト名を生成できます。
      しかしながら、バックスラッシュ('\')を挿入する必要があります。そしてこれと『数値とドットで構成される』という条件を同時に満たすことは不可能です。

というような感じです。

もちろん重大な脆弱性であることは事実であるとおもいますが、現状としてはそれを突くのが難しいといった形で、ある程度の余裕をもって対処出来るかなとおもいました。

補足

  • そもそも脆弱性が見つかった関数

    nss/digits_dot.cにある__nss_hostname_digits_dots()という関数。

  • "inet-aton requirement" とは

    抜粋です。ちゃんと理解するためには"2 Analysis"の全文を読んだ方がいいっぽいです。

    • 「数値とドットで構成された」ホストネームをinet_pton()でIPv6としてパースすることは不可能です。
      したがって、もしもIPアドレスファミリーがAF_INET6だった場合は、gethostbyname2()gethostbyname2_r()を使ってオーバーフロー脆弱性を突くのは不可能です。

    • Conclusion: inet_aton() is the only option, and the hostname must have one of the following forms: "a.b.c.d", "a.b.c", "a.b", or "a", where a, b, c, d must be unsigned integers, at most 0xfffffffful, converted successfully (ie, no integer overflow) by strtoul() in decimal or octal (but not hexadecimal, because 'x' and 'X' are forbidden).