Skip to content

Vulnerability Disclosure - MISP 2.4.155

Introduction

MISP (Malware Information Sharing Platform) is an open source threat intelligence platform. This web application is used for collecting, storing, distributing and sharing cyber security indicators and threats about cyber security incidents analysis and malware analysis.

The source code of MISP is built with CakePHP, an open-source web framework that follows the model–view–controller approach.

In February 2022, I was mandated to perform a security audit of the latest release of MISP. This two weeks long source code security audit resulted in the discovery of several security issues.

The most critical vulnerability could lead an authenticated attacker to gain remote code execution.

Vulnerability summary

  • CVE-2022-29528 - Insecure PHAR deserialization.
  • CVE-2022-27245 - Server-side request forgery.
  • CVE-2022-27243 - Local File Inclusion.
  • CVE-2022-27246 - Cross-Site Scripting via SVG upload.
  • CVE-2022-27244 - Stored Cross-Site Scripting.

Vulnerability details

Insecure PHAR deserialization - CVE-2022-29528

It is possible to trigger an insecure PHAR deserialization in the import function of the DecayingModelController.php controller. This vulnerability can lead to remote code execution.

As seen in the snippet of code below, when the import function is being called in a POST or PUT HTTP request, the value of $this->request->data['DecayingModel'] is assigned to the $data variable.

php
// app/Controller/DecayingModelController.php
public function import()
{
  if ($this->request->is('post') || $this->request->is('put')) {
    $data = $this->request->data['DecayingModel'];
    // ...
    if ($data['submittedjson']['size'] > 0) {
      $filename = basename($data['submittedjson']['name']);
      $file_content = file_get_contents($data['submittedjson']['tmp_name']);
      // ...
    }
  }
}

If the value of $data['submittedjson']['size'] is greater than 0, then the value of $data['submittedjson']['tmp_name'] is passed to the file_get_contents function as an argument.

CakePHP Request

In CakePHP 2.x, all POST data can be accessed using $this->request->data associative array. Any form data that contains a data prefix will have that data prefix removed. For example:

php
// An input with a name attribute equal to 'data[DecayingModel][json]'
// is accessible at
$this->request->data['DecayingModel']['json'];

CakePHP merges the form data as well as uploaded files to the $this->request->data property. When a file is uploaded in a CakePHP application, the item in the $_FILES superglobal along some of its attributes (tmp_name, error, name, type and size) are inserted as a new item to the $this->request->data property.

In MISP, the /decayingModel/import view generates a form containing a textarea with a name attribute equal to data[DecayingModel][json] and a file input with a name attribute equal to data[DecayingModel][submittedjson].

html
<form action="/decayingModel/import" method="POST">
  <textarea name="data[DecayingModel][json]"></textarea>
  <input type="file" name="data[DecayingModel][submittedjson]">
  ...
</form>

When submitting the form with an attached file, CakePHP will merges all the POST data in the associative array. For example:

php
// The items in $_FILES are merged to $this->request->data
$data = $this->request->data['DecayingModel'];
echo $data['json'];
echo $data['submittedjson']['tmp_name'];
echo $data['submittedjson']['name'];
echo $data['submittedjson']['size'];

During a file upload, an attacker should not be able to control the value of tmp_name because it's a file path that is randomly generated by the server to store the uploaded file. The path usually looks like /tmp/phpn3FmFr.

However, because CakePHP merges all the POST data, it is possible to forge a fake file upload with attacker controlled attributes. An attacker can create a new form that replaces the file input with several text inputs named after each attributes of a regular $_FILE entry. For example:

html
<form action="/decayingModel/import" method="POST">
  <textarea name="data[DecayingModel][json]"></textarea>
  <input type="text"
         name="data[DecayingModel][submittedjson][tmp_name]"
         value="phar:///tmp/exploit.phar/test">
  <input type="text"
         name="data[DecayingModel][submittedjson][error]"
         value="">
  <input type="text"
         name="data[DecayingModel][submittedjson][name]"
         value="name">
  <input type="text"
         name="data[DecayingModel][submittedjson][type]"
         value="application/octet-stream">
  <input type="text"
         name="data[DecayingModel][submittedjson][size]"
         value="1">
  ...
</form>

This way the value of tmp_name can be controlled by an attacker and set to a phar:// (PHP Archive) stream wrapper such as phar:///tmp/exploit.phar/test.

As we saw earlier, the function file_get_contents is called with the value of tmp_name as an argument. This function can be abused to execute arbitrary commands while the path is set to a malicious PHP Archive item.

INFO

Generating a ROP chain and uploading the PHAR archive at a predictable path is left as an exercise to the reader.

References