ニュースサイトを見ていたらglibcのGHOSTと呼ばれる脆弱性について盛り上がっていました。
Table of Contents
1 CVE-2015-0235の概要
gethostbyname_r関数にバッファオーバフローの脆弱性があり、DOSを引き起こされたり、リモートで不正なコードを実行される場合があります。
2013年に修正パッチが取り込まれたようですが、重要な修正であることが周知されておらず、加えてglibcはいくつかのメジャーバージョンが並走している状態であり、多くのバージョンに修正が取り込まれていなかったようです。
2 gethostbyname_rのインターフェース
nameで与えた名前を基に、hostent構造体にIPアドレス等のサーバ情報を格納します。bufは作業用領域として使われるようです。
int gethostbyname_r(const char *name,
struct hostent *ret, char *buf, size_t buflen,
struct hostent **result, int *h_errnop);
本脆弱性は不正なnameを与えることで、bufの領域をバッファオーバフローするものです。
以下はgethostbyname_rを用いた、コマンドライン引数で与えられたサーバ名からIPアドレスを出力するプログラムです。
コメントにも記載しておりますが、gethostbynameは古いものであり、getnameinfoを使う方が良いみたいです。
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
int main(int argc, char *argv[])
{
static char buffer[BUFSIZ];
struct hostent ret, *result;
struct in_addr addr;
int retval, error;
if (argc != 2) {
fprintf(stderr, "usage: %s [Hostname]\n", argv[0]);
return 1;
}
memset(buffer, 0, sizeof(buffer));
/**
* NOTE: Man's DESCRIPTION
* The gethostbyname*() and gethostbyaddr*() functions are obso‐
* lete. Applications should use getaddrinfo(3) and getname‐
* info(3) instead.
*/
retval = gethostbyname_r(argv[1], &ret, buffer, sizeof(buffer),
&result, &error);
if (retval != 0 || result == NULL) {
perror(argv[1]);
return 1;
}
memcpy(&addr, ret.h_addr_list[0], sizeof(addr));
printf("%s: %s\n", argv[1], inet_ntoa(addr));
return 0;
}
実行すると以下の結果が得られます。
./a.out localhost localhost: 127.0.0.1
bufのサイズを1とかにすると下記のエラーが発生します。
./a.out localhost localhost: Numerical result out of range
3 CVE-2015-0235の確認方法
作業用領域の後ろに文字列を格納しておき、不正なnameを用いてgethostbyname_rを呼び出した後に文字列が書き換わってないかを確認するプログラムが公開されています。
wget https://webshare.uchicago.edu/orgs/ITServices/itsec/Downloads/GHOST.c gcc GHOST.c ./a.out vulnerable # or not vulnerable
4 まとめ
各ディストリですでにセキュリティアップデートが公開されております。
glibcはほぼ確実に使われるパッケージである為、ニュースサイト等で取り上げられるのもいたしかたなしかと思います。
glibcの開発コミュニティで2013年の修正パッチを反映するのにタイムラグがあった点を今後どうしていくのかが気になる点です。