GHOST: glibc gethostbyname buffer overflow について

通称、GHOST と呼ばれるこの脆弱性は、JVN : glibc ライブラリにバッファオーバーフローの脆弱性 によると glibc ライブラリに存在する gethostbyname() などの関数を悪用し、バッファオーバーフローを発生させ、遠隔の第三者によって任意のコードを実行させたり、サービス運用妨害 (DoS) 攻撃が行われる可能性があるそうです。

Critical レベルなので、早速対応しましょう。

  • glibc 依存サービスリスト確認
  • Qualys より公開されているテストコード作成
  • 脆弱性確認用のテストコードをコンパイル
  • 脆弱性確認用のバイナリファイル実行し、脆弱性対象か確認
  • glibc アップデート
  • 脆弱性が直っていることを確認
  • 再起動

Step 1. glibc 依存サービスリスト確認

まずは、影響範囲を確認します。

glibc に依存しているサービスリストとバイナリファイルリストは、lsof で確認できます。

以下は、出力例であり、環境によって出力結果は、異なります。

glibc 依存サービスリスト確認Raw Code(S)Raw Code(T)
# lsof | grep libc | awk '{print $1}' | sort | uniq
acpid
agetty
awk
bash
crond
dhclient
grep
init
lsof
mingetty
mysqld
mysqld_sa
rsyslogd
sendmail
sort
sshd
su
udevd
uniq

lsof が入っていない場合には、以下を実行してインストールします。

# yum -y install lsof

Step 2. Qualys より公開されているテストコード作成

次に、Qualys Security Advisory CVE-2015-0235 が公開している脆弱性対象かどうかを確認するためのソースコードを作成します。

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define CANARY "in_the_coal_mine"

struct {
    char buffer[1024];
    char canary[sizeof(CANARY)];
}
temp = { "buffer", CANARY };

int main(void) {
    struct hostent resbuf;
    struct hostent *result;
    int herrno;
    int retval;

    /*** strlen (name) = size_needed - sizeof (*host_addr) - sizeof (*h_addr_ptrs) - 1; ***/
    size_t len = sizeof(temp.buffer) - 16*sizeof(unsigned char) - 2*sizeof(char *) - 1;
    char name[sizeof(temp.buffer)];
    memset(name, '0', len);
    name[len] = '\0';

    retval = gethostbyname_r(name, &resbuf, temp.buffer, sizeof(temp.buffer), &result, &herrno);

    if (strcmp(temp.canary, CANARY) != 0) {
        puts("vulnerable");
        exit(EXIT_SUCCESS);
    }
    if (retval == ERANGE) {
        puts("not vulnerable");
        exit(EXIT_SUCCESS);
    }
    puts("should not happen");
    exit(EXIT_FAILURE);
}

Step 3. 脆弱性確認用のテストコードをコンパイル

次に、gcc を使って上記のソースコードをコンパイルし、バイナリ実行ファイルを生成します。

ghost.c コンパイルRaw Code(S)Raw Code(T)
# gcc -o ghost ghost.c

# ls -l
-rwxr-xr-x  1 root root 8309  1月 28 23:58 2015 ghost
-rw-r--r--  1 root root  958  1月 28 23:58 2015 ghost.c

Step 4. 脆弱性確認用のバイナリファイル実行し、脆弱性対象か確認

生成されたバイナリ実行ファイルを実行し、脆弱性対象かどうかを確認します。

・ vulnerable : 脆弱性対象

・ not vulnerable : 脆弱性非対象

ghost バイナリファイル実行Raw Code(S)Raw Code(T)
# ./ghost
vulnerable

Step 5. glibc アップデート

ghost 実行結果、脆弱性対象であれば、glibc をアップデートします。

以下は、RHEL / CentOS の場合にアップデートする例です。

glibc アップデートRaw Code(S)Raw Code(T)
# rpm -qa | grep glibc
glibc-common-2.12-1.107.el6.x86_64
glibc-2.12-1.107.el6.x86_64
glibc-headers-2.12-1.107.el6.x86_64
glibc-devel-2.12-1.107.el6.x86_64

# yum update glibc

# rpm -qa | grep glibc
glibc-common-2.12-1.149.el6_6.5.x86_64
glibc-2.12-1.149.el6_6.5.x86_64
glibc-headers-2.12-1.149.el6_6.5.x86_64
glibc-devel-2.12-1.149.el6_6.5.x86_64

glibc アップデートが失敗する場合の対処

# yum update glibc

Loaded plugins: fastestmirror, security

Loading mirror speeds from cached hostfile

Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again

remi、epel などのリポジトリを無効化し、nss をアップデートしてからリトライしてみてください。

# yum --disablerepo=epel update nss

# yum update glibc

Step 6. 脆弱性が直っていることを確認

アップデートが終わったら再度 ghost バイナリファイルを実行し、脆弱性が直っていることを確認します。

ghost バイナリファイル実行Raw Code(S)Raw Code(T)
# ./ghost
not vulnerable

Step 7. 再起動

一番最初に確認した glibc に依存しているサービスと実行ファイルリストを参考にし、サービスは、再起動すればいいでしょうけど、sortuniq などの実行ファイルは、まだ問題のあるライブラリを掴んでいる可能性もあるので、万全を期すなら再起動するべきだと思います。

# shutdown -r now

以上、CVE-2015-0235 : glibc 脆弱性対策 でした。