[EN] YesWeHack DOJO#21

YesWeHack DOJO#21

Write-up of the YesWeHack DOJO Challenge #21.

Scenario

/dojo21/scenario.png

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.

/dojo21/result.png

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 :

/dojo21/inputs.png

  • $id : 0
  • $username : ADMIN
  • $passwd : 464c41477b466c6f637a69697d