プライバシーポリシー

2013年6月25日火曜日

SQLインジェクションゴルフ - なんと3文字で認証回避が可能に

昨日のエントリ「SQLインジェクションゴルフ - 認証回避の攻撃文字列はどこまで短くできるか?」にて、認証回避の攻撃文字列が5文字にできる(「'OR'1」)ことを示しましたが、@masa141421356さんと、やまざきさん(お二人とも拙著のレビュアーです)から、idとpwdにまたがった攻撃例を示していただきました。やまざきさんの例は、MySQL限定ながら、なんと3文字です。これはすごい。

@masa141421356さんの攻撃例

@masa141421356さんのツイートを引用します。
ここで「長さ0の文字列がNULL扱いされ」るDBというのはOracleを指します。出題ではMySQLとPostgreSQLを対象としていてどちらも「長さ0の文字列がNULL扱い」しないので、5文字パターンでいけます。すなわち、idに「'OR」、pwdに「>'」です。この場合のSQL文は下記となります。

SELECT * FROM users WHERE id =''OR' AND pwd = '>''

このままだと分かりにくいので、WHERE句の式を以下にわかりやすく示します。

id =''  OR  ' AND pwd = ' > ''

これは、列idが空文字列(長さ0の文字列)か、文字列「 AND pwd = 」が空文字列よりも大きい場合となりますので、後者が必ず真で、WHERE句は常に成立することになります。
第1のパラメータでリテラルを終端して、途中の式を文字列リテラルの中に入れてしまっていますね。これはXSSではよくやる方法ですが、SQLインジェクションに応用した例は珍しい気がします。

やまざきさんの攻撃例

次に、@ymzkei5さんのツイートです。
idに「'」、pwdに「|'」の計3文字です。この場合のSQL文は下記となります。

SELECT * FROM users WHERE id =''' AND pwd = '|''

WHERE句を分かりやすく表示すると以下の通りです。

id =''' AND pwd = ' | ''

青地の中は、「' AND pwd = 」ですね。これと '' (空文字列)とで、| (ビット単位の論理和)の演算をしています。この結果は 0 になります。
mysql> select ''' AND pwd = '|'';
+--------------------+
| ''' AND pwd = '|'' |
+--------------------+
|                  0 |
+--------------------+
1 row in set, 2 warnings (0.00 sec)
なぜ0になるかというと、MySQLは数値が要求される文脈に文字列があった場合は数値(浮動小数点数)に暗黙の型変換され、数値として正しくない文字列の場合は 0 になるからです。すなわち、| の左右のオペランドは、どちらも 0 になります。

この結果、先のSQL文は、「SELECT * FROM users WHERE id=0」と同じです。これを実行してみましょう。
mysql> SELECT * FROM users WHERE id=0;
+--------+--------+
| id     | pwd    |
+--------+--------+
| tanaka | a2f9hy |
| yamada | sn6s3n |
+--------+--------+
2 rows in set, 2 warnings (0.00 sec)
つまり、'tanaka'=0と解釈されているわけですが、MySQLの場合(他のDBもですが)、文字列と数値の比較の場合、暗黙に文字列を数値に変換してから比較します。そして、MySQLに限り、数値に変換できない文字列は 0 に変換するからです。この結果、'tanaka' = 0 は真になります。
やまざきさんの解は、MySQLの「暗黙の型変換」の仕様を巧妙に利用したものと言えます。

まとめ

昨日紹介したSQLインジェクションゴルフの解答例として、@masa141421356さんとやまざきさんの解答を紹介しました。どちらの解も、SQL文の一部を文字列リテラルに閉じ込めるという技を披露してくださっていて、興味深いものです。特に、やまざきさんの3文字解には脱帽です。
同時に、あらためてSQLの暗黙の型変換は危険だなとも思いました。暗黙の型変換の危険性については、以前の拙稿「SQLの暗黙の型変換はワナがいっぱい」を参照下さい。

2013年6月24日月曜日

SQLインジェクションゴルフ - 認証回避の攻撃文字列はどこまで短くできるか?

コードゴルフという競技があります。与えられた問題(例えばFizzBuzz)を解くコードを、いかに短いプログラムで実現できるかというものです。
脆弱性の世界でもXSS Golfというものは既にあるようで、我らが はせがわようすけ氏にも、「短いXSSの話」というプレゼン資料が公開されています。第2回のOWASP Japanローカルチャプターミーティングでの講演ですね。これ、面白いので、まだ見ていない方はぜひご覧になって下さい。

XSSがあるならSQLインジェクションはどうかということで、ちょっと考えてみました。この手の遊びは、問題のルールが命というというところはありますが、最初なのであまり厳密に考えずにだらだらとやってみます。

攻撃対象プログラム

