プライバシーポリシー

2015年12月18日金曜日

Joomla!の「ゼロデイコード実行脆弱性」はPHPの既知の脆弱性が原因

Joomla!にコード実行脆弱性(CVE-2015-8562)があり、パッチ公開前から攻撃が観測されていたと話題になっています。
パッチ公開の前に攻撃が始まる状態を「ゼロデイ脆弱性」と言いますが、それでは、この脆弱性のメカニズムはどんなものだろうかと思い、調べてみました。
結論から言えば、この問題はJoomla!側に重大な脆弱性はなく、PHPの既知の脆弱性(CVE-2015-6835)が原因でしたので報告します。

exploitを調べてみる

既にこの問題のexploitは公開されていますが、悪い子が真似するといけないのでURL等は割愛します。以下のページでは攻撃の原理が説明されています。
ざっくり言うと、以下の様な攻撃です。
  1. Joomla! がUser-Agentをセッション変数に保存するので、セッション形式のデータ(文字列)をUser-Agent経由でセットする
  2. その際、MySQLのデフォルトでは、UTF-8の4バイト形式があると、それ以降をトランケートする仕様を悪用して、攻撃に不要なデータを切り詰める
  3. 何ということでしょう! 切り詰めをすると、文字列がオブジェクトに化けるではありませんか
  4. 上記によりJoomlaのJDatabaseDriverMysqli、SimplePie等のクラスのオブジェクトをインジェクションして、デストラクタにより任意コードを起動
全体的には、典型的なオブジェクトインジェションによるコード実行です。なぜデストラクタにより任意コードが実行できるかについては、以下の記事を参照下さい。
問題は、上記の 3 です。なぜ、文字列を切り詰めると、文字列型のデータがオブジェクトに化けるのでしょうか。前記の記事にはその辺の説明はなかったので、自分で調べてみました。

シンプルな再現コード

以下は、セッション変数にログインユーザ名とUser-Agentのみをセッション変数にセットして、その際のセッション形式の文字列を表示するだけの簡単なプログラムです。
<?php
// インジェクションするクラス(攻撃対象の既存クラス)
class Class1 {
  private $private = 'prv';
  function __destruct() {
    echo "Class1::__destruct()\n";
  }
}

session_start();

$id = 'ockeghem'; // ログインユーザ名
// $browser はUser-Agentであり外部からコントロールできる
$browser = 'Mozilla/5.0';

$_SESSION['_default']['id'] = $id;
$_SESSION['_default']['browser'] = $browser;

echo str_replace("\0", '%00', session_encode()) . "\n";
出力は以下となります。
_default|a:2:{s:2:"id";s:8:"ockeghem";s:7:"browser";s:11:"Mozilla/5.0";}
セッション変数のシリアライズ形式は、以下のような形です。
  • _default   セッション変数のキー
  • a:2:{...}  要素数2の配列
  • s:2:"id"   文字列長の2の文字列「id」
一方、外部からは操作できませんが、browserのところにオブジェクトをセットした場合の形式は下記のとおりです。ヌル文字を含むため、パーセントエンコードした形で表示しています(bloggerの制限により%記号は全角にしていますが実際は半角です)。
_default|a:2:{s:2:"id";s:8:"ockeghem";s:7:"browser";O:6:"Class1":1:{s:15:"%00Class1%00private";s:3:"prv";}}
これを念頭におきつつ、外部からUser-Agentとして以下を設定してみます(パーセントエンコード形式)。■は、実際には、UTF-8の4バイト形式の文字をセットします。
_aa|O:6:"Class1":1:{s:15:"%00Class1%00private";s:3:"prv";}■
セッション変数のシリアライズ結果は下記となります。
_default|a:2:{s:2:"id";s:8:"ockeghem";s:7:"browser";s:57:"_aa|O:6:"Class1":1:{s:15:"%00Class1%00private";s:3:"prv";}■";}
しかし、これはあくまで文字列です。それは、s:57という型指定がある以上、外部からは変更できないはずです。
しかし、Joomla!のデフォルトのセッションストレージはMySQLであり、文字エンコーディングはutf8_general_ciとなっています。この場合、MySQLは、UTF-8の4バイト形式の文字があると、その文字を含めてそれ以降が切り詰められる、というすごい仕様があります。

