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

~~~
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}');
"""
)
~~~
This challenge features a login form implemented with Flask and SQLite, containing a classic UNION-based SQL injection vulnerability.
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.
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 --