はまやんはまやんはまやん

hamayanhamayan's blog

revenant [LORD OF SQLINJECTION]

Lord of SQLInjection

<?php
include "./config.php";
login_chk();
$db = mssql_connect();
if(preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['id'])) exit("No Hack ~_~");
if(preg_match('/master|sys|information|prob|;|waitfor|_/i', $_GET['pw'])) exit("No Hack ~_~");
$query = "select * from prob_revenant where id='{$_GET['id']}' and pw='{$_GET['pw']}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
sqlsrv_query($db,$query);
if(sqlsrv_errors()) exit(mssql_error(sqlsrv_errors()));

$query = "select * from prob_revenant where id='admin'"; 
$result = sqlsrv_fetch_array(sqlsrv_query($db,$query));
if($result['4'] === $_GET['pw']) solve("revenant"); // you have to pwn 5th column
highlight_file(__FILE__);

特徴は以下。

  • SQL Server
  • id,pwが入力可能
    • master,sys,information,prob,;,waitforがフィルタリング
  • エラーが出れば表示される
  • adminの5番目のカラムの内容を取得してくる必要がある

カラム名をまずは抜き取る

  • HAVING, GROUP BYトリック
    • [Lord of SQL Injection] LoS - revenant 문제풀이 | mingzzi
    • ここに書いてある。having 1=1を書いておくと、エラーが出る。かつ、エラーが表示されるようになっていると、カラム名が流出する。
    • 1個とってきたら、group by name1 having 1=1としてエラーを出すと2つ目のカラム名が出てくる。
    • カラム名を入れてうまくいかなかったら[カラム名]のようにするとうまくいったりする(よくわからん)
    • エラーが消えたら全部抜き取り成功

こんな技があるのか…
書いてあるままにやってみると、確かに抜き出せる。
id, pw, [45a88487], [13477a35], [9604b0c8]

中身を抜き取る

これで後は、Blind SQL Injectionかな…と思いきや、エラーから直接抜き取るテクもある。

  • エラー文から内容を抜き取る方法
    • password=1をwhereの条件に含めると、passwordに文字列が来ると比較に失敗して、中身がエラー文に表示されてしまう
    • 一時カラム名みたいなカラム名の場合は"9604b0c8"=1のようにダブルクオーテーションで指定する

ほほう。?id=admin' and "9604b0c8"=1 --で抜き出せる。