Skip to content

Sqli canary exfiltration - #331

Merged
kOaDT merged 25 commits into
mainfrom
sqli-canary-exfiltration
Sep 22, 2026
Merged

kOaDT merged 25 commits into
mainfrom
sqli-canary-exfiltration

Conversation

@kOaDT

@kOaDT kOaDT commented Sep 13, 2026

Copy link
Copy Markdown
Owner

No description provided.

@kOaDT kOaDT self-assigned this Sep 13, 2026
@github-actions github-actions Bot added the size/XL PR size: XL label Sep 13, 2026
@kOaDT
kOaDT marked this pull request as ready for review September 18, 2026 22:14
@kOaDT
kOaDT force-pushed the sqli-canary-exfiltration branch from 395b816 to a242fb6 Compare September 19, 2026 20:36
The four SQL injection routes each carried their own copy of the guard and of
the row filter. The sanitizer now matches on the OSS{ prefix instead of the
word "flag", which stops it from hiding sqlite_master output from the player
while still keeping flag values out of every response.
A SQL keyword in the header used to be enough, so the challenge taught payload
recognition rather than exploitation. The endpoint now hides a per-instance
canary in internal_secrets and echoes back the rows the request wrote, so the
flag only drops once the player reads that canary out of the database through
the INSERT sink.
Any SQL keyword in the search term used to be enough. The flag now requires a
UNION SELECT that actually reaches the per-instance canary in internal_secrets,
and the SQLite error is returned as-is so the column count can be worked out
from the endpoint itself rather than guessed.
Dumping the users table through the status filter used to be optional: any SQL
keyword handed the flag over. The flag now requires reading the per-instance
canary out of internal_secrets, which means a nine-column UNION that actually
lands, while the credential dump stays exactly as exploitable as before.
Storing a SQL payload as a display name was rewarded on sight, and the audit
panel handed the same flag to anyone typing that payload into the query string.
The flag now needs the canary from internal_secrets to come back through a
filter value the reviews table actually holds, which is what makes the
injection second-order in the first place.
A bare PATCH from a terminal used to earn the flag, so the challenge rewarded
doing nothing at all. The flag now requires the browser metadata a page attaches
on a victim's behalf, with a Referer that is not the admin dashboard, which the
shipped proof-of-concept page already sends. The endpoint still updates the
order for any caller: the missing CSRF protection is the vulnerability, not the
flag condition.

The walkthrough also claimed a top-level navigation would carry the cookie
cross-site, which sameSite=lax only allows for safe methods.
db:seed alone fails once the table is dropped, it reads reviews before writing
them. Players also need to know their captured flags survive the recovery.
@kOaDT
kOaDT force-pushed the sqli-canary-exfiltration branch from a597ba9 to 1cb5de3 Compare September 20, 2026 19:23
@kOaDT
kOaDT force-pushed the sqli-canary-exfiltration branch from 001e0ce to dd883b5 Compare September 22, 2026 22:11
@kOaDT
kOaDT merged commit 957a0db into main Sep 22, 2026
7 checks passed
@kOaDT
kOaDT deleted the sqli-canary-exfiltration branch September 22, 2026 22:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SQL injection flags are awarded on payload shape, not on successful exploitation

1 participant