Beginner Code Review (Part 2)

Part 2 of the Beginner Code Review Series. Here I will be describing how the vulnerabilities found can be used to escalate privileges. I also got the code to run so it is easier for everyone to understand and not just code.

I have updated the code so it can be run after PHP 5.0. Also visit the link if the PHP scripts are not running.

Broken Authorization for Privilege Escalation

Vulnerabilities used:


Due to the lack of input sanitization on the register functionality it is possible to have a username with non-alphanumeric characters. This means it is possible to perform directory traversal as the getfiles() function uses the username to navigate to the user’s file storage.

In addition, as the files are hosted on the web root and there are no access controls in place. As a result, it is possible for an unauthenticated user to view the admin’s secret file.

Due to the lack of input sanitization it is possible to register with the username ../files/admin. This will show the list of files available to the admin user.
The files folder does not have a “../files/admin” folder.

Unrestricted file upload to Remote Code Exec

Vulnerabilities used:


In the application there is a file upload functionality on index.php. It is designed to only accept PDF files and the code to ensure this happens is in /classes/user.php.

Figure 1 — The php code to add a file.

The regex here looks for the string “.pdf” in the file name. However, this string can be anywhere in the file name. As a result a file such as file.pdf.php will be allowed.

Figure 2 — Regex will match .pdf and allow the php file to be uploaded.

When a php file is uploaded, the file should be accessible from the location[user]/file.pdf.php. From here, it should be possible to create a reverse shell and gain access to the host system. This walk through affects the confidentiality, integrity and availability of the whole system.

It is possible to upload a .php file.
The php file can be accessed without authentication and PHP code can be run.
Created a reverse shell on the php file and connected to it. Result is access to the host system as www-data.

JSON Web Token Privilege Escalation

Before beginning this walk through, here is a quick breakdown on the structure of JSON Web Tokens:

Format: header.payload.signature
Header: Algorithm, Type
Payload: variables and values
Signature: HMACSHA256(b64UrlEncode(header)+”.”+b64UrlEncode(payload), secret)

In this web application, there are two problems with how JWTs are implemented in this application. In jwt.php there are 4 functions:

There are vulnerabilities in all of these functions.

Exploiting the verify function:

Figure 3 — jwt.php, line 22, verify function.

The if statement works as follows:

If the signature exists, perform a check to see if it is valid. If it is invalid, die. Otherwise continue.

As a result it is possible to not include a signature and no checks will be performed. The purpose of the signature is to ensure the message has not been tampered with and this cannot be guaranteed anymore.

A JWT without the signature is still accepted.

Exploiting parse_json function:

The way the parse_json function works is by splitting up the string by the commas. The sign function contains no sanitization for special characters such as commas.

As a result, if the username has a comma and double quotes, it will affect the contents of the JWT when decoded. This can be exploited to impersonate other users. Here is an example username that can be used to hijack other accounts.


Parse_json function splits up the data by the commas.
Sign function has no sanitization for alphanumerical characters.
List of users in the application
Logging in as test”,”username:admin and dissecting the token.
The resultant view as use test”,”username:admin
It is possible to enumerate other usernames on the registration functionality.

Proof of concept code for exploiting JWT:


<?phpfunction verify($auth) {
list($h64,$d64,$sign) = explode(".",$auth);
if (!empty($sign) and (signature($h64.".".$d64) != $sign)) {
die("Invalid Signature");
$header = base64_decode($h64);
$data = base64_decode($d64);
return parse_json($data);
function signature($data) {
return hash("sha256","donth4ckmebr0".$data);
function parse_json($str) {
$data = explode(",",rtrim(ltrim($str, '{'), '}'));
$ret = array();
foreach($data as $entry) {
list($key, $value) = explode(":",$entry);
$key = rtrim(ltrim($key, '"'), '"');
$value = rtrim(ltrim($value, '"'), '"');
$ret[$key] = $value;
return $ret;


<?phpfunction sign($data) {
$header = str_replace("=","",base64_encode('{"alg":"HS256","iat":'.time().'}'));
$token = "{";
$token.= '"username:admin"';
$token .= "}";
$to_sign = $header.".".base64_encode($token);
return $to_sign.".".signature($to_sign);
function signature($data) {
return hash("sha256","donth4ckmebr0".$data);

What’s next

Next part in this series will be about the methodologies I took to perform the static code analysis.


Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store