YesWeHack DOJO#21
Write-up of the YesWeHack DOJO Challenge #21.
Scenario
Code overview
This is the Sqlite code used in the challenge :
--run
/*Create a new user to our website:*/
INSERT INTO users(id, username, email)
VALUES(
$id, LOWER(REPLACE(LTRIM('$username', ' '), 'admin', 'Nope')), 'EvilTwin'||'@'||'ywh.com'
);
--run
UPDATE users
SET password = cast(x'$passwd' AS TEXT), role = IIF( $id > 1, 'USER', 'ADMIN')
WHERE id=$id;
--return
/*We should only have one admin. Limit the output:*/
SELECT ('===(RESULT)=='=0),* FROM users WHERE ( username='admin' AND role=upper('admin') ) AND password LIKE cast('FLAG{%}' AS TEXT) LIMIT 1;
--_____ _____ __ __ __ __ __
/* __ \ /\ __-. /\ `-./ \ /\ \ /\ `-.\ \
\ \ __ \\ \ \/\ \\ \ \·./\ \\ \ \\ \ \·. \
\ \_\ \_\\ \____, \ \_\ \ \_\\ \_\\ \_\\"\_\
\/_/\/_/ \/____/ \/_/ \/_/ \/_/ \/_/ \/*/
/*You need help? Debug you process*/
-- return
SELECT ('===(DEBUG)=='=0),* FROM users WHERE id = $id;
We also have some input restrictions :
- The
$id
allows only numbers - The
$username
and$passwd
fields prohibit the single quote'
and backslash\
The first query allows to insert a new user to the database, with user-supplied id
and username
. Note that the ltrim()
, replace()
and lower()
functions are applied on the username
, they respectively remove leading spaces, replaces the “admin” string with “Nope”, and lowercase the input.
Also, we can’t use the id
1, because it is already the admin’s id
which is the primary key of the user table.
The second query sets the password
and the role
for the newly created user. The passwd
input is casted from hexadecimal to text, so it must be supplied in this format (hex characters) else an error is thrown. Then the role
is set depending of the user
’s id : If it is greater than 1, the role
is “USER”, else “ADMIN”.
Finally, the third query is supposed to search for the admin user, which has the username “admin” and the role “ADMIN”, in addition to a password
looking like “FLAG{%}” with %
matching any sequence of zero or more characters. The output of this query is limited to 1, because there should be only one admin :)
Exploitation
We can notice several flaws allowing us to become the new administrator of the app.
The first flaw is in the id
input. The role of “ADMIN” is given only if this value is greater than 1, with 1 already being the admin’s id
. But we can set it to 0 which is lower than 1 since all numbers are allowed, so our user is given the “ADMIN” role.
Moreover, the username
is not strictly checked at creation because the lower()
function is applied right after the replace()
that removes the lowercase string “admin” from the field. It means we can set our username
to “admin” by supplying a value with at least one uppercase letter like “ADMIN” to bypass this filter.
Eventually, we set our password
to the hexadecimal value of the string “FLAG{AnythingHere}” to match the admin’s password : 464c41477b466c6f637a69697d (Here “FLAG{Floczii}”).
We now fulfill all requirements to be returned by the third query, as a user with username
“admin”, role
“ADMIN”, and password
matching “FLAG{%}”.
Since the output of the last query (checking for the administrator) is limited to 1 row and our new user has the id
0, we are the first (and only) row being returned and we should have access to the application with our custom password.
We successfully added our EvilTwin user with a custom password as the only administrator of the app !
PoC
To complete the challenge, we can fill the input fields with the following values :
$id
:0
$username
:ADMIN
$passwd
:464c41477b466c6f637a69697d