IIJ-SECT

IIJ

 

Security Diary

HOME > Security Diary > CVE-2012-2122 MySQLにおける認証迂回の脆弱性について

CVE-2012-2122 MySQLにおける認証迂回の脆弱性について

この脆弱性は2012年5月7日にリリースされたMySQLバージョン5.1.63と5.5.24において修正されました。 認証時に指定するパスワードは何でもよく、認証要求を繰り返すと一定確率でログインが可能というかなり奇妙な脆弱性です。 すべての環境において発生するわけではありませんが、攻撃成立時には深刻な影響を受けます。

該当するバグチケットは以下です。リリースバージョンも同様の修正でした。
MySQL Bugs: #64884: logins with incorrect password are allowed

Rapid7によりPoCや影響が確認された環境等が纏められています。
CVE-2012-2122: A Tragically Comedic Security Flaw in MySQL

アプリケーションに対するコード修正は1行のみ、発生する環境が限られている、非常に簡単なPoCと、 興味深い点が多いので、何故この様な現象が起きているのかを解説したいと思います。

今回の脆弱性は以下の複合要因で発生しています。

  1. MySQLにおいてmemcmpの戻り値のint型をmy_bool型(char)にキャストしている
  2. glibcのmemcmpが-256以下、または256以上の値を返す可能性がある


まずは1のキャストについてです。
認証に使用される関数内部で一致判定にmemcmp関数を使用しています。該当するコードは以下の箇所です。

== sql/password.c
my_bool
check_scramble(const char *scramble_arg, const char *message,
       const uint8 *hash_stage2)
{
  ...
  return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
}

入力の一致時のみmemcmp関数により0が戻されるため一見問題無さそうですが、memcmp関数の戻り値はint型、 check_scramble関数の戻り値はmy_bool型(char)とそれぞれ異なり暗黙的にキャストが発生します。

以下はこのキャストに注目し値の変化を比較するテストコードです。

#include <stdio.h>
int main(int argc, char ** argv){
    int i;
    char c;
    for(i = -300; i < 300; i++){
        c = i;
        printf("% 4d: %d\n", i, c);
    }
    return 0;
}

このコードをコンパイルし生成したバイナリのディスアセンブル結果を抜粋します。 intからcharへの代入で上位3バイトは無視され下位の1バイトのみ代入されています。

 // c = i;
 804839e:       8b 45 f4                mov    0xfffffff4(%ebp),%eax
 80483a1:       88 45 fb                mov    %al,0xfffffffb(%ebp)

更にこれを実行した結果です。出力が多いので重要な箇所のみ抜粋しています。 256の周期でキャスト後の結果が0になってしまいます。

#int  char
-257: -1
-256: 0
-255: 1
...
  -1: -1
   0: 0
   1: 1
...
 255: -1
 256: 0
 257: 1

入力された値は一致していないにも関わらず、一致していると見なされてしまうのはこの動作に起因しています。


次は2のmemcmpの戻り値についてです。
上記キャストの動作より、脆弱性の存在するバージョンであったとしてもmemcmpの戻り値が-255から255の範囲に収まっている限り問題は発生しません。 ですが、このmemcmpの動作がgccやglibcのバージョン、実行しているCPUにより異なる事が問題を複雑にしています。

背景としてmemcmpやmemcpyなどの頻繁に呼ばれ、大量のデータを扱う事が前提の関数はCPUの拡張機能を用いて高速化されています。 この機能は比較的新しいglibcに導入されており、これらはコンパイル時ではなく実行時にCPUの拡張機能有無を判定して使用するルーチンを決定しています。

Fedora16付属のglibcにて確認したところ、memcmpはアーキテクチャとCPUの拡張機能毎に複数の最適化ルーチンが存在していました。 これを検証結果と合わせて記載したのが以下の表です。 複数の拡張機能をサポートしている場合は、各アーキテクチャで下に記載してある物ほど優先されます。

memcmp最適化ルーチン アーキテクチャ 戻り値の範囲(-255~255)
IA32 x86 収まる
SSSE3 x86 収まる
SSE4.2 x86 収まる
SSE2 x86_64 収まる
SSSE3 x86_64 収まる
SSE4.1 x86_64 外れる

これに加えてgccのビルドイン実装が存在しますが、こちらについては影響を受けませんので詳細は割愛します。 RHEL6においては最適化オプション無し、または-O0指定時のみglibc側の関数が使用されますが、Fedora16においては最適化オプションの指定に関わらずglibc側の関数が使われていました。 この変化はglibc側により高速な処理が実装されたため、gccが最適化処理を見直したのではないかと推測されます。

まとめると今回の脆弱性は以下の条件が揃う場合に発生すると考えられます。

  • SSE4.1の拡張機能を持ったCPUを使用
  • 脆弱性の存在するMySQLバージョンを使用
  • 64bit(x86_64)バイナリを使用
  • memcmpの最適化が施された新しいglibcを使用
  • gccのビルドイン実装が使用されていない


今回の脆弱性はPoCだけ見るとジョークかと思えるような物ですが、実際はコードの問題や実行環境などの複合要因により発生しています。 日頃、多くの脆弱性情報に注目していると、あまりに単純な内容で明らかに偽情報であるような物も多数見つかります。 しかし、今回の件のように単純でありながら影響の大きい脆弱性もあることから、一つ一つ検証していくことが必要となっています。

(2012年6月13日追記) MySQLのリリース日を間違って記載していたため訂正しました。

-
 
カテゴリー :
脆弱性  
タグ :
Vulnerability   MySQL   Linux  
この記事のURL :
https://sect.iij.ad.jp/d/2012/06/122899.html