やはり、SQLインジェクション攻撃でみなさまおなじみの認証回避がよいのではないかと思いました。拙著「体系的に学ぶ 安全なWebアプリケーションの作り方」P123にSQLインジェクション攻撃で認証回避されてしまうスクリプトを紹介しましたが、以下に、PDOで書き換えたものを示します。
<?php
  header('Content-Type: text/html; charset=UTF-8');
  $id = $_GET['id'];   // ユーザID
  $pwd = $_GET['pwd']; // パスワード
  // データベースに接続
  $dbh = new PDO('pgsql:dbname=wasbook host=localhost', 'wasbook', 'wasbook'); // Postgres用
  //$dbh = new PDO('mysql:dbname=test', USERNAME, PASSWORD');   // MySQL用
  // 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 'ログイン成功です';
  } else {
    echo 'ログイン失敗です';
  }
  $dbh = 0;
?></body>
</html>
テーブル users は以下のような感じで。
CREATE TABLE users (id varchar(10) NOT NULL PRIMARY KEY,  pwd varchar(10) NOT NULL);
INSERT INTO users VALUES ('yamada','sn6s3n');
INSERT INTO users VALUES ('tanaka','a2f9hy');

認証回避の基本形

拙著で紹介している認証回避のための攻撃文字列は以下の通りです。
' or 'a'='a
空白まで入れて11文字ですが、空白は不要なので除去すると9文字ですね。以下のように確認できます。「=」はパーセントエンコードして「%3d」と入力しています。


SQLコメントを使う

短い攻撃コードという目的には、SQLコメントを使う方法があります。なりすまし対象のログインIDが分かっているとすると、MySQLの場合、以下のように、idを「yamada'#」としてログインできます。MySQLは「#」から行末までがコメントとして認識しますから、パスワードの照合が無視されます。


次にPostgreSQLの場合。「#」 の代わりに、「--」をコメント開始記号として使用します。MySQLも「--」をコメントとして使えますが、MySQLの場合は「--」の後に一文字以上の空白が必要です。


コメントを使う場合の文字数は、MySQLの場合は2文字「'#」、PostgreSQLの場合は3文字「'--」となります。ただし、ログインIDまで文字数に含めるとすると、それぞれ8文字と9文字になります(なりすまし対象のログインIDが6文字の場合)。

あくまで論理和にこだわる

次に、あくまで論理和にこだわる場合を考えます。実は「OR 'a'='a'」という式は結構冗長でして、ORの右側(右オペランド)はとにかく真(true)の値をとればいいわけです。例えば、1=1が考えられますが、この場合、シングルクォートが余ってしまうのでコメントを使う必要があります。
SELECT * FROM users WHERE id ='' AND pwd = ''OR 1=1#'
上記の場合、攻撃文字列は「'OR 1=1#」で8文字となります。PostgreSQLの場合は「'OR 1=1--」で9文字です。元の9文字と比べて短くなっているとは言い難いですね。

できるだけ短い文字数の真値を探す

1=1よりもさらに短くすることはできないでしょうか。ここから先はデータベースの仕様によって変わります。
MySQLの場合、ゼロでない数値(1など)や、ゼロでない数値に変換される文字列('1'など)が暗黙の型変換で真値になります。これを利用して、以下の攻撃文字列が可能です。
  • 'OR 1#   (6文字)
  • 'OR'1     (5文字)
PostgreSQLの場合、数値から論理値への暗黙の型変換は認められないようですが、文字列から論理値への暗黙の型変換はできるようです。以下は、論理値を必要とする文脈で、暗黙に TRUE に変換されます。
  • '1'
  • 'TRUE'
  • 'TRU'
  • 'TR'
  • 'T'
  • 't'
以下は、暗黙に FALSE に変換される例です。
  • '0'
  • 'FALSE'
  • 'FALS'
  • 'FAL'
  • 'FA'
  • 'F'
  • 'f'
以下は、論理値が必要な文脈ではエラーになります。
  • 1
  • 'a'
  • 'truex'
この仕様を利用(悪用)すると、以下の攻撃文字列ができます。
  • 'OR'1   (5文字)
  • 'OR't    (5文字)
「'OR't」を指定した場合のSQL文は下記となります。
SELECT * FROM users WHERE id ='' AND pwd = ''OR't'

さらに短くできないか

以上の説明のように、認証回避の攻撃文字列を5文字まで短縮することができましたが、さらに短くできないでしょうか。例えば、MySQLにはビット論理和を求める演算子 | (1文字!)がありますが、これを使えないでしょうか。
mysql> SELECT * FROM users WHERE 0 | '1';
+--------+--------+
| id     | pwd    |
+--------+--------+
| tanaka | a2f9hy |
| yamada | sn6s3n |
+--------+--------+
2 rows in set (0.00 sec)
論理値が必要な文脈でビット演算を用いること自体は問題ないですね。
でも、ダメです。
mysql> SELECT * FROM users WHERE id='' AND pwd=''|'1';
Empty set, 2 warnings (0.00 sec)
なぜかというと、演算子の優先順位が理由です。以下は、MySQLの演算子の優先順位のまとめです(参考)。