このため、セッションをいったんMySQLに保存して、次のページでそのセッションデータを読みだすと、以下のように■以降がカットされた状態となります。
_default|a:2:{s:2:"id";s:8:"ockeghem";s:7:"browser";s:57:"_aa|O:6:"Class1":1:{s:15:"%00Class1%00private";s:3:"prv";}
このセッションデータをダンプすると、何ということでしょう! 文字列だった部分がオブジェクトになっているではありませんか。そして、オブジェクトが生成されているので、このデストラクタも実行されます。
array(2) {         ← ダンプ
  ["_default"]=>
  NULL
  ["57:"_aa"]=>
  object(Class1)#1 (1) {
    ["private":"Class1":private]=>
    string(3) "prv"
  }
}
Class1::__destruct()    ← デストラクタの実行
上記から、以下のことが言えます。
  • これは Joomla! の脆弱性ではない

この問題の原因は何か

phpallを使ってこの問題を確認すると、PHPの以下のバージョンで起こることが分かります
  • PHP-5.0.3~PHP-5.0.5
  • PHP-5.1.x ~ PHP-5.3.x 全て
  • PHP-5.4.0~PHP-5.4.44
  • PHP-5.5.0~PHP-5.5.28
  • PHP-5.6.0~PHP-5.6.12
すなわち、以下のバージョンで修正されています。
  • PHP-5.4.45
  • PHP-5.5.29
  • PHP-5.6.13
  • PHP-7.0.0
これらで修正されている脆弱性はなんだろうと思ってリリースノートを見ると、以下が該当するようですね。
  • Fixed bug #70219 (Use after free vulnerability in session deserializer). (CVE-2015-6835)
セッション・デシリアライザのUse after free脆弱性ということで、挙動から見てもビンゴでしょう。

Linuxディストリビューションではどうか?

PHP本家の対応は上記のとおりですが、RHEL/CentOS等のLinuxディストリビューションから、パッケージとして提供されているPHPのパッチの対応状況はどうでしょうか?
  • CentOS 5,6,7ともパッチ提供なし(参考
  • Ubuntu 12.04、14.04ともパッチ提供済み(参考
  • Debian/GNU Linux Debian6はパッチ未提供、7以降は提供済み
  • Fedora Fedora21以降でパッチ提供済み(20はサポート終了でパッチ提供なし)
Red Hat社の脆弱性トリアージ(緊急度判断)は通常妥当だと思っているのですが、この件に関しては外れてしまったようです。ただし、シリアライズされたセッションデータが切り詰められるなんて状況はちょっと予想しがたいので、悪いのはMySQLの仕様だ!、と思わなくもありません。

影響を受けるソフトウェア

PHPのこの脆弱性の影響は、Joomla!に限られるものではありません。セッションストレージとしてMySQLを使うことは、一般的によく行われているからです。

このため、影響の有無判定はともかく、PHPの最新版を使うことを推奨します。

RHEL/CentOSについてはパッチが提供されていないので、個別の対策をとるしかないでしょう。例えば、以下の様な対応が考えられます。
  • アプリケーション側で対応したバージョンを導入する(例:Joomla! 3.4.6)
  • MySQL 5.5.3 以降で使える utf8mb4 エンコーディングを使用する
  • セッションストレージとしてMySQLを避ける
  • バリデーションによりUTF-8の4バイト形式をエラーにする
緩和策としては、WAF(Web Application Firewall)の導入があります。

まとめ

Joomla!のリモートコード実行の問題を分析しました。これまで説明したように、この問題の直接の原因は、Joomla!側にはなく、PHPの既知の脆弱性(CVE-2015-6835)が原因です。私も「Joomla!にゼロデイ脆弱性」とツイートしてしまいましたが、Joomla!の問題ではないと訂正いたします。

この問題は、
  • PHPの通常は顕在化しない脆弱性CVE-2015-6835が
  • MySQLのUTF-8 4バイト形式以降を切り詰めるという仕様のため顕在化した
ことが問題と考えます。とくに、MySQLの上記挙動は、こちらでも書いたように、長いデータを黙って切り詰めると思わぬバグや脆弱性の原因になり得るという例だと言えるでしょう。



【HASHコンサルティング広告】
HASHコンサルティングが販売するWAF(SiteGuard、SiteGuard Lite)は、このJoomla!のコード実行の問題に対応したシグネチャを提供済みです。お問い合わせはこちら
HASHコンサルティング株式会社は、セキュリティエンジニアを募集しています。
興味のある方は、twitterfacebookのメッセージ、あるいは問い合わせページからお問い合わせください。


2015年12月7日月曜日

WordPressの侵入対策は脆弱性管理とパスワード管理を中心に考えよう

この記事はWordPress Advent Calendar 2015の7日目の記事です。

今年初めてWordCamp Tokyoにて講演の機会をいただき、WordPressのセキュリティについて話しました(スライド)。そこでもお話ししましたが、WordPressに限らず、Webサイトへの侵入経路は2種類しかありません。それは以下の2つです。
  • ソフトウェアの脆弱性を悪用される
  • 認証を突破される
したがって、侵入対策としては以下が重要になります。
  • 全てのソフトウェア(OS、Apache等、PHP、WordPress本体、プラグイン、テーマ等)を最新の状態に保つ
  • パスワードを強固なものにする
以上! と叫びたい気分ですが、それではシンプル過ぎると思いますので、以下、WordCampでお話した内容とリンクしながら、もう少し細く説明したいと思います。

全てのソフトウェアを最新の状態に保つ

WordPressサイトを前提とすると、以下のソフトウェアの脆弱性を悪用した攻撃の可能性があります。
  • Apache、OpenSSL等
  • PHP
  • WordPress本体
  • WordPressのプラグイン、テーマ
これらのうち、Apache、OpenSSL、PHP等については、できればソフトウェアのアップデートを自前でやるのではなく、ホスティング業者等が代行してくれるサービスを選ぶとよいでしょう。昔からあるレンタルサーバー(共用ホスティング)も該当しますし、PaaS(Platform as a Service)も原則としてアップデートを事業者側でやってくれるはずです(要個別確認)。

WordPress本体とプラグイン、テーマのアップデートは重要です。とくに、プラグインとテーマについては、セキュリティ上の品質が本当にまちまちなのが困ったところです。WordCampでデモに用いたのはMailPoetというプラグインですが、過去のバージョンではテーマアップロードの際に認証をチェックしておらず、誰でも自由に勝手なテーマをアップロードできたという脆弱性があり、このため、脆弱性のデモも以下のように単なるアップロードフォームで攻撃できてしまいました(攻撃がマネできないように一部伏せ字)。
<body>
<form action="http://examle.jp/wp-admin/admin-post.php?page=xxxxxxxxxxxx&action=xxxxx" method="post" enctype="multipart/form-data">
<input type="text" name="action" value="xxxxxxxxx">
<input type="text" name="submitter" value="xxxxxxx">
<input type="text" name="xxxxxxxxxxxxx" value="xx">
<input type="file" name="xxxxxxxxx">
<input type="submit" value="攻撃">
</form>
</body>
このため、プラグインとテーマのアップデートは特に重要です。具体的には、
  • 本当に必要最小限のプラグインとテーマのみを導入する
  • プラグインとテーマのアップデートは自動化する
ことが重要です。
自動アップデートするとサイトが動かなくなることが心配という人もいるでしょうね。そういう心配には、クラウドのイメージバックアップ機能によりサイト全体を保存しておき、万一サイトが動かなくなった場合はバックアップから戻した上でゆっくりと原因分析をするとよいでしょう。ただし、バックアップから戻した直後はプラグイン等が古いわけですから、そのままの状態で公開してはいけません。動かなくなった原因を究明して対処を行い、プラグインのアップデートをすませてから公開するべきです。

パスワードを強固なものにする

もう一つの侵入経路は、認証を突破されるケースですが、WordPressの場合は「パスワードがばれちゃった」というケースが該当します。具体的な手口としては以下の様なものがあります。
  • パスワードが辞書に載っているもので、パスワードの辞書攻撃により侵入された
  • パスワードを他サイトでも使い回ししていて、パスワードリスト攻撃により侵入された
  • 管理端末がウイルス感染して、ウイルスがパスワードを漏洩させた
したがって、対策としては、下記が有効です。
  • よいパスワードを設定する(他で使っていない、辞書に載っていない、できればランダムな)
  • 管理用パソコンのウイルス対策(ソフトウェアのアップデートとウイルス対策ソフト)
WordPressの場合、よく「管理者のユーザ名としてadminは避けましょう」ということが言われます。確かに、admin決め打ちの攻撃も多いのでできればadminを避けたほうがよいとは思いますが、WordPerssは、ログイン名が外部にバレやすいという特性があります。下記は、WPscanというツールを用いてWordPressの辞書攻撃を行った結果の例ですが、adminユーザの方は良質なパスワードを設定していたので破られなかったものの、yamadaユーザはtiggerというパスワードが辞書攻撃によりばれてしまいました。
  +----+--------+------+----------+
  | Id | Login  | Name | Password |
  +----+--------+------+----------+
  | 1  | admin  |      |          |
  | 4  | yamada |      | tigger   |
  +----+--------+------+----------+
つまり、良質なパスワードをつけることが第一優先であり、その他は副次的な対策である、ということです。
WordPressの場合、ログインユーザ名を隠すことは不可能ではないようですが、かなりハードルが高いといえます。このため、ログインユーザ名がわかってしまうことは許容し、パスワード管理に注力することが得策であると考えます。

ファイルのパーミッション

レンタルサーバーにおいては、ファイルのパーミッション設定が重要となります。これは、一つのApacheを複数ユーザーで共有するという特性上必要なものです。
レンタルサーバー事業者側の対策が十分であれば通常は問題になることはないはずですが、現実に大規模な攻撃に至ったケースもあるので、利用者側でもできる対策はしておきましょう。
レンタルサーバーにおいては、以下のパーミッション設定が基本となります。
  • HTMLやJS、CSS、画像は604
  • PHP スクリプトは 600
  • CGI スクリプトは 700
  • ディレクトリは 701
※レンタルサーバー事業者によっては多少異なるパーミッションを指定している場合があります

静的なファイルに関しては、レンタルサーバ独自の特性として、1桁目(右端の桁)にReadパーミッションが必要となります。その他、PHPスクリプトやCGIスクリプトについては、ファイルオーナーのみに権限を与えることが重要です。

その他の「対策」について

上記二点がWordPressサイトのセキュリティ施策としてもっとも重要なものですが、「WordPress セキュリティ」等のキーワードで検索すると、「WordPressを守るために必須の10個の対策」みたいな記事をよく見かけます。
これらの記事を読むと、往々にして「それ、無意味とは言わないけど、それほど効果は期待できないから…」というものが多いです。
以下、それらの代表例を紹介します。

テーブル名のプレフィックをデフォルトから変更することの効果

WordPressのテーブル名にはデフォルトでwp_というプレフィックスがつきますが、そのままだとSQLインジェクション攻撃を受けるので、必ず他のものに変えるようにという記事をよく見かけます。
やらないよりはやった方がよいと思いますが、SQLインジェクション脆弱性があるという前提では、実はそれほど効果はありません。
なぜなら、SQLデータベースにはinformation_schemaという機能があり、テーブル名やデータベース名(スキーマ)は、ここから分かるからです。具体的には、information_schemaに対してSQLインジェクション攻撃をかけることで、テーブル名等の情報を得ることができます。
したがって、プレフィックスを変更すると、へっぽこな攻撃者や攻撃ツールは避けることができるかもしれませんが、腕の良い攻撃者からの攻撃は避けられません。
つまり、SQLインジェクション脆弱性があり、それを攻撃者に見つけられた時点で終わりなのです。このため、SQLインジェクション脆弱性を全力で避ける必要があります。
WordPressのプラグイン等であれば、WordPressの提供するプレースホルダ機能でSQLを呼び出すこと、素のPHPスクリプトであれば、PDOのプレースホルダ機能を用いてSQLを呼び出すことで、SQLインジェクション対策を行って下さい。

.htaccess等で wp-config.php をアクセス制限することの効果

.htaccess等を用いて、外部からwp-config.phpのアクセス制限をするという施策はよく見かけますが、この「対策」が役に立つケースは、実はそれほど多くありません。
wp-config.phpは設定のためのパラメータ設定のPHPスクリプトが並んでおり、このファイルにアクセスしても何も起きません。外部に公開されているPHPスクリプトなのでそれは当然です。問題は、wp-config.phpに記述されたデータベースのユーザ名やパスワードが漏洩することです。
しかし、wp-config.php自体にアクセスしてもそのソースコードは表示されません。表示されるとしたら、なんらかの脆弱性がある場合ですが、wp-config.php自体は単純なものなので、これ自体に脆弱性がある可能性はまずありません。したがって可能性としては、下記が考えられます。

(a) PHPのインストールを忘れていてwp-config.phpが生のままダウンロードされる
(b) 他のPHPスクリプトにディレクトリトラバーサル等の脆弱性がありwp-config.phpを閲覧される
(c) PHP等に脆弱性があり、PHPのソースが漏洩する

(a)は論外のケースであり、インストールの手順をしっかり立てましょう。万一 wp-config.phpの内容を閲覧されてしまった可能性がある場合、すみやかにデータベースのパスワードを変更する必要があります。また、念のため、データベースをすべて削除しておくとよいでしょう。(まだデータは入っていないはずなので)

(b)はあり得るケースですが、残念ながらこの場合は .htaccessの設定では防げません。.htaccessで制限しても、PHP等からは読めるからです。そうでないと、PHPスクリプトからインクルードもできないことになりますよね。

(c)も過去にはありました。CGI版のPHPにCVE-2012-1823という脆弱性があり(参考)、以下のURLのように、?-s をURLにつけることでwp-config.phpのソースを閲覧することができました。
  • http://example.jp/wp-config.php?-s
なんだ、効果があるじゃないかと思われるかもしれませんが、CVE-2012-1823に関しては、リモートコード実行もできたので、.htaccess による制限だけでは、結局ソースコードの閲覧も含め、さまざまな攻撃を許してしまう状況でした。
実際、レンタルサーバー事業者の中には、上記 ?-s による攻撃のみを重視した結果、肝心のリモートコード実行を防ぐことができず、重大な攻撃を受けてしまったところもあります。
将来見つかる脆弱性において、PHPのソースを閲覧できるものが出てくるかもしれませんので、その場合は .htaccess による制限も効果はあることになります。よって、「やっても無駄」というつもりはありませんが、今後そのような脆弱性が発見される見込みはそれほど高くないと思いますので、優先順序としては、脆弱性やパスワードの管理をしっかりやった後、ということです。

SiteGuard WP Pluginのすすめ

今までの話がWordPressのセキュリティ対策の「原則」の話ですが、いくら注意していても設定漏れ等により侵入を許す場合もあり、また長いパスワードをつけているので辞書攻撃の被害を受けないことはわかっていても、延々と攻撃を受け続けると気分はよくありません。
このため、付加的なセキュリティ対策についての検討をするところですが、私からはSiteGuard WP Pluginを紹介したいと思います。
SiteGuard WP Pluginは、WordPressのログイン周りに特化した無料のプラグインで、以下の機能を提供します。


管理ページアクセス制限ログインしていない接続元から管理ディレクトリ(/wp-admin/)を守ります。
ログインページ変更ログインページ名を変更します。
画像認証ログインページ、コメント投稿に画像認証を追加します。
ログイン詳細エラー
メッセージの無効化
ログインエラー時の詳細なエラーメッセージに変えて、単一のメッセージを返します。
ログインロックログイン失敗を繰り返す接続元を一定期間ロックします。
ログインアラートログインがあったことを、メールで通知します。
フェールワンス正しい入力を行っても、ログインを一回失敗します。
ピンバック無効化ピンバックの悪用を防ぎます。
更新通知WordPress、プラグイン、テーマの更新を、メールで通知します。
WAFチューニングサポートWAF (SiteGuard Lite)の除外リストを作成します。
JP-Secure社の紹介記事より引用

SiteGuard WP Pluginのレビューについては既に多くの記事がありますので、そちらをお読みいただければと思いますが、私がよいと思うポイントは下記の三点です。
  • SiteGuard の不正ログイン防止に特化している
  • 簡単に導入できて効果が高い
  • プラグイン自体の脆弱性対策がなされている(重要)
「セキュリティプラグイン」と称していながらSQLインジェクション脆弱性があったなんてものも過去ありましたので、プラグイン自体がセキュアであることは現実問題として非常に重要です。

SiteGuard WP Pluginのインストールはこちらから。

まとめ

WordPressの侵入対策について説明しました。
WordPressに限りませんが、ウェブサイトに対する侵入対策としては、脆弱性管理とパスワード管理が極めて重要であり、これらをおろそかにして他の(楽な)対策をいくら積み重ねても、あまり効果はありません。レンタルサーバーを利用する場合は、ファイルのパーミッション設定も重要です。
本稿の内容が皆様のサイトの安全性寄与にお役に立てれば幸いです。


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のメッセージ、あるいは問い合わせページからお問い合わせください。