Image credits to Leobit |
This is a walkthrough of an exercise created by PentesterLab as a free course for learning beginner-friendly source code review.
The link to the source code is here. Either clone it or download it as a zip locally. As instructed in the exercise we won't run the run, just read through the source code and look for possible weaknesses that we can leverage into vulnerabilities.
You can find below the list of issues present in the application:
- Hardcoded credentials or secrets
- Information leak
- Missing security flags
- Weak password hashing mechanism
- Cross-Site Scripting
- No CSRF protection
- Directory Listing
- Crypto issue
- Signature bypass
- Authentication bypass
- Authorization bypass
- Remote Code Execution
Hand-On Findings and Objectives
* Hardcoded credentials or secrets
Finding hardcoded credentials or secrets can be quite easy
where you have the source code, you just need to grep for the right keywords
and it will spill it out.
Hardcoded creds are usually a result of developers failing to remove them
and pushing them directly into live production environments. These hardcoded
credentials are useful while in development as the developer does not have
to log in again and again to the application.
We use a simple grep command with keywords like hash, token, secrets,
username, password, admin, etc, and see if we can find something
useful.
Files containing credentials :
Using "hash" as a keyword in grep we find a PHP file that is used for
generating jwt tokens and we see a hardcoded secret. This secret can be used
when we serialize/deserialize PHP objects for authentication.
```text classes/jwt.php ```
```php public static function signature($data) { return hash("sha256","donth4ckmebr0".$data); } ```
File deploy.sql has hardcoded admin credentials.
```text deploy.sql ``` ```sql create database cr; use cr; GRANT ALL PRIVILEGES ON cr.* TO pentesterlab@'localhost' IDENTIFIED BY 'pentesterlab'; create table users ( login VARCHAR(50) not null primary key , password VARCHAR(50)); INSERT INTO `users` (login,password) VALUES ('admin','bcd86545c5903856961fa21b914c5fe4'); ```
* Information Leak
Information is everywhere but finding sensitive information
can be a bit tricky in black box testing.
Information like the git folder in the root directory is considered
information disclosure as it can be used to reconstruct the source code,
also any hardcoded credentials and secrets are considered information
leaks.
* Missing security flags
Missing Secure and HTTPOnly flag in cookies in login.php and register.php
```text login.php and register.php ``` ```php setcookie("auth", User::createcookie($_POST['username'], $_POST['password'])); ```
PHP setcookie() function defines cookies to be sent with the rest of the
HTTP headers, the code is missing security headers which may allow the
cookie to be sent/used unencrypted through scripting languages like
javascript making it insecure.
* Weak Password Hashing Mechanism
```text classes/user.php ``` ```php public static function login($user, $password) { $sql = "SELECT * FROM users where login=\""; $sql.= mysql_real_escape_string($user); $sql.= "\" and password=md5(\""; $sql.= mysql_real_escape_string($password); $sql.= "\")"; $result = mysql_query($sql); if ($result) { $row = mysql_fetch_assoc($result); if ($user === $row['login']) { return TRUE; } } //else //echo mysql_error(); return FALSE; //die("invalid username/password"); } ```
* CSRF Protection
After going through all the source code you would see that
CSRF is totally missing, which means this app has no means of protection
against CSRF attacks.
(Don't misunderstand tokens for CSRF tokens, those are JWT tokens for
authentication and in no means have relation to CSRF attacks)
Digging further into the source code you will realize that
the app allows directory listing through this vulnerable code.
```text classes/user.php ``` ```php public static function getfiles($user) { $base = "files/".$user; if (!file_exists($base)) { mkdir($base); } return array_diff(scandir($base), array('..', '.')); } ```
The function "scandir" lists out the files belonging to the user, it
removes the current and parent directory from the list using the array_diff
function. But the user parameter is not sanitized and an attacker is
permitted to keep a username like "../../" or "../../../../" which would be
directly supplied to the base variable and the user will be able to see web
server files where it is hosted.
* Authorization bypass/ IDOR/Access Control
When
a user uploads a file it gets saved in a fixed manner -->
files/user1/file1.pdf, so for an attacker, it's trivial to guess the
username and file name and get access to their files. The developer should
implement some access control mechanism and make links impossible to
guess.
```text classes/user.php ``` ```php public static function addfile($user) { $file = "files/".$user."/".basename($_FILES["file"]["name"]); if (!preg_match("/\.pdf/", $file)) { return "Only PDF are allowed"; } elseif (!move_uploaded_file($_FILES["file"]["tmp_name"], $file)) { return "Sorry, there was an error uploading your file."; } return NULL; } ```
* Upload Bypass will lead to RCE
There is an upload functionality in the application that
allows uploading only pdf files. The regex that checks for the valid pdf
extension is missing a "$" at the end that allows an attacker to upload a
file that contains ".pdf" in it, so an attacker can upload a file named
"evil.pdf.php" with reverse shell in it. Since ".pdf" is present in the
file name it will be valid and will upload successfully while this is a
PHP file and not a pdf file.
```text classes/user.php ``` ```php public static function addfile($user) { $file = "files/".$user."/".basename($_FILES["file"]["name"]); if (!preg_match("/\.pdf/", $file)) { return "Only PDF are allowed"; } elseif (!move_uploaded_file($_FILES["file"]["tmp_name"], $file)) { return "Sorry, there was an error uploading your file."; } return NULL; } ```
Thanks for reading!
Comments
Post a Comment