上手のように、ビット論理和演算 | は、比較演算子 = よりも優先順位が高くなっています。このため、先のSQL文は下記のように解釈されます。

SELECT * FROM users WHERE id='' AND pwd=(''|'1');
(''|'1')の結果は 1 となるため、上記のWHERE句は、id=''AND pwd=1 ということで、認証回避にはなりません。

まとめ

SQLインジェクションゴルフということで、認証回避のSQLインジェクション攻撃文字列をどこまで短くできるかについて検討しました。もっと短くできる方法を見つけた方はぜひ教えて下さい。
また、認証回避だと問題が簡単すぎるきらいがありますので、もっと面白い想定があったらよいなと思います。こちらも、良いアイデアがあれば発表して、皆で楽しみましょう。
SQLインジェクションゴルフの実用的な価値はあまりないと思いますが、強いて言えば下記があげられます。

  • 文字数制限があって脆弱性の影響がないと言い張る人の論破
  • IPSやWAFの回避技術や、回避技術の対抗策の検討



2013年6月21日金曜日

LinkedInでDNSハイジャックの可能性

昨日LinkedInでアクセス障害があり、DNSハイジャックの可能性を指摘されています。
app.netの共同創設者、Bryan Berg氏はその原因を「DNSハイジャック」によるものではないかと指摘している。Berg氏は、「その間LinkedInにアクセスしたユーザーのトラフィックは、Confluence-Networksがホスティングしていたネットワークに送信されていた」と述べ、しかもサイトではSSLを利用していなかったことから、長い有効期限が設定されていたCookieが平文のまま送信された可能性があるとしている。
LinkedInでアクセス障害、原因はDNSハイジャックとの指摘 - @IT より引用

DNSハイジャックとは

