Nire.Com

www.nire.com – 1994年からやってる個人サイト、にれ.コム。サーバ構築、携帯、カメラ、ゲーム、目の話、水泳とか。
2009 年 8 月 13 日

「ピンポンダッシュ」対策でセキュリティ強化された箇所 – WordPress 2.8.4 リリース Part2

« 前記事: こんな簡単に他人がパスワードリセットできたのか – WordPress 2.8.4 リリース

実験してみたらあっさりとパスワードリセットができてしまった WordPress 2.8.3 ですが、今回の WordPress 2.8.4 でどこが強化されたのか、コードを追いかけてみました。

最初のパッチにもまだ甘い点が

traq に送られた最初のパッチは下記のようなものだったらしいですが、

$key = preg_replace('/[^a-z0-9]/i', '', $key);
-    if ( empty( $key ) )
+    if ( empty( $key ) || is_array( $key ) )
        return new WP_Error('invalid_key', __('Invalid key'));

これだと文字列型と配列型以外の型を使うと、やはり key チェックをすり抜けられてしまうため、最終的な WordPress 2.8.4 の wp-login.php は以下のようになっています。

$key = preg_replace('/[^a-z0-9]/i', '', $key);
-    if ( empty( $key ) )
+   if ( empty( $key ) || !is_string( $key ) )
        return new WP_Error('invalid_key', __('Invalid key'));

さらに login ユーザチェックで二重に確認

さらに、WordPress 2.8.4 が生成するパスワードリセット確認用 URL に login という 2つ目の変数が追加され、

http://www.example.com/wp-login.php?action=rp&key=abcdefgh&login=username

キー文字列 (key) とログインユーザー名 (login) の組み合わせが両方合致して初めてパスワードがリセットされるよう、セキュリティ強化されています。

悪意のパスワードリセットができなくなったかテスト

WordPress 2.8.4 で、先ほどの「特別に作成された URL」でパスワードリセットが拒否されるかどうか確認してみます。

WordPress 2.8.4: パスワードリセット拒否

たしかに拒否しているようです。

参考: wp-login.php の変更箇所

以下に wp-login.php の unified diff の全体をメモがわりにつけておきます。

--- wordpress-2.8.3-ja/wp-login.php     2009-08-04 10:28:51.000000000 +0900
+++ wordpress-2.8.4-ja/wp-login.php     2009-08-12 13:26:29.000000000 +0900
@@ -161,7 +161,7 @@
        $message .= get_option('siteurl') . "\r\n\r\n";
        $message .= sprintf(__('Username: %s'), $user_login) . "\r\n\r\n";
        $message .= __('To reset your password visit the following address, otherwise just
 ignore this email and nothing will happen.') . "\r\n\r\n";
-       $message .= site_url("wp-login.php?action=rp&key=$key", 'login') . "\r\n";
+       $message .= site_url("wp-login.php?action=rp&key=$key&login=" . rawurlencode($user
_login), 'login') . "\r\n";

        $title = sprintf(__('[%s] Password Reset'), get_option('blogname'));

@@ -182,15 +182,18 @@
  * @param string $key Hash to validate sending user's password
  * @return bool|WP_Error
  */
-function reset_password($key) {
+function reset_password($key, $login) {
        global $wpdb;

        $key = preg_replace('/[^a-z0-9]/i', '', $key);

-       if ( empty( $key ) )
+       if ( empty( $key ) || !is_string( $key ) )
                return new WP_Error('invalid_key', __('Invalid key'));

-       $user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_activation_key = %s", $key));
+       if ( empty($login) || !is_string($login) )
+               return new WP_Error('invalid_key', __('Invalid key'));
+
+       $user = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wpdb->users WHERE user_activation_key = %s AND user_login = %s", $key, $login));
       if ( empty( $user ) )
                return new WP_Error('invalid_key', __('Invalid key'));

@@ -370,7 +373,7 @@

 case 'resetpass' :
 case 'rp' :
-       $errors = reset_password($_GET['key']);
+       $errors = reset_password($_GET['key'], $_GET['login']);

        if ( ! is_wp_error($errors) ) {
                wp_redirect('wp-login.php?checkemail=newpass');

続き: 冷却性能はダントツに高いが、25cm ファンの寿命が短い – サイズ PC ケース XClio 6020 »

関連する投稿

「「ピンポンダッシュ」対策でセキュリティ強化された箇所 – WordPress 2.8.4 リリース Part2」へのコメント/トラックバック (2)

  1. RT @nirecom: [Blog] 「ピンポンダッシュ」対策でセキュリティ強化された箇所 – WordPress 2.8.4 リリース Part2 http://bit.ly/lxdHO


  2. これむしろ、wpdb クラスの prepare メソッドの脆弱性という気がします。川崎勉強会で「実装があやしい」と指摘しましたが、まさにそこを突かれています。その面では is_array() チェックで足りるのですが、セキュアなプログラミングとしては string 以外を弾くのが安全でしょうか。

    わたしが指摘するならば、prepare メソッドを直したいですが、それだと既存のプラグインに影響が出るかもしれず、悩ましいところです。根本解決としては、PHP 5.1 以降を必須にして DB 回りを PDO 化するしかないと思います。


コメントをどうぞ