徳丸浩のtumblr
セッションアダプションがなくてもセッションフィクセイション攻撃は可能

大垣(@yohgaki)さんと、セッションアダプション脆弱性が「重大な脅威」か否かで論争を続けています。

議論がかみ合わないので、twitterで「ブログ読みました。サンプルも動かしました。問題は分かるのですが、セッションアダプションがないPHPだと、何が改善されるのかが分かりません。教えて下さい」とツイートしたところ、大垣さんがブログで返信下さいました。

これを読んでかみ合わない理由が分かりました。大垣さん、ありがとうございます。以下大垣さんのブログの末尾を引用します。

脱線しましたが、何が改善されるのか?結論は

  1. ログイン時にsession_regenerate_idを呼んでない
  2. 自動ログインなど通常のセッション用以外でsession_regenerate_idを呼んでいない
  3. session_regenerate_idを呼んでいても、途中で保存している
  4. session_regenerate_idを呼んでいても、途中で実行パスが変えられる

という事を考えなくてもアダプションによるログインセッション乗っ取りが行えなくなる事が改善点です。

つまり、大垣さんの主張は、セッションアダプションがないPHPでは、アプリケーション側で対策しなくても、セッションフィクセイション攻撃を防げるということなのですね。徳丸は、セッションアダプションがなくても、アプリケーション側でも対策しなければ、セッションフィクセイション攻撃を防げないと考えます。

つまり、徳丸の主張を証明するためには、「セッションアダプションのないPHPを使っているが、セッションフィクセイション攻撃を受ける」実例を示せばよいことになります。これを書いてみました。

幸い、大垣さん自身が、「PHPのStrict Sessionパッチ」を公開しておられます。これをPHP5.4.0に適用して、セッションアダプションのないPHP環境を試験用に借りているVPS上に構築しました。デモ環境を期間限定(1ヶ月程度)で公開しますので、以下にデモとソースの説明をします。

デモの想定

以下のデモでは、サブドメインによるレンタルサーバーを想定しています。これは、大垣さんの記事にある想定に従ったものです。以下の2つのサイトがあります。

  • FIX.WSXW.INFO (セッションフィクセイション脆弱性のあるサイト)
  • XSS.WSXW.INFO(XSS脆弱性のあるサイト)

ここで登場人物が二人登場します。佐藤氏はFIX.WSXW.INFOにユーザ登録しています。攻撃者は、佐藤氏にセッションフィクセイション攻撃を仕掛けて、佐藤氏の個人情報を得ようとしています。セッションフィクセイション攻撃を仕掛けるためには、攻撃対象サイト(FIX.WSXW.INFO)のセッションクッキーを佐藤氏のブラウザ上でセットしなければなりませんが、その目的のために、XSS.WSXW.INFOのXSS脆弱性を悪用します。

サンプルスクリプトの説明

ここで、脆弱性のあるサンプルスクリプトを紹介します。まずは、FIX.WSXW.INFOのソースです。まずは、ログインフォーム(index.html)。

<body>
<form action="login.php" method="POST">
ユーザIDを入力:<input name="userid"><br>
パスワードを入力:<input name="password"><br>
<input type="submit">
</form>
</body>

ログインの実行画面(login.php)。デモなので、IDとパスワードはハードコーディングされています。

<?php
  session_start();
  $userid = @$_POST['userid'];
  $password = @$_POST['password'];
  if ($userid === 'sato' && $password === 'pass1') {
    $loginok = true;
    $_SESSION['id'] = $userid;
  } else {
    $loginok = false;
  }
?><body>
セッションID:<?php echo htmlspecialchars(session_id()); ?><BR>
<?php if ($loginok): ?>
<?php echo htmlspecialchars($userid); ?>さん、ログイン成功です<BR>
<?php else: ?>
ユーザIDまたはパスワードが違います<br>
<br>
ここからはテスト用の情報です。<br>
あなたは攻撃者です。以下のURLを誰かに踏ませて下さい。<br>
被害者に見立てた別のブラウザ(FirefoxやOpera)を起動して、
<a href="http://xss.wsxw.info/search.cgi?search=%3Cscript%3Edocument.cookie%3D%22PHPSESSID%3D<?php
 echo htmlspecialchars(session_id()); ?>%3B+domain%3Dwsxw.info%22%3B%3C%2Fscript%3
