🐘

いにしえのPHPを召喚してHTTPヘッダインジェクションを再現する

2022/01/16に公開約3,000字

はじめに

安全なウェブサイトの作り方」の中で、HTTPヘッダインジェクションが紹介されています。理解を深めるために普段使っているPHPで動きを再現しようとしたのですが、思うように動かず、、。

調べてみると、バージョン5.1.2では対策されており、現在メンテナンスされてるバージョンでは再現しないことがわかりました。

修正によってheader()を使用して、1回の呼び出しで複数の応答ヘッダーを送信することはできなくなったのことです。

https://www.php.net/releases/5_1_2.php

HTTP Response Splitting has been addressed in ext/session and in the header() function. Header() can no longer be used to send multiple response headers in a single call.

ちなみに初回リリースは12 Jan 2006なので、15年以上前ですね。

https://www.php.net/ChangeLog-5.php#5.1.2

本記事ではバージョン5.1.2以前のPHPを用意してHTTPヘッダインジェクションを再現してみます。

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

HTTPヘッダインジェクションの概要は以下のページなどがわかりやすいです。

https://www.ipa.go.jp/security/vuln/websecurity-HTML-1_7.html
https://yamory.io/blog/about-http-header-injection/

HTTPヘッダ・インジェクションの脆弱性とは、任意のレスポンスヘッダフィールドやレスポンスボディを作成する罠が仕掛けられ、この罠を踏んだ利用者のブラウザで偽のページが表示されたり、スクリプトが実行したり、任意のCookieを保存させられたりする可能性があります。

リクエストに対して出力するHTTPレスポンスヘッダのフィールド値を、外部から渡されるパラメータの値等を利用して動的に生成するケースがあります。PHPではheader関数を利用した場合でしょう。

たとえば、HTTPリダイレクトの実装として、パラメータから取得したジャンプ先のURL情報を、Locationヘッダのフィールド値に使用する場合や、掲示板等において入力された名前等をSet-Cookieヘッダのフィールド値に使用する場合等が挙げられる。

その渡されたパラメーターを利用してたページにおいて、HTTPレスポンスヘッダの出力処理に問題があることが原因です。具体的には改行コードの扱いです。

改行コードはHTTPヘッダにおいて特殊文字にあたります。各HTTPヘッダ行は改行で区切られ、それ以降は新たなヘッダ行として処理されます。つまり改行コードが挿入できると意図しないレスポンスヘッダが追加できてしまいます。

再現していく

いにしえのPHPを召喚

バージョン5.1.2以前のPHP環境を用意していくにあたって、以下のDockerイメージにお世話になりました。(ありがたい、、。)

https://hub.docker.com/r/nouphet/docker-php4/

環境は以下です。

  • PHP 4.4.0
  • Apache 2.2

PHP 4.4.0のリリースは11 Jul 2005のようです。歴史を感じますね^^。

https://www.php.net/ChangeLog-4.php#4.4.0

状況

パラメーターの値をもとに新しいURLへリダイレクトするという状況を想定します。

たとえば、http://localhost?url=sample.htmlにアクセスするとhttp://localhost/sample.htmlにリダイレクトされるという仕様です。

上記を踏まえて、ドキュメントルート下に以下のようなファイルを設置しました。

index.php
<?php
if(isset($_GET['url'])){
    header('Location: ' . $_GET['url']);
}
?>

<div>Render Cookies</div>
<?php
    if (isset($_COOKIE)){
        echo('<pre>');
        var_dump($_COOKIE);
        echo('</pre>');
    }
?>

header('Location: ' . $_GET['url']);とあり、header()で'Locationを設定することでリダイレクトを実現しています。

(このケース、オープンリダイレクトの脆弱性も含まれてしまってますが、、、。)

やり方

Set-Cookieヘスポンスヘッダを追加することで、Cookieをセットしていきましょう。

そのために、以下のURLにアクセスします。
http://localhost/?url=http://localhost/%0d%0aSet-Cookie:+PHPSESSID%3Dhogehoge

アクセスすると、%0d%0aが改行として読み込まれ追加されるHTTPレスポンスヘッダは以下のようになりCookieが書き換えられるわけです。

Location: http://localhost
Set-Cookie: PHPSESSID=hogehoge

デモ

それでは実際に動きをみていきましょう。

https://youtu.be/eUPzJtFnYFo

開発者コンソールからSet-Cookie: PHPSESSID=hogehogeという内容のレスポンスヘッダも確認できました!!

以上になりますmm

参考

Discussion

ログインするとコメントできます