2015年12月3日木曜日

PHPにおけるHTTPヘッダインジェクションはまだしぶとく生き残る

この記事はPHPアドベントカレンダー2015の3日目の記事です 。

MBSD寺田さんの記事「LWSとHTTPヘッダインジェクション」では、PHPのheader関数に関連して、PHP側のHTTPヘッダインジェクション対策を回避する手法と、それに対するPHP側の対応について書かれています。この記事では、寺田さんの記事を受けて、現在でもHTTPヘッダインジェクション攻撃が可能なPHP環境が残っているかを検証します。

HTTPヘッダインジェクションとは

以下の様なスクリプトがあるとします。
<?php
  header('Location: ' . $_GET['url']);
オープンリダイレクタ脆弱性がありますが、それは気にしないとして、PHP5.1.1までのバージョンでは、以下の様な攻撃が可能でした。

http://example.jp/header.php?url=http://example/top.php%0d%0aSet-Cookie:+PHPSESSID%3DABC

これにより生成されるHTTPレスポンスヘッダは以下となります。
Location: http://example/top.php
Set-Cookie: PHPSESSID=ABC
すなわち、HTTPヘッダとして出力されるパラメータに改行を含めることにより、開発者の意図しないレスポンスヘッダを出力させることができるというものです。上記の例では、Set-Cookieヘッダを出力させることにより攻撃者が任意のセッションIDをセットさせ、セッション固定攻撃に悪用できるというケースを示しています。

PHP 5.1.2での改良およびその抜け道

これに対して、PHP5.1.2にて、header関数の引数中の改行をチェクし、複数のヘッダを送信しないように改修されました。
これで、PHPでヘッダインジェクションはできなくなった…と思いきや、抜けがありました。PHP5.1.2での修正は、改行を構成するキャリッジリターンとラインフィードのうち、ラインフィードのみをチェックしていて、キャリッジリターンはチェックしていません。一方、大半のブラウザ(IE、Google Chrome、Safari、Opera)ではキャリッジリターンのみでも改行とみなしていて、ヘッダインジェクションが可能な状態でした。
http://example.jp/header.php?url=http://example/top.php%0dSet-Cookie:+PHPSESSID%3DABC
この問題はPHP 5.3.11およびPHP 5.4.0で修正され、最新のPHPではキャリッジリターンのみを使ったヘッダインジェクションはできなくなっています。


「継続行」を用いた攻撃方法

これでPHPではヘッダインジェクション攻撃はできなったと思われていましたが、まだ抜けがありました。それは継続行を使う方法です。
継続行とは、HTTP/1.1のRFC2616で規定されていたもので、以下のように、一つのレスポンスヘッダを複数行に分けて記述するものです。行頭に空白やタブがある場合、それは直前のヘッダに継続する内容(継続行)とみなされます。
Set-Cookie: PHPSESSID=UJqaktGaFBGTTAyM0diNks1aEJvZ2NNYz;
 domain=example.jp; path=/;
上の例では、Set-Cookieヘッダのdomain属性とpath属性を継続行に置いています。
これについて、下記の状況がありました。
  • PHPは5.1.2で複数行ヘッダを禁止したが、継続行は正規のヘッダとして認めていた
  • 多くのブラウザは継続行に対応していたが、IEのみ継続行を無視し、別のヘッダとして認識する
ということから、以下の攻撃に対して、IEの場合のみヘッダインジェクションが成立する状況でした。
http://example.jp/header.php?url=http://example/top.php%0d%0a%20Set-Cookie:+PHPSESSID%3DABC
ご覧のように、改行(%0d%0a)につづいて空白(%20)を用いることにより、以下の状況によりヘッダインジェクション攻撃を行うものです。
  • PHPは継続行と認識してそのまま通す
  • IEは(継続行ではなく)2つのヘッダと認識してSet-Cookieが受け入れられる
これに対して、HTTPの継続行がRFC7230で廃止されたことを受けて、PHPの以下のバージョンにて継続行もエラーになるように改修されました。
  • 5.4.38
  • 5.5.22
  • 5.6.6
すなわち、現在メンテナンスされている最新版のPHPにおいては、アプリケーション側で対処しなくても、HTTPヘッダインジェクションはできなくなりました。

Linuxディストリビューションの対応

PHP本家の最新版ではHTTPヘッダインジェクションに対処されたといっても、CentOSやDebian等LinuxディストリビューションのパッケージとしてPHPを導入している環境ではどうでしょうか?以下のディストリビューションにて検証してみました。現時点のすべてのパッチを適用した状態でテストしています。
  • Centos 5、6, 7
  • Ubuntu 10.04, 12.04, 14.04, 15.04, 15.10
  • Debian 6, 7, 8
  • Fedora 20, 21, 22, 23
結果は以下のとおりです。※ 注記参照


この結果から言えることは…
  • 全てのディストリビューションにおいて、キャリッジリターンのみによるヘッダインジェクションは対策されている
  • 長期サポートのCentOS、Ubuntu LTSでは、継続行によるヘッダインジェクションにはパッチが提供されていない
ということで、PHPの最新のパッチがあたっている場合でも、HTTPヘッダインジェクションができるサーバーはまだ存在する、というのが結論です。

※ 2016年8月11日のコミットにて、Ubuntu 12.04LTS以降も、継続行を禁止するパッチが作られました。これで、継続行によるヘッダインジェクションが可能なディストリビューションは、RHEL/CentOSのみとなりました。(2016年12月17日追記)

まとめ

HTTPヘッダインジェクションの最新動向について、寺田さんのブログ記事を参照しながら紹介しました。PHPの最新版においてはHTTPヘッダインジェクション攻撃の変種についても対策されているものの、CentOSやUbuntu等の長期サポートディストリビューションの中には、まだ「継続行」を用いた攻撃に対するパッチが提供されて環境があります。
したがって、HTTPヘッダインジェクション脆弱性対策については、一応はPHP側の責任と考えたうえで、アプリケーション側でもヘッダ文字列のバリデーション等で対策をしておくことを推奨します。

PHPにおいて、HTTPヘッダインジェクションは過去の(歴史的な)攻撃手法になりかけてはいるものの、まだしぶとく生き残っている、というのが結論です。


【HASHコンサルティング広告】
HASHコンサルティング株式会社は、セキュリティエンジニアを募集しています。
興味のある方は、twitterfacebookのメッセージ、あるいは問い合わせページからお問い合わせください。


0 件のコメント:

コメントを投稿

フォロワー

ブログ アーカイブ