E<a+href=%22http://fix.wsxw.info%22>ログイン</a>">
このURL</a>をアドレスバーにコピペして下さい<br>

<?php endif; ?>
<a href="profile.php">個人情報</a>
</body>

ログイン成功後に個人情報を表示する画面(profile.php)

<?php
  session_start();
  $loginok = isset($_SESSION['id']);
?>
<html>
<body>
セッションID:<?php echo htmlspecialchars(session_id()); ?><BR>
<?php if ($loginok): ?>
ユーザID:<?php echo htmlspecialchars($_SESSION['id']); ?><BR>
氏名: 佐藤信治<br>
住所: 東京都千代田区1-1<br>
<form action="logout.php" method="POST">
<input type="submit" value="ログアウト">
</form>
<?php else: ?>
ログインして下さい
<?php endif; ?>
</body>
</html>

ログアウト画面(logout.php)。デモの都合で、様々なdomainのCookieを削除しています。

<?php
  session_start();
  setcookie(session_name(), '', 1, '/', 'wsxw.info');
  setcookie(session_name(), '', 1, '/', 'fix.wsxw.info');
  setcookie(session_name(), '', 1);
  session_destroy();
?>
<html>
<body>
ログアウトしました<br>
<a href="/">トップに戻る</a>
</body>
</html>

次に、XSS.WSXW.INFOのソースです。

まずは検索フォーム(index.html)。

<body>
<form action="search.cgi" method="GET">
検索文字列<input name="search" size="40"><br>
<input type="submit">
</form>
</body>

検索実行画面(search.cgi)。クエリストリングsearchをエスケープしないで表示しているので、XSS脆弱性があります(注:当初PHPでこれを書いていましたが、誤解を招いたようなので、CGIプログラムに書き換えました。画面はPHPのままですが、実機では修正されています)。

#!/usr/bin/perl
use strict;
use CGI;
my $query = new CGI;
my $search = $query->param('search');
print <<END;
Content-Type: text/html; charset=UTF-8

<body>
検索文字列: $search<br>
<br>
検索結果: ありません
</body>
END

正常系での実行

ここで、まず正常系を試してみます。デモの都合で、ブラウザはChromeをつかいますが、IEでも大丈夫です。fix.wsxw.infoを呼び出し、ユーザ名とパスワードにそれぞれ、sato、pass1と入力します。

image

送信ボタンをクリックすると以下の画面になります。

image

「個人情報」のリンクをクリックすると、satoさんの個人情報が閲覧できます。

image

「ログアウト」ボタンをクリックすると、ログアウトします。

image

次に、xss.wsxw.infoを試しますが、こちらはXSSも試したいので、(XSSフィルタのない)FirefoxかOperaで試しましょう。

image

検索文字列欄に「<script>alert(1)</script>」と入力して「送信」ボタンをクリックします。

image

ちゃんと(?)XSSが発動してalertが表示されました。

攻撃のデモ

次に、あなたは攻撃者の立場です。先ほどのChromeのログアウトした状態から、「トップに戻る」リンクをクリックして、ログインフォームを表示して下さい。

あなたは佐藤さんのIDとパスワードを知らないで、それを入力することはできませんが、IDとパスワードが空の状態で、送信ボタンを押してみて下さい。

image

ログイン機能が動作したために、セッションIDが設定されています。デモ用の画面が表示されていますが、「このURL」のところでマウスの右クリックでコンテキストメニューを表示させて「リンクアドレスをコピー」をクリックします。

image

これはXSS攻撃用の罠のURLを生成しているのです。本来は、このURLを佐藤さん(被害者)に踏んでもらうのですが、ここは一人二役で、あなたが佐藤さんのFirefoxを操作して下さい。Firefoxのアドレスバーに、さきほどコピーしたURLをペーストして実行します。

image

ここで、画面上は見えませんが、以下のJavaScriptが起動されています。

