Arbitrary File Overwrite via Core Files(@stake)の意味を解りやすく解説してみる試み

先日来話題になっている、APPLE-SA-2003-10-28 Mac OS X 10.3 Panther(古暮さんによる翻訳:[harden-mac:0515] [security-announce] APPLE-SA-2003-10-28 Mac OS X 10.3 Panther)で書かれているMac OS X 10.2.8以前ではまだ修正されていない脆弱性の内の一つ、@stakeの報告による Arbitrary File Overwrite via Core Files について、できるだけ解りやすく解説してみる。
# 少々のつもりが超長文になってしまったが。
# 文体が変だけど、自分に説明するつもりで書いてたらこうなったので、そのまま上げてみます。



この脆弱性に関して、id:t_traceさんは『ベンダーによる 脆弱性 報告ルール無視』の中で

プロセスクラッシュが発生した場合に作成されるコアファイルをリモートログインなどで読まれる可能性がある。

と言っている。私には、この文面は「リモートログインしたユーザがコアファイルを直接読む可能性がある」と言っているように読める。実際id:t_traceさんが直接のつもりで書いてるのか間接のつもりで書いてるのかは解らないけれど。でも、この一文を予備知識なしで読むとそう読めそうだよね。私も最初SAをつらっと読んだ時に単純に「あぁcoreが読めちゃうの? それマズイでしょ」と思ってただけだったし。



それから、塚本牧生さんが『Mac OS X 10.2.8はどう危険なのか?Remake。』で述べている一文を取り上げると、

問題点(1)は、Unixがソフトウェアの異常を検知し強制終了させる際にその時の状況を追跡する手がかりとして作成させるcoreファイルに問題があるというものだった。

と、core自体に問題があるように書かれている。



実はこの脆弱性、coreを直接読まれる可能性とかcore自体の問題とかそういうことを言っているんじゃないみたいなんですね。
もしかしたらお二人はとっくに理解してて、でも読者に解り易くするためにそう書いてるのかも知れないけど、他の方の為に、以下にこの脆弱性って実はこうなんだってのをきちんと書いてみることにする。まぁ結局はcoreが読まれちゃうって話ではあるんですが。



先に言ってしまうと、このAdvisoryで指摘されているMac OS X 10.2.8以前の脆弱性というか欠陥は、噛み砕いてまとめると以下の2点。

  • coreが吐かれる場所が /cores に決まっており、/coresのパーミッションはworld writableつまりdrwxrwxrwt=1777*1で、誰でも読み書きできてしまう。
  • 吐かれるcoreは、必ずパーミッションが0400で、名前が「core.プロセスID」というルールで生成される。
     (0400であることはあまり問題ではない。問題なのは名前の生成規則が推測できるということ)

後者によれば、パーミッションを考えればcoreはrootしか読めないことになる。つまり先にroot権限を奪取してない限りはcoreを直接読むことはできない。
だからt_traceさんの文面やAdvisoryやニュースサイトの記事なんかを読んで、直接coreが読めると思った人は間違い。
でもこのAdvisoryでは「読める」と言っている。なんでだろう??? ちなみにroot権限なんて奪取する必要もない。



さてまずは、今、私のマシンの/coresを見てみよう。

$ ls -l
total 1267240
­r--------  1 root  wheel  70463488 Sep 25 10:46 core.452
­r--------  1 root  wheel  70492160 Sep 10 13:52 core.464
­r--------  1 root  wheel  67051520 Aug  6 21:09 core.467
­r--------  1 root  wheel  71614464 Oct 31 18:28 core.470
­r--------  1 root  wheel  39133184 Sep  8 22:27 core.479
­r--------  1 root  wheel  70475776 Sep  1 09:30 core.483
­r--------  1 root  wheel  75755520 Oct 20 16:35 core.486
­r--------  1 root  wheel  39141376 Sep  8 15:29 core.488
­r--------  1 root  wheel  72372224 Oct 28 09:49 core.489
­r--------  1 root  wheel  72327168 Sep 30 10:10 core.500

