Challenge

脆弱性があるって? でも秘密のテーブルにはアクセスできないはず…

image.png

~~~
    query = (
        f"SELECT * FROM users WHERE username='{username}' AND password='{password}';"
    )
~~~
    # users
    conn.execute(
        """
        CREATE TABLE IF NOT EXISTS users (
            username TEXT PRIMARY KEY,
            password TEXT NOT NULL
        );
        """
    )
    for username, password in USERS.items():
        conn.execute(
            f"""
            INSERT OR IGNORE INTO users (username, password) VALUES ('{username}', '{password}');
            """
        )

    # secret
    conn.execute(
        """
        CREATE TABLE IF NOT EXISTS secret (
            flag TEXT PRIMARY KEY
        );
        """
    )
    conn.execute(
        f"""
        INSERT OR IGNORE INTO secret (flag) VALUES ('{FLAG}');
        """
    )
~~~

Solution

This challenge features a login form implemented with Flask and SQLite, containing a classic UNION-based SQL injection vulnerability.

WAF Analysis

A naive WAF is applied to user input:

if "secret" in value:
return "The table is secret!"

Key observations:

Therefore, using SECRET instead of secret bypasses the WAF.

UNION

By SQL standard:

All SELECT statements combined with UNION must return the same number of columns

so, this query requires a dummy second column

UNION SELECT flag, '' FROM secret --

Final Payload