WordPress 2.6.2はセキュリティ修正
WordPress2.6.2が出たのでさっそく更新したが、今回のリリースにはセキュリティ関連の修正が入っていた。
PHPのrand関数はlibcのrandのラッパで、mt_randはメルセンヌ・ツイスタ擬似乱数生成装置の実装なのだが、どちらも32ビット型符号なし整数をシードにしている。しかし、実装の問題により実際にはそれ以下の強度にしかならないそうだ。そのため、暗号化に際してこれらの関数を利用するのは不適切ということになる。それに対処したようだ。
MySQLではデフォルトでサーバとクライアント間で送信されるクエリとその応答の長さがmax_packet_sizeディレクティブ(っていうのかな?それはApacheだけ?)で1MBに制限されている。もし1MBを超えたクエリがクライアントから送信された場合、MySQLサーバ側でエラーとして処理してしまう。
たとえば、期限の切れたセッションデータをDBから削除するようなクエリがあり、意図的にこのクエリが長くなるようなデータをセッションに埋め込むことができれば、クエリはいつまでも実行されず、何かしら問題が起きることになる。
update: もっとすごい問題があった。
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:再現しますた。
Comments
[…] 昨日書いたMySQLの脆弱性ですが、手元の環境で見事に再現しました。MySQLのバージョンはCentOSでyumからインストールしたmysql-4.1.20-3.RHEL4.1.el4_6.1です。 […]