こんなにcoreがある。
実は知らなかったんだけど(笑 coreを吐くように設定したつもりも無かったので。まぁこれについては後述。



core.452 という名のcoreがあるね。ってことは、過去にプロセスID 452のプロセスがcoreを吐いたことがあるってこと。coreの命名規則から言えば。
じゃぁ、仮にまだそのプロセスが同じPID 452で動いていたとしたらどうだろう? もう一回coreを吐いたとしたら?
そう。/cores/core.452 がまた生成される。同じ名前で上書かれてしまうんだね。名前の生成規則が決まってるから。上で2点にまとめたのの後者の方だね。


じゃぁ、/cores/core.452を一度削除して、/cores の中に以下の様なシンボリックリンクを作っておいたらどうだろう?

$ ln -s /cores/core.452 /Users/hehehe/PID-452-no-core

/cores はパーミッションが1777だから一般ユーザで書き込みできる。つまり勝手に一般ユーザがシンボリックリンクを置くことができてしまうんだね。シンボリックリンクのターゲットももちろん(許される場所であれば)自分の好きなとこに好きな名前で置ける。これは、上でまとめたのの前者の方に起因する。

この状態で、/Users/hehehe/PID-452-no-core を見ても何も無い。

$ cat /Users/hehehe/PID-452-no-core
cat: /Users/hehehe/PID-452-no-core: No such file or directory

当たり前だね。/cores/core.452ってファイルはまだ存在しないんだから。そう。まだ、ね。



ここまで来れば解る人も多いと思うけど、この状態で、もう一回 PID 452 のプロセスがcoreを吐いたらどうなるか?
上で書いたように/cores/core.452と以前と同じ名前でcoreが生成されるね。

でも、予め hehehe ってユーザの PID-452-no-core ってファイルにシンボリックリンクが張ってあるから、/cores/core.452 と /Users/hehehe/PID-452-no-core は同じ内容になる。
だから、heheheさんは、自分のホームディレクトリにあるPID-452-no-coreを読めば、本来なら0400のパーミッションによりrootしか読めないはずのcore.452を労せず読めちゃうってことになる。
まぁ言ってみれば、中身が無かったはずのPID-452-no-coreは/cores/core.452と同じ内容として上書きされちゃう感じだね。



試しに、以下の様にしてみれば、シンボリックリンクがcoreで上書きされリンクのターゲットのを見ると上書きされた内容が見れる、というのが解ると思う。

$ ln -s /cores/core.452 ~/PID-452-no-core
$ cat ~/PID-452-no-core 
cat: /Users/hehehe/PID-452-no-core: No such file or directory
$ sudo echo "Can you see me?" > /cores/core.452
$ sudo chmod 400 /cores/core.452
$ cat ~/PID-452-no-core 
Can you see me?

説明すると。

  1. 上述の様に、core.452という名のシンボリックリンクを作ってみます。ターゲットは自分のHomeのPID-452-no-coreとします。
  2. PID-452-no-coreの中身をcatして確認してみます。まだ/cores/core.452は実際には有りませんので「そんなファイルもディレクトリも無い」と言われてしまいます。
  3. coreを手動で吐いてみます。実際にcoreを吐かせるのではなく、擬似的に「Can you see me?」という文字列をcoreに見立てています。sudo を使っているのは実際にcoreが吐かれる際はroot権限で吐かれるからです。
  4. /cores/core.452を実際のcoreと同じパーミッション=0400にします。
  5. シンボリックリンクのターゲットである、~/PID-452-no-coreを見てみると、/cores/core.452の中身が見えてしまいます。



もう一回まとめてみよう。



/coresは、パーミッションが1777だ。だから誰でも書き込める。しかも/coresに書かれるcoreの名前は解ってる。いや、解らなくてもcore.1からcore.999とかまでシンボリックリンクをだぁ〜っと作ればいい。てきとーな場所のてきとーなファイルに対して。
いつか何かのプロセスが落ちたら、シンボリックリンクされてる手元のてきとーなファイルを眺めればcoreの解析ができる。



そう、つまりこの脆弱性の本質は、シンボリックリンクを利用して任意の場所に作った任意のファイルが*coreで上書きされてしまう*ってこと。
だから、直接coreを読むんじゃなくて、作られるcoreに問題があるんでもなくて、coreができるディレクトリのパーミッションとcore生成の名前規則が問題なんであって、coreで上書きされたファイルを読み取ると結果的にcoreが読めてしまう。しかもその際、core自体のパーミッションは関係ない。
こーゆー問題だったんだね、このAdvisoryは。



だからこそこのAdvisoryのタイトルは、「Arbitrary File Overwrite via Core Files」つまり意訳すれば、「coreを介した任意のファイルの上書き」だったんですね。



さて話は変わって、この脆弱性への対処だけど、やっぱり基本的には何もする必要はない。これは変わらない。
Appleも「デフォルトではcoreを吐かない(Core file creation is disabled by default on Mac OS X )」って言ってるから。
t_traceさんや塚本さんが言うように、サービスを全てオフにして、ファイアウォールをオンにして、穏やかに過ごしてれば大丈夫。もちろん基本的に余計なアカウントは作らないとか、パスワードはきちんとしたものにしておくとか、そういうのは既にやっているという前提で。



ちなみに、coreが吐かれる設定というか意図的にcoreを吐かせる為には、/etc/hostconfig に

COREDUMPS=-YES-

の行を追加する。



で、後述すると書いたけど、実は私はマシンにそんな設定を施した覚えはない。けど、/cores以下にcoreはある。何か変だ。
試しに某所のMac OS X Serverで稼働してるマシンを調べたら、こいつにもcoreがあった。もちろん/etc/hostconfigにCOREDUMPSの行は無い。
加えて言うと、macosxhintsの Remove hidden core dump files to restore drive space の元投稿者もコメント を見る限り、設定もしたことが無いはずなのに何でcoreが吐かれるのか解らない様子だ。
どうも /core って何か簡単なことをした程度で吐かれちゃうんじゃないか???
少なくともcoreなんて見るつもりもない、設定したつもりもない私のMacでcoreが生成されているのだから。
まぁこの辺はちゃんと追跡調査しないと解らないので今は置いといて。



最後にこの脆弱性への対処としてダメ押しを一つ。

sudo chmod go-rwx /cores

これで /cores 以下はroot以外読み書きできなくなる。だから、シンボリックリンクを作られるなんてこともなくなるだろう。
ちなみに“sudo chmod 700 /cores”とやるのは止めておこう。stickyビットというものが消えてしまうから。



ホントはcoreの命名規則まで対処したい所だけど、まぁそこら辺はヘタレな私には無理なんで、素直にアップデートを待ちましょうかね。



以上、解説してみる試みでした。

*1:1777の「1」はstickyビットと言って、これが有効だと該当ディレクトリのownerと該当ディレクトリ内のファイルのownerだけしか、そのディレクトリの中からファイルを削除できなくなる。参考:Manpage of CHMOD