DNSハイジャックとは、ドメイン名を管理するネームサーバーを乗っ取られることですが、具体的には以下のような状況が考えられます。以下の例では、モデルとしてドメイン名example.jpを使います。
  • example.jpの権威DNSサーバー(レンタルDNSサーバー含む)が不正アクセスされた(脆弱性の例
  • example.jpのレジストラのコントロールパネルが不正アクセスされた(他国の例
  • JPドメイン名のレジストリ(JPRS)が不正アクセスされた(他国ではまれにあります; 参考
  • example.jpの管理者がドメイン情報の設定を間違えた(たまにあります)
このうち、レジストラに対する不正アクセスは時々見かけますので、以下、このケースについて説明します。下図は、www.example.jpがDNSハイジャックされる様子を説明するために、まず正常時の状況を図示したものです。


この状況で、example.jpの架空のレジストラ「おネーム.com」(仮に類似の名前のレジストラがあったとしても偶然に過ぎません)のコントロールパネルに侵入され、example.jpの権威DNSサーバーを書きかえられると、下記の状況になります。


evil.example.comは、攻撃者が管理するDNSサーバーです。この状況では、攻撃者はexample.jpのDNS設定を自由に変更できるので、www.example.jpのAレコードを192.0.2.5(攻撃者が管理するWebサーバーのIPアドレス)に変更します。これがDNSハイジャックです。

2010年11月には、著名なデンマークのセキュリティ企業Secuniaが、レジストラDirectNICが攻撃を受けた影響で、ウェブサイトの表示を改ざんされた事件が起こっています(参考参考)。

DNSハイジャックの影響

DNSハイジャックされると以下の影響があり得ます。
  • 秘密情報の漏洩
  • コンテンツの書き換え
  • サービス停止(今回のLinkedInでも起こった)
  • なりすまし
すなわち、セキュリティ上の悪いことは全てあり得るという状況です。
上記の例で説明すると、www.example.jpへのリクエストには、このサイトのCookieが付与されるため、利用者がアクセスした瞬間に、Cookieが漏洩することになります。これは、冒頭に紹介した記事でも言及されています。
さらに積極的に、フィッシングのテクニックによりログイン情報を収集することもできます。正規のドメイン名を悪用されるので、見分けるにはSSL証明書のエラーの他にはないわけですが…LinkedInのトップ画面を確認してみましょう。

なんということでしょう! 平文のトップページにログインフォームが設置してあります。これでは、DNSハイジャックによる偽画面を見分ける術がありません。『SSLを入力画面から使用しないのはそろそろ「脆弱性」と判断してしまってよいころかも』は高木浩光氏の2005年11月の記事ですが、それから約7年半以上たつのに、著名サイトでこのような状況は困ったものです。

情報漏洩やコンテンツ書き換えのシナリオとして、偽のWebサーバーが本物サイトのリバースPROXYとして動く仕組みも考えられます(下図)。


この状況ですと、利用者の通信(リクエストおよびレスポンス)はすべて傍受されます。中間者攻撃(MITM)という奴ですね。攻撃者は盗聴に徹することもできますし、iframe要素やscript要素を埋め込んで、利用者の端末にマルウェア感染させることもできます(利用者の端末に脆弱性がある場合)。

対策

DNSハイジャックの根本対策は、DNS運用を見直すこと、信頼の置けるレジストラ(どこ?)と契約するくらいでしょうが、私はDNSの専門家ではないので、具体的には専門家の解説にゆだねたいと思います。
Webサイト側でとれる緩和策としては、SSLの運用があります。
  • 少なくとも入力フォームからSSLとする
  • サイト全体をSSLとする(いわゆる常時SSL)を検討する
  • 機密性の要求されるCookieにセキュア属性を付与する
GoogleやTwitterは常時SSLに移行していますし、今後この流れが進むのではないでしょうか。
徳丸は今年の6月13日以降下記を実施しています。
後者のDNS情報の監視ですが、TLDから当該ドメイン名などのツリーから監視項目を定め、別サーバーから定期的に監視するようにしています。このままですと、監視システムが動いているか不安になるので、テスト用のドメイン名についても監視して、たまに人為的にDNS設定を変更して、検知されることを確認しています。

まとめ

LinkedInのアクセス障害がDNSハイジャックである可能性を受けて、DNSハイジャックの脅威について説明しました。
DNSに対する攻撃は意外に頻繁に発生しており、Webサイト管理者が想定しておかなければならない脅威と言えます。すぐにとれる対策としては、SSLの使用状況を見直すことが挙げられます。

2013年6月20日木曜日

Yahoo!ジャパンの「秘密の質問と答え」に関する注意喚起

昨日の福井新聞の報道魚拓)によると、中学生がYahoo!の「秘密の質問と答え」を悪用して同級生のYahoo!アカウントにログイン成功し、不正アクセス禁止法などの疑いで書類送検されたようです。
同課によると、同級生との間には当時トラブルがあり、男子生徒は「自分の悪口をメールに書いているのではないか」と考え、盗み見たという。
男子生徒は、パスワードを再設定しようと「秘密の質問」のペットの名前に何度か答え、合致しパスワードを変更した
ログインできなくなった同級生がパスワードを変更し直したが、男子生徒は再びパスワードを変更したという。同級生が「身に覚えのないログインがある」と警察に相談し、容疑が明らかになった。
不正アクセスで県内中学生を初摘発 容疑で県警、同級生のメール盗み見 より引用(赤字は引用者)
後述するように、Yahoo!の「秘密の質問と答え」を知っていると強大な権限が与えられたことになり注意が必要です。以下、Yahoo!の「秘密の質問と答え」の利用に対して、注意喚起を致します。

「秘密の質問と答え」とは何か

Yahoo!では、パスワード等を忘れた際のリカバリー方法として、メールを用いる方法、秘密の質問と答えを用いる方法、クレジットカード番号を用いる方法の3種類が用意されています。
 以下は、秘密の質問と答えの登録画面です。


秘密の質問と答えの問題点

Yahoo!の「秘密と質問と答え」を知っている人には、後述するように、当該アカウントに対して強大な権限が与えられますが、その権限と不釣り合いに下記の問題があります。
  • 1度登録すると、取り消しも変更もできない(但し例外あり…後述)
  • 登録時に、秘密と質問と答えが重大な影響をもたらすことを説明していない
  • 「あなたしか知らない質問と答え」とあるが、質問は選択制なので利用者が自由に記述できない
  • 質問の選択肢には、「父親の出身地」、「卒業旅行で行った場所」、「1番年上のいとこの名前」、「初めて勤めた会社の場所」など、第三者が知っている可能性の高いものが多い

秘密の質問と答えでどこまでできるか

Yahoo!アカウントの秘密の質問と答えが重大な影響があると書きましたが、具体的には「秘密の質問と答え」と生年月日の組み合わせにより、以下が可能です。
  • パスワードのリセット(再設定)
  • ワンタイムパスワードの解除
  • シークレットIDの解除
  • アカウントロックの解除

ケーススタディ

ここで、架空のYahoo!利用者Aさんに登場いただきます。Aさんは、Yahoo!を熱心なユーザであり、Yahoo!の以下のセキュリティ機能を登録しています。
  • ワンタイムパスワード
  • シークレットID
  • ログインアラート
  • ログインシール
これらは、「もっと安全ガイド - Yahoo! JAPAN IDガイド」に紹介されたセキュリティ機能のうち、ユーザが設定できるもの全てです。「Yahoo!セキュリティ機能全部入り」という感じでしょうか。

 一方、Aさんは「秘密の質問」として、「小学生の頃のあだ名は?」を選択し、答えを「とくちゃん」にしていました。

ここで、Aさんの子供時代を知るX氏が登場します。X氏は、AさんのYahoo!ID、生年月日と「とくちゃん」なるあだ名を知っています。X氏はAさんのアカウントに不正ログインしようとします。詳細は割愛しますが、以下の手順で可能です。
  • X氏は秘密の質問と答え、生年月日により、シークレットIDを解除する(ヘルプ)
  • X氏は秘密の質問と答え、生年月日によりパスワードをリセットする(ヘルプ)
  • X氏がリセットしたパスワードでログインしようとするとワンタイムパスワードを問われる
  • X氏は秘密の質問と答え、生年月日により、ワンタイムパスワードを解除する(ヘルプ)
  • X氏は再度、リセットしたパスワードでログインを試し、今度は成功する
Yahoo!自慢のセキュリティ機能三点セットが全て秘密の質問と答えと生年月日で解除されてしまい、まんまとログインできることを確認済みです。上記を解除する実験に際しては、リスクベース認証による保護の可能性も検証するため、端末のOS、ブラウザ、ISPなどを全て変えて試しましたが、とくに支障なく解除できました。

この時点でAさんがログインアラートにより不正ログインに気づき、ログインアラートの機能の1つであるログインロックを実行しました。
すると、X氏はいったんはログイン解除されますが、慌てず騒がず、以下を実行します。
  • X氏は秘密の質問と答え、生年月日により、ログインロックを解除する(ヘルプ)
つまり、Yahoo!のパスワードおよび追加のセキュリティ機能は全て「秘密の質問と答え」および成年月日により解除ないし再設定できるのです。この段階で、Aさん、X氏の両方が「秘密の質問と答え」と生年月日を知っているため、どちらもAさんのYahoo!アカウントにログイン可能な状態が続きます。AさんはYahoo!に連絡して対処してもらうしかなさそうですが、ヘルプを見ても、どこに連絡すればよいのか分かりませんでした。ヘルプからお問い合わせフォームにはリンクされていますので、ここから問い合わせるくらいでしょうか。

 「秘密の質問と答え」で上記解除ができることは、秘密でも何でもなく、Yahoo!の仕様であり、オンラインヘルプにすべて書いてある内容です。

「秘密の質問と答え」の問題を避ける方法はあるか?

秘密の質問が推測可能、あるいは何らかの方法で漏洩した場合、Yahoo!のセキュリティ機能は無力になってしまいます。朝日新聞の報道魚拓)によると、Yahoo!のアカウント情報漏洩事件で「秘密の質問と答え」は漏洩した可能性があり、暗号化されていなかったとのことですので、これは現実的な脅威です。いくらなんでもYahoo!が同じ失敗をすることはないだろうと期待したいところですが…
 サイトからの漏洩に対しては利用者が取れる対策はありませんが、上記のように、知らずに良くない「秘密の質問と答え」をつけている利用者も多いと予想されます。ここでは、既に良くない「秘密の質問と答え」をつけている場合の対策について説明します。

Yahoo!ウォレットに登録すれば秘密の質問と答えは変更できる

Yahoo!アカウントの「秘密の質問と答え」は原則的には変更できないのですが、1つ方法があり、以前Yahoo!に問い合わせて教えて頂きました。その経緯は、「Yahoo!の『秘密の「質問」と「答え」』の変更方法 - 徳丸浩のtumblr」に書きました。ただし、条件があります。
  • 「Yahoo!ウォレット」に登録していること
  • 免許証あるいは住民票のスキャンデータを送信すること
Yahoo!ウォレットへの登録自体に費用は掛かりませんが、クレジットカードか銀行口座を登録する必要があります。銀行については、ジャパンネット銀行のみオンラインで登録できるようで、その場合は認証にジャパンネット銀行のセキュリティトークンを用います。利用者の認証は、本人確認書類をYahoo!のオペレーターが目視確認するのだと思います。
この方法も裏技ではなく、マニュアルに書いてあるものですが、本来は、Yahoo!の有償サービスを使っているのにパスワードが分からなくなったという状況で使用する機能と推測されます。
この方法の問題は、Yahoo!ウォレットに登録するためにクレジットカード番号を登録しなければならないことで、「リスクを増やしてどうする!」というツッコミがありそうです。

Yahoo!アカウントを作り直す

Yahoo!の過去の履歴を捨ててもよいという場合は、Yahoo!の現在アカウントを破棄し、新しいアカウントを作り直すという方法もあります。確認したところ、現状のYahoo!の仕様では、アカウント登録時に「秘密の質問と答え」の登録は必須ではありません。この辺の仕様は時々変わるようで、以前試したときは、アカウント登録時に「秘密の質問と答え」が必須だったように記憶します。

 「秘密の質問と答え」を登録しない状態でも、Yahoo!の大部分の機能は使えますが、私が試した範囲では、ワンタイムパスワードの登録時に「秘密の質問と答え」の登録が強制されるようです。すなわち、以下の選択を迫られます。
  • 秘密の質問と答えを登録せず、ワンタイムパスワードは諦める
  • 秘密の質問と答えを登録して、ワンタイムパスワードを使う
  • 秘密の質問と答えを登録して、ワンタイムパスワードは使わない
上の2つは「究極の選択」という趣ですね。ワンタイムパスワード(2段階認証)単体でみると安全性が高まることは確実ですが、その代わりに漏れなく「秘密の質問と答え」の登録が必要になります。「秘密の質問と答え」が漏洩するリスク、推測されるリスクが生じます。

 私はYahoo!の内部や今後の計画は知らないので、上記の優劣を決めることはできません。ただし、シークレットIDとパスワードの両方を十分長いランダムな文字列にすれば、ワンタイムパスワードなしでも十分安全性は保てるはずで、後はフィッシングの被害にあう可能性などを考慮して検討頂くしかないと思います。

ログインアラートの問題点

ログインアラートのデフォルト設定は、「注意が必要なログイン時のみ通知」となっていますが、この設定でテストしたところ、「秘密の質問と答え」によるパスワードリセットでは、ログインアラートは通知されませんでした。設定を「ログイン時は常に通知」にすると、ログインアラートが通知されます。

ログインアラートは一種のリスクベース認証(ただし通知のみ)と考えられますが、リスクと認定する基準が少し緩めに設定されているのではないかと思いました。今回の実験ではISPなどは変えて「不正アクセス」していますが、同じ日本からのログインなので、国を変えるなどすれば「注意が必要」と認定されるのかもしれません。しかし、Yahoo!サービスの特性上、「ヤフオクの詐欺に使うためのアカウント乗っ取り」などは、日本国内で行われそうで、リスクベース認証が有効に働かないかもしれません。
ログインアラートの設定を「ログイン時は常に通知」にすれば、当然ながら、パスワードリセット後のログインで通知されるようになります。アラート例を以下に示します。
上記のログインに心当たりがない場合は、以下をご確認ください。
■心当たりのないログイン、利用であった場合

 1. 「ログイン履歴」と「登録情報」に心当たりがない情報がないかご確認ください。

  ◇ ログイン履歴
    https://lh.login.yahoo.co.jp/

  ◇ 登録情報ページの見方
    http://help.yahoo.co.jp/help/jp/edit/edit-54.html

 2. 心当たりがない情報があった場合は、下記のURLにアクセスし、一時的にログインできない状態に設定すること(ログインロック)をおすすめします。

  ◇ ログインロック    https://login.yahoo.co.jp/alert/lock?.ea=wOlemehXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-
    ※URLの有効期限:2013/06/09 12:14:37
これ、「■心当たりのないログイン、利用であった場合」の選択肢なのに、まず『1. 「ログイン履歴」と「登録情報」に心当たりがない情報がないかご確認ください。』と進めていますが、悠長な感じです。不正アクセスされて、パスワード変更された場合は、ログイン履歴も確認できないわけです。
だから、心当たりのないログインが来た場合は、さっさとログインロックしたくなりますが、今度は自分もログインできなくなるので、ログインロックは使い方が難しいと思いました。

私がユーザの立場で、心当たりのないログインがあったら以下のようにすると思います。
  1. まずは普通にログインする
  2. ログインできたら、不正アクセスの可能性を考慮してパスワードを変更する
  3. ログインできなかった場合パスワードリセットする(結果としてパスワードは変わる)
  4. ログイン履歴から、本当に不正アクセスかどうかなどを調べる(勘違いという可能性もある)
  5. IPアドレス、アクセス元の国などからその後の対処を決める
それでは、アカウントロックは役に立たないかというと、出先などで上記がすぐにできない場合に、とりあえずロックしておく、という使い方はありそうです。

パスワード変更通知の問題点

「秘密の質問と答え」による不正アクセスの過程では、パスワード変更を伴うため、パスワード変更の通知は来ます。このメールには下記のように書かれています。
あなたが上記のYahoo! JAPAN IDでパスワード変更をしたおぼえがない場合
=================================================================
自分のパスワードでYahoo! JAPANにログインできるかどうかを確認してください。
ログインできない場合は、お手数ですが、下記のヘルプをご確認ください。
http://help.yahoo.co.jp/help/jp/edit/edit-63.html
不正アクセスの場合は、「パスワード変更をしたおぼえがない場合」に該当するわけですが、その割にはのんびりした文面になっています。ユーザーに不安感を持たせない配慮かもしれませんが、自分のアカウントが勝手にパスワード変更されている状況は不正アクセスがまず疑われるわけで、電話やメールによる確認がしたいところですが、問い合わせ先は書いてありません。
メールからリンクされたヘルプには以下のような文面があります。
「パスワード変更の確認」メールは、パスワード変更を行うと、Yahoo! JAPAN IDの登録メールアドレスあてに、自動的に送信されます。
■確認メールの本文に記載されたYahoo! JAPAN IDをお使いの場合
メールに心あたりがない場合、念のため、こちらからお使いのYahoo! JAPAN IDとパスワード(※)を入力して、問題なくYahoo! JAPANにログインできるかをお試しください。
※メールに記載されているパスワードではなく、普段お使いのパスワードを入力してください。
  • ログインできなくなった場合は、パスワードを再設定し、再度ログインをお試しください。
    再設定方法は「パスワードを忘れてしまった」をご覧ください。
  • 万が一、第三者に利用されている可能性がある場合は、こちらをご覧ください。
最後の「こちら」のリンク先は、ご覧になるとわかりますが、被害にあった場合の一般論の説明で、Yahoo!の問い合わせ窓口が書いてあるわけではありません。

結局どうすればよいか

利用者としてとれる対策は下記の通りです。
  • 「秘密の質問と答え」は乱数のような文字列を設定して、印刷したものを安全な場所に保管する
  • 既存の「秘密の質問と答え」が安全でない場合は、前述の方法で再設定依頼するか、アカウントを作り直す
  • 新規にアカウントを作成する場合は、「秘密の質問と答え」を設定しない運用も検討する

まとめ

Yahoo!の「秘密の質問と答え」に関するリスクと対処について説明しました。現在のところ、「秘密の質問と答え」の権限が大き過ぎて、あまり良い対策がないのが実状です。 「秘密の質問と答え」の設定は十分注意頂き、たとえば、質問に関係ない乱数で設定するというのも1つの方法です。

なお、本稿に書いたパスワードリセットなどを他人のアカウントに対して試す行為は、不正アクセス禁止法などの違法行為となりますので、絶対にしないで下さい。冒頭に述べたように、逮捕者(書類送検された人)も出ています。

2013年6月18日火曜日

多発するWeb改ざんに備えてinotifywaitによる改ざん検知を導入した

Webサイトの改ざん事件が多発しています。Webサイトに対する基本的なセキュリティ施策を実施していればまず被害にあうことはないとは思うものの、全ての手口が公開されているわけではないので、何となく「嫌な感じ」もします。

【参考】
当方のサイト(会社個人)は、一通りのセキュリティ施策は実施しているつもりですが、絶対に改ざんされないかというと、改ざんされることは想定しておかなければならないと考えています。

当方のセキュリティ施策の例
  • FTPをやめ、sshのみで管理運用
  • sshのパスワード認証を禁止し、鍵認証のみとする
  • sshサーバーのIPアドレス制限
  • 脆弱性管理
上記のセキュリティ施策を講じていても、例えば以下のような侵入シナリオが考えられます。
  • サイトの管理用PCがゼロデイ脆弱性でマルウェアに感染し、管理用PCを踏み台として、管理用PCに保存された秘密鍵によりsshからログインされる
  • サーバーソフトのゼロデイ脆弱性により侵入される
  • VPSのコントロールパネルに脆弱性がある場合、コントロールパネルに侵入され、シングルユーザーモードからrootパスワードを変更された後、コントロールパネルのリモートコンソールからログインされる
私自身としても、サイトに侵入されてしまうかもしれないという想定は心情的には受け入れにくいものではありますが、冷静に考えれば侵入されるという事態はあり得るわけで、仮に侵入された場合に素早く対処できる施策を施しておきたいと考えるようになりました。と言っても、何分にも個人経営のサイトですので、掛けられる予算も限られています。そこで、無償で利用できる改ざん検知ツールについて検討しました。
検討したツールは以下の通りです。
  • Tripwire(オープンソース版)
  • inotifywait
実際には両方を導入して運用していますが、本稿ではinotifywaitについて報告します。

inotifywaitによる改変検知

Linux 2.6.13から、ファイルシステムのイベント監視APIとして、inotifyが組み込まれています。これを利用して、ファイルの改変検知を行うことにしました。inotifyを簡単に利用するためのコマンドとしてinotifywaitがあり、Ubuntuの場合下記によりインストールできます。
$ sudo apt-get install inotify-tools
inotifywaitを用いて、/etc以下を監視する場合の起動例を下記に示します。
$ sudo inotifywait -m -e create,delete,modify,move,attrib --format '%T %w %f %e' -r --timefmt '%F %T' /etc
オプションパラメータは以下の通りです。

-mイベント後も継続する
-rディレクトリを再帰的に監視する
-e監視するイベントを指定
-format出力形式を指定
-timefmt時刻の表示形式を指定

この状態で、以下のように、/etc以下にファイルを作成してみましょう。
$ sudo touch /etc/xxxxx
以下の出力が得られます。
2013-06-16 22:36:57 /etc/ xxxxx CREATE
2013-06-16 22:36:57 /etc/ xxxxx ATTRIB
inotify(inotifywait)はリアルタイムに上記の表示が得られます。一方、オープンソース版のTripwireは定期的なバッチ処理による監視なので、リアルタイム性はありません。

ファイル改変の監視対象は以下としました。
  • /etc/ 以下の設定ファイル
  • バイナリ
  • Webコンテンツ(.htaccess等含む)
  • その他
これらのディレクトリにおける、ファイル新規作成、更新、削除、移動、属性変更が起こる度にメール通知するスクリプトを書きました。inotifywaitはリアルタイムにファイルに対するイベントを監視できますが、イベントの度にメールを送信すると、1度に何通ものメールが送信されるのでうれしくありません。そこで、こちらを参考にして、イベント発生後5秒の間に発生したイベントをまとめてメール通知しました。参照したエントリはシェルスクリプトによる方法を紹介していますが、私はPerlにより記述して、デーモンとして常駐させています。

攻撃側の対抗策として、侵入に成功後 inotifywait プロセスを止めてしまうというシナリオも考えられます。そこで、inotifywait の死活監視も実施することにしました。inotifywaitを呼び出すPerlスクリプトから、定期的にハートビートのメールを別サーバーに送信し、一定時間メールが来ない場合、別サーバーからメール通知するようにしています。

効果・まとめ

inotifywaitによるリアルタイム改ざん検知の導入について報告しました。
導入の効果ですが、改ざんのことは忘れて他の業務に専念できる点が大きいと思いました。また、tripwire(オープンソース版)によるバッチの改ざん検知と比べてCPU負荷が軽いのもメリットです。

IPAの注意喚起では、Webコンテンツの改ざん有無をチェックするように呼びかけており、具体的な手段としては、(1)原本との比較、(2)セキュリティソフトによるスキャン、(3)FTPアクセスログの確認、という3種類の方法を紹介しています。これら手法は、一般的なツールだけで実現可能という理由から採用されたものだと思いますが、確実性や即時性という点で課題があります。リアルタイムにファイルの改変を直接監視することで、コンテンツが改ざんされていないという安心を得ることができます。
導入前は、誤検知(フォルス・ポジティブ)を心配していましたが、運用上問題ないレベルだと思います。ただし、これは私が一人で運用しているからであって、コンテンツを更新する人と監視をする人が別の場合は、運用ルールを定めないと、「コンテンツが変更されたが、正規の更新か、攻撃か分からない」という事態も起きそうです。

トータルで見て、小規模な企業ホームページなどで、多大な費用を掛けずに実施できるセキュリティ施策として、ファイル改ざん検知は有望な方法だと感じました。

※18:55修正 CPU負荷について追記、タイトルを微修正

2013年6月11日火曜日

360webscan攻撃(仮称)を観測しました

本日、HASHコンサルティング株式会社セキュリティ・オペレーション・センター(HASH-C SOC)では、奇妙な攻撃リクエストを観測しました。それは、以下のようなURLによるものです。
http://example.jp/?s=/abc/abc/abc/$%7B@print(md5(base64_decode(MzYwd2Vic2Nhbg)))%7D/
s=以下をパーセントデコードすると下記となります。
/abc/abc/abc/${@print(md5(base64_decode(MzYwd2Vic2Nhbg)))}/
{ } で囲まれた部分はPHPのスクリプトのように見えますが、2箇所文法違反があります。

  • MzYwd2Vic2Nhbg がクォートされていない
  • } の前にセミコロンがない

このうち、MzYwd2Vic2Nhbgのクォートに関しては @ 演算子によりエラー抑止され、'MzYwd2Vic2Nhbg' とみなされます。これをbase64デコードすると、360webscan となります。このため、この攻撃を仮に「360webscan攻撃」と名づけました。
PHPスクリプトに、足りないセミコロンを補って実行すると以下となります。
$ php
<?php
@print(md5(base64_decode(MzYwd2Vic2Nhbg)));
ed1e83f8d8d90aa943e4add2ce6a4cbf
360webscan と ed1e83f8d8d90aa943e4add2ce6a4cbf を検索すると、前者は多数、後者は10件ほどヒットします。見たところ、中国語のサイトが多いようです。

この攻撃の意図は分かりませんが、パラメータとしてPHPスクリプトの断片を渡しているからには、これを実行するためのバックドアを作成する攻撃が先にあり、その攻撃の正否を確認するためのリクエストなのかもしれません…が、まったく違う可能性もあります。

この攻撃(?)に対する監視を継続したいと思います。