Skip to content

Commit

Permalink
QA: 1.2.29 Security Updates (#6074)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheWitness authored Jan 26, 2025
1 parent 096a403 commit c7e4ee7
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 46 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Cacti CHANGELOG

1.2.x
1.2.29
-security#GHSA-pv2c-97pp-vxwg: Local File Inclusion (LFI) Vulnerability via Poller Standard Error Log Path
-security#GHSA-f9c7-7rc3-574c: SQL Injection vulnerability when using tree rules through Automation API
-security#GHSA-vj9g-P7F2-4wqj: SQL Injection vulnerability when view host template
-security#GHSA-fh3x-69rr-qqpp: SQL Injection vulnerability when request automation devices
-security#GHSA-c5j8-jxj3-hh36: Authenticated RCE via multi-line SNMP responses
-security#GHSA-fxrq-fr7h-9rqq: Arbitrary File Creation leading to RCE
-issue#5843: Issue with temporary tables with use of microtime
-issue#5847: Presets Time in Cacti 1.2.28 Not Automatically Updating...
-issue#5848: RRDfile Auto Clean not working
Expand Down
66 changes: 38 additions & 28 deletions automation_devices.php
Original file line number Diff line number Diff line change
Expand Up @@ -345,45 +345,44 @@ function process_request_vars() {
'filter' => FILTER_VALIDATE_INT,
'pageset' => true,
'default' => '-1'
),
),
'page' => array(
'filter' => FILTER_VALIDATE_INT,
'default' => '1'

),
),
'filter' => array(
'filter' => FILTER_DEFAULT,
'pageset' => true,
'default' => ''
),
),
'sort_column' => array(
'filter' => FILTER_CALLBACK,
'default' => 'hostname',
'options' => array('options' => 'sanitize_search_string')
),
),
'sort_direction' => array(
'filter' => FILTER_CALLBACK,
'default' => 'ASC',
'options' => array('options' => 'sanitize_search_string')
),
),
'status' => array(
'filter' => FILTER_CALLBACK,
'pageset' => true,
'default' => '',
'options' => array('options' => 'sanitize_search_string')
),
),
'network' => array(
'filter' => FILTER_CALLBACK,
'filter' => FILTER_VALIDATE_INT,
'pageset' => true,
'default' => '',
'options' => array('options' => 'sanitize_search_string')
),
'default' => '-1',
),
'snmp' => array(
'filter' => FILTER_CALLBACK,
'pageset' => true,
'default' => '',
'options' => array('options' => 'sanitize_search_string')
),
),
'os' => array(
'filter' => FILTER_CALLBACK,
'pageset' => true,
Expand All @@ -400,49 +399,60 @@ function get_discovery_results(&$total_rows = 0, $rows = 0, $export = false) {
global $os_arr, $status_arr, $networks, $device_actions;

$sql_where = '';
$sql_params = array();

$status = get_request_var('status');
$network = get_request_var('network');
$snmp = get_request_var('snmp');
$os = get_request_var('os');
$filter = get_request_var('filter');

if ($status == __('Down')) {
$sql_where .= 'WHERE up=0';
$sql_where .= 'WHERE up = 0';
} else if ($status == __('Up')) {
$sql_where .= 'WHERE up=1';
$sql_where .= 'WHERE up = 1';
}

if ($network > 0) {
$sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . 'network_id=' . $network;
$sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . 'network_id = ?';
$sql_params[] = $network;
}

if ($snmp == __('Down')) {
$sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . 'snmp=0';
$sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . 'snmp = 0';
} else if ($snmp == __('Up')) {
$sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . 'snmp=1';
$sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . 'snmp = 1';
}

if ($os != '-1' && in_array($os, $os_arr)) {
$sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . "os='$os'";
$sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . 'os = ?';
$sql_param[] = $os;
}

if ($filter != '') {
$sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . '(hostname LIKE ' . db_qstr('%' . $filter . '%') . '
OR ip LIKE ' . db_qstr('%' . $filter . '%') . '
OR sysName LIKE ' . db_qstr('%' . $filter . '%') . '
OR sysDescr LIKE ' . db_qstr('%' . $filter . '%') . '
OR sysLocation LIKE ' . db_qstr('%' . $filter . '%') . '
OR sysContact LIKE ' . db_qstr('%' . $filter . '%') . '
)';
$sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') .
'(hostname LIKE ? OR ip LIKE ? OR sysName LIKE ? OR sysDescr LIKE ? OR sysLocation LIKE ? OR sysContact LIKE ?)';

$sql_params[] = '%' . $filter . '%';
$sql_params[] = '%' . $filter . '%';
$sql_params[] = '%' . $filter . '%';
$sql_params[] = '%' . $filter . '%';
$sql_params[] = '%' . $filter . '%';
$sql_params[] = '%' . $filter . '%';
}

if ($export) {
return db_fetch_assoc("SELECT * FROM automation_devices $sql_where ORDER BY INET_ATON(ip)");
return db_fetch_assoc_prepared("SELECT *
FROM automation_devices
$sql_where
ORDER BY INET_ATON(ip)",
$sql_params);
} else {
$total_rows = db_fetch_cell("SELECT
$total_rows = db_fetch_cell_prepared("SELECT
COUNT(*)
FROM automation_devices
$sql_where");
$sql_where",
$sql_params);

$page = get_request_var('page');

Expand All @@ -455,7 +465,7 @@ function get_discovery_results(&$total_rows = 0, $rows = 0, $export = false) {
$sql_order
$sql_limit";

return db_fetch_assoc($sql_query);
return db_fetch_assoc_prepared($sql_query, $sql_params);
}
}

Expand Down
13 changes: 13 additions & 0 deletions automation_graph_rules.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,19 @@ function save() {
$save['operator'] = form_input_validate((isset_request_var('operator') ? get_nfilter_request_var('operator') : ''), 'operator', '^[0-9]+$', true, 3);
$save['pattern'] = form_input_validate((isset_request_var('pattern') ? get_nfilter_request_var('pattern') : ''), 'pattern', '', true, 3);

/* Test for SQL injections */
$field_name = str_replace(array('ht.', 'h.', 'gt.'), '', $save['field']);

if (!db_column_exists('host', $field_name) && !db_column_exists('host_template', $field_name) && !db_column_exists('graph_templates', $field_name)) {
raise_messsage('sql_injection', __('An attempt was made to perform a SQL injection in Tree automation'), MESSAGE_LEVEL_ERROR);

cacti_log(sprintf('ERROR: An attempt was made to perform a SQL Injection in Graph Automation from client address \'%s\'', get_client_addr()), false, 'SECURITY');

header('Location: automation_graph_rules.php?header=false&action=edit&id=' . get_request_var('id') . '&rule_type=' . AUTOMATION_RULE_TYPE_GRAPH_ACTION);

exit;
}

if (!is_error_message()) {
$item_id = sql_save($save, 'automation_graph_rule_items');

Expand Down
13 changes: 13 additions & 0 deletions automation_tree_rules.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,19 @@ function automation_tree_rules_form_save() {
$save['operator'] = form_input_validate((isset_request_var('operator') ? get_nfilter_request_var('operator') : ''), 'operator', '^[0-9]+$', true, 3);
$save['pattern'] = form_input_validate((isset_request_var('pattern') ? get_nfilter_request_var('pattern') : ''), 'pattern', '', true, 3);

/* Test for SQL injections */
$field_name = str_replace(array('ht.', 'h.', 'gt.'), '', $save['field']);

if (!db_column_exists('host', $field_name) && !db_column_exists('host_template', $field_name) && !db_column_exists('graph_templates', $field_name)) {
raise_messsage('sql_injection', __('An attempt was made to perform a SQL injection in Tree automation'), MESSAGE_LEVEL_ERROR);

cacti_log(sprintf('ERROR: An attempt was made to perform a SQL Injection in Tree automation from client address \'%s\'', get_client_addr()), false, 'SECURITY');

header('Location: automation_tree_rules.php?header=false&action=item_edit&id=' . get_request_var('id') . '&item_id=' . (empty($item_id) ? get_request_var('item_id') : $item_id) . '&rule_type=' . AUTOMATION_RULE_TYPE_TREE_MATCH);

exit;
}

if (!is_error_message()) {
$item_id = sql_save($save, 'automation_match_rule_items');

Expand Down
19 changes: 13 additions & 6 deletions lib/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -4562,9 +4562,14 @@ function cacti_escapeshellarg($string, $quote = true) {
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. */
/* remove any carriage returns or line feeds from the argument */
$string = str_replace(array("\n", "\r"), array('', ''), $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) {
Expand All @@ -4574,12 +4579,14 @@ function cacti_escapeshellarg($string, $quote = true) {
return substr($string, 1, (strlen($string)-2));
}
} else {
/* escapeshellarg takes care of different quotation for both linux and windows,
/**
* escapeshellarg takes care of different quotation for both linux and windows,
* but unfortunately, it blanks out percent signs
* we want to keep them, e.g. for GPRINT format strings
* so we need to create our own escapeshellarg
* on windows, command injection requires to close any open quotation first
* so we have to escape any quotation here */
* so we have to escape any quotation here
*/
if (substr_count($string, CACTI_ESCAPE_CHARACTER)) {
$string = str_replace(CACTI_ESCAPE_CHARACTER, "\\" . CACTI_ESCAPE_CHARACTER, $string);
}
Expand Down Expand Up @@ -7459,7 +7466,7 @@ function cacti_format_ipv6_colon($address) {
if (!filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
return $address;
}

if (strpos($address, '[') !== false) {
return $address;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/html_validate.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function die_html_input_error($variable = '', $value = '', $message = '') {
global $config;

if ($message == '') {
$message = __('Validation error for variable %s with a value of %s. See backtrace below for more details.', html_escape($variable), html_escape($value));
$message = __esc('Validation error for variable %s with a value of %s. See backtrace below for more details.', $variable, html_escape($value));
}

if (isset_request_var('json')) {
Expand Down
42 changes: 36 additions & 6 deletions lib/snmp.php
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ function cacti_snmp_session_walk($session, $oid, $dummy = false, $max_repetition
}

if (cacti_sizeof($out)) {
foreach($out as $oid => $value){
foreach($out as $oid => $value) {
if (is_array($value)) {
foreach($value as $index => $sval) {
$out[$oid][$index] = format_snmp_string($sval, false, $value_output_format);
Expand Down Expand Up @@ -537,7 +537,7 @@ function cacti_snmp_session_get($session, $oid, $strip_alpha = false) {
}

if (is_array($out)) {
foreach($out as $oid => $value){
foreach($out as $oid => $value) {
$out[$oid] = format_snmp_string($value, false, SNMP_STRING_OUTPUT_GUESS, $strip_alpha);
}
} else {
Expand Down Expand Up @@ -579,7 +579,7 @@ function cacti_snmp_session_getnext($session, $oid) {
}

if (is_array($out)) {
foreach($out as $oid => $value){
foreach($out as $oid => $value) {
$out[$oid] = format_snmp_string($value, false);
}
} else {
Expand All @@ -589,6 +589,18 @@ function cacti_snmp_session_getnext($session, $oid) {
return $out;
}

function cacti_snmp_validate_oid($oid) {
$oid = ltrim($oid, '.');

$validate = array_unique(array_map('is_numeric', explode('.', $oid)));

if (array_search(false, $validate, true)) {
return false;
} else {
return true;
}
}

function cacti_snmp_walk($hostname, $community, $oid, $version, $auth_user = '', $auth_pass = '',
$auth_proto = '', $priv_pass = '', $priv_proto = '', $context = '',
$port = 161, $timeout_ms = 500, $retries = 0, $bulk_walk_size = 10, $environ = 'SNMP',
Expand Down Expand Up @@ -728,11 +740,20 @@ function cacti_snmp_walk($hostname, $community, $oid, $version, $auth_user = '',
* usually on sysDescr on Cisco devices.
*/
$i = 0;

foreach($temp_array as $index => $value) {
if (preg_match('/(.*) =.*/', $value)) {
$parts = explode('=', $value, 2);
$snmp_array[$i]['oid'] = trim($parts[0]);
$snmp_array[$i]['value'] = format_snmp_string($parts[1], false, $value_output_format);
$parts = explode('=', $value, 2);
$t_oid = trim($parts[0]);
$t_value = $parts[1];

if (!cacti_snmp_validate_oid($t_oid)) {
cacti_log(sprintf('WARNING: SNMP Agent exploit attempted on SNMP agent from host ip: %s with oid: %s', $hostname, $t_oid), false, 'SECURITY');
continue;
}

$snmp_array[$i]['oid'] = $t_oid;
$snmp_array[$i]['value'] = $t_value;
$i++;
} else {
$snmp_array[$i-1]['value'] .= $value;
Expand All @@ -741,6 +762,15 @@ function cacti_snmp_walk($hostname, $community, $oid, $version, $auth_user = '',
}
}

/**
* replay the array to escape value data in case of a multi-line exploit
*/
if (cacti_sizeof($snmp_array)) {
foreach($snmp_array as $index => $data) {
$snmp_array[$index]['value'] = format_snmp_string($data['value'], false, $value_output_format);
}
}

return $snmp_array;
}

Expand Down
4 changes: 2 additions & 2 deletions scripts/ss_net_snmp_disk_bytes.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@ function ss_net_snmp_disk_bytes($host_id_or_hostname = '') {
}
}

$data = "'" . json_encode($current) . "'";
shell_exec("echo $data > $tmpdir/$tmpfile");
$data = json_encode($current);
file_put_contents("$tmpdir/$tmpfile", $data);
}

if ($found) {
Expand Down
4 changes: 2 additions & 2 deletions scripts/ss_net_snmp_disk_io.php
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ function ss_net_snmp_disk_io($host_id_or_hostname = '') {
}
}

$data = "'" . json_encode($current) . "'";
shell_exec("echo $data > $tmpdir/$tmpfile");
$data = json_encode($current);
file_put_contents("$tmpdir/$tmpfile", $data);
}

if ($found) {
Expand Down

0 comments on commit c7e4ee7

Please sign in to comment.