<script>document.cookie=”PHPSESSID=27898lqtkjjfup9hoi4dskt204; domain=wsxw.info”;</script><a href=”http://fix.wsxw.info”>ログイン</a>

このスクリプトはxss.wsxf.info上で動いていますが、domain=wsxf.info上のPHPSESSIDクッキーをセットすることで、fix.wsxw.infoにも有効なセッションIDを佐藤さんのブラウザ上で設定できたことになります。

次に、佐藤さん(実はあなた)は「ログイン」というURLをクリックします。あなたは佐藤さんなので、自分のIDとパスワードを正しく入力します。

image

「送信ボタン」を押すと当然ながらログインに成功します。

image

ここで、セッションIDに注目して下さい。先ほどの攻撃者のChrome上で表示されていたセッションIDと同じです。攻撃者がXSS攻撃で設定したセッションIDが、そのまま有効になっています。

このセッションIDは、攻撃者が「知っている」内容なので、セッションハイジャックが可能です。再び攻撃者の立場になって、Chromeの表示を見ましょう。

image

セッションIDが同じなので、攻撃者は佐藤さんの個人情報を閲覧できるはずです。「個人情報」をクリックします。

image

たしかに、攻撃者のブラウザ上で、佐藤さんの個人情報を盗み見することができました。セッションフィクセイション攻撃の成功です。

セッションアダプションは使っていない

このデモに用いているPHPは、大垣さん作成の「Strict Sessionパッチ」が適用されています。それは、phpinfo()の表示からも確認することができます。

http://fix.wsxw.info/phpinfo.php

image

session.use_strict_modeがOnになっており、厳密なセッション管理が有効であることが分かります。

セッションアダプションとセッションフィクセイション

ここまで、セッションアダプションとセッションフィクセイションという用語を説明しておりませんでした。

セッションアダプションとは、外部で勝手に作成したセッションIDをPHPが受け入れてしまう問題です。通常配布されているPHP処理系は、あらかじめPHPSESSID=ABC12345などと適当に決めたクッキーをセットしておくと、PHPはそのセッションIDを受け入れ、自動的にセッションIDを振り直すことはしません。

一方、セッションフィクセイション攻撃とは、上記で説明したように、何らかの方法で第三者(被害者)のセッションIDを強制しておいて、被害者がログインした頃を見計らって、攻撃者がセッションハイジャックするという攻撃手法です。

上記のセッションフィクセイションの攻撃シナリオでは、セッションアダプションは使っていません。その代わりに、攻撃者は、攻撃対象サイトに先にアクセスして、「有効なセッションID」を取得し、それを被害者のブラウザにセットしています。元々が、攻撃対象サイトが発行したセッションIDなので、PHPはそのまま当然のように受け入れます。

つまり、セッションフィクセイション攻撃を防ぐためには、セッションアダプションを取り除いただけでは駄目だということになります。これが、このデモで言いたかったことです。

まとめ

セッションアダプションを使わないで、セッションフィクセイション攻撃をするデモを紹介しました。仮に、セッションアダプションがある通常のPHPであれば、「予め有効なセッションIDを取得する」というステップを省略して、適当なセッションIDを用いて攻撃することができます。このため、セッションアダプションがあれば攻撃の手間は少なくてすみます。

しかしながら、セッションアダプションがあってもなくても、攻撃の手間が少し変わるだけで、攻撃ができなくなるわけではありません。このため、セッションアダプションの有無に関わらず、セッションフィクセイション攻撃の対策は必要です。そのためには、ログイン成功直後に以下を実行するとよいでしょう。

session_regenerate_id(true);

これにより、ログイン後のセッションIDは変更され、攻撃者の「知らない」セッションIDになります。そのため、セッションハイジャックを防ぐことが可能となります。

  1. sonodamockeghemからリブログしました
  2. act2012blatm09tdからリブログしました
  3. atm09tdockeghemからリブログしました
  4. sendockeghemからリブログしました
  5. sunpe78ockeghemからリブログしました
  6. bgnori-technologyockeghemからリブログしました
  7. ts-asano-codesockeghemからリブログしました
  8. ts-asanoockeghemからリブログしました
  9. samaiockeghemからリブログしました
  10. ockeghemの投稿です
Google