T

WordPress 2.6.2はセキュリティ修正

WordPress2.6.2が出たのでさっそく更新したが、今回のリリースにはセキュリティ関連の修正が入っていた。

1 推測されやすい乱数生成の問題

PHPのrand関数はlibcのrandのラッパで、mt_randはメルセンヌ・ツイスタ擬似乱数生成装置の実装なのだが、どちらも32ビット型符号なし整数をシードにしている。しかし、実装の問題により実際にはそれ以下の強度にしかならないそうだ。そのため、暗号化に際してこれらの関数を利用するのは不適切ということになる。それに対処したようだ。

2 MySQLのクエリの長さ制限の問題

MySQLではデフォルトでサーバとクライアント間で送信されるクエリとその応答の長さがmax_packet_sizeディレクティブ(っていうのかな?それはApacheだけ?)で1MBに制限されている。もし1MBを超えたクエリがクライアントから送信された場合、MySQLサーバ側でエラーとして処理してしまう。

たとえば、期限の切れたセッションデータをDBから削除するようなクエリがあり、意図的にこのクエリが長くなるようなデータをセッションに埋め込むことができれば、クエリはいつまでも実行されず、何かしら問題が起きることになる。

update: もっとすごい問題があった。

3 MySQLのダメダメな文字列比較ルール

MySQLにこんなクエリを投げる。

SELECT * FROM user WHERE username = 'admin';

たとえば、ユーザ登録の際に登録名の重複チェックをしているとしよう。WordPressのように、そのサイトにはadminという名のユーザが必ず存在するとして考える。新規のユーザが登録時に「admin」という名前を使おうとすると、上のようなクエリでチェックが行われ、すでに登録されている名前であるとしてアプリケーションによって登録がはじかれる。まあ、そういう仕組みのウェブアプリがあるものと思ってもらいたい。

このusernameというカラムが、たとえばchar(16)だったとする。MySQLではSELECTによる比較時にクエリ内の文字列の後ろの空白は無視されるようになっている。「admin           」だと、

SELECT * FROM user WHERE username = 'admin           ';

こうなるが、実際には最初のクエリと同じ扱いになる。

ところで、じゃあ「admin           x」という名前を使おうとしたらどうなるだろう。ここでは意図的に名前をchar(16)から外れるようにした。数えにくいかもしれないが、17文字ある。

SELECT * FROM user WHERE username = 'admin           x';

MySQLでは、比較の際にはカラムの型を無視してくれるので、上のSQLは何も返ってこない。つまり、新規登録可能なユーザ名として認識される。そこで、INSERET処理を実行すると、今度はカラムの型をみて余分なところはカットし、さらに後ろの空白を取り除くので、あれま、「admin」という名前でユーザ登録が完了してしまう。

これでadminアカウントの乗っ取りが完了する。ひええ。

もちろん、UNIQUE INDEXで対処することは可能だが、そうでないアプリケーションなら困ったことになる。

未検証なのでなんともいえないが、本当だったらこわい。

update:再現しますた

Posted by on 9月 10, 2008 in PHP, Security, WordPress

Comments

  • […] 昨日書いたMySQLの脆弱性ですが、手元の環境で見事に再現しました。MySQLのバージョンはCentOSでyumからインストールしたmysql-4.1.20-3.RHEL4.1.el4_6.1です。 […]

  • コメントを残す