The vulnerability to be detected for this challenge was a resource (variable) injection that enabled authentication to be bypassed. Solving the challenge requires knowledge of certain PHP functions.
Note: This article is also available in french 🇫🇷. The challenge was announced in this tweet 🐦.
Explanation
The problem lies mainly in using the extract()
function on unsafe data (user input).
extract()
allows you to import variables from an array into the symbol table.
As a reminder, array() are not arrays in the classical meaning of other languages, but are map (association of a key and a value) sometimes called associative arrays (Dictionary in Python, Hash in Ruby, etc.).
extract()
will therefore take an associative array and create variables whose names are the indexes/keys of this array, and assign them the associated value.
Using extract()
on an associative array from a user input allows the user to arbitrarily create variables.
The vulnerable code was as follows:
if (isset($_REQUEST['color']['color']))
extract($_REQUEST['color']);
Note: the extract page of the PHP manual issues a warning about this coding error.
The extract($config);
above is quite benign, as the data is not user-controllable.
Note: the $_SERVER['PHP_AUTH_USER']}
in the welcome
message is bad practice, as it’s a user input that is not sanitized. On the other hand, there is no security risk in this case, as the message is only displayed once the user has been authenticated and it has been validated that $_SERVER['PHP_AUTH_USER']}
corresponds to the user’s name (except, of course, in the case of resource injection presented here).
Let’s analyze extract($_REQUEST['color'])
:
$_REQUEST
is a global variable which retrieves all entries from$_GET
,$_POST
and$_COOKIE
.- The use of the name
color
in$_REQUEST['color']
might lead you to believe that it only allows you to modify the$color
variable extracted from the$config
associative array. But this is not the case: the name of the HTTP parameter is arbitrary, andextract
can be used to create or modify any variable. - Without argument, by default
extract()
will use theEXTR_OVERWRITE
flag, so if there is a collision when extracting a variable (if it already exists) then its contents will be overwritten. If the variable does not already exist, then it will be created.
So extract()
+ $_REQUEST
allows you to overwrite any variable from an HTTP GET
or POST
parameter.
Let’s now analyze the if condition (isset($_REQUEST['color']['color']))
: this is a semblance of protection that simply checks that the color
key is present in the color
parameter and therefore that the color
parameter is of array type.
The following requests will therefore not be allowed:
- http://127.0.0.2:8080/app.vuln.php?color[nouvelle_variable]=1337 (creation of a new variable)
- http://127.0.0.2:8080/app.vuln.php?color[messages]=void (overwriting `$messages)
At the very least, the color
key must be present, i.e., for example, http://127.0.0.2:8080/app.vuln.php?color[color]=green, which is the case that seems to have been planned to be able to change the background color of the text.
However, the application checks that the color
key exists, but not that no other key is present. It is therefore perfectly possible to add a second key in addition to color
: http://127.0.0.2:8080/app.vuln.php?color[color]=green&color[messages]=void.
Apart from breaking the application’s behavior, this doesn’t seem to get us very far.
This behavior should be correlated with the following code:
if (!empty($credentials)) {
login($credentials['user'], $credentials['password']);
}
In fact, authentication is only performed if $credentials
is not empty. No authentication if the configuration is left empty. With extract
, we could overwrite $credentials
with an empty-like value by empty to bypass authentication. For example, 0
is evaluated as empty.
The following payload can be used to bypass authentication:
http://127.0.0.2:8080/app.vuln.php?color[color]=green&color[credentials]=0
Note: putting nothing (null
) rather than 0
also works.
Fixed code
Here is the corrected code:
Simply reassign a value to the $color
variable when a user input is entered, there’s no risk of overwriting another variable and XSS is not possible thanks to URL encoding.
The source code is available on the Github repository Acceis/vulnerable-code-snippets and on the website acceis.github.io/avcs-website.
About the author
Article written by Alexandre ZANNI aka noraj, Penetration Testing Engineer at ACCEIS.