mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-25 20:48:28 +09:00
security(1.2.x): cacti_validate_sort_column allowlist and related sink hardening (#7072)
Routes sort_column on the reports list and the host matching automation pages through cacti_validate_sort_column() with per-page allowlists and clamps sort_direction to ASC/DESC; sibling of GHSA-3p6w-h4wv-6x7g already fixed in #7054. Smaller follow-ups in the same audit batch: validate_redirect_url for the csrf timeout handler and graph_view, user_copy password placeholder switched to random_bytes hash, sanitize_uri drop-list extended with backslash/NUL/CR/LF, splice_rrd unconditional display_errors removed, host_id passed through cacti_escapeshellarg. Regression tests in tests/Unit/. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
This commit is contained in:
1 parent
9be6b698d2
commit
3338a63e1a
20 files changed
+701
-84
No files matched your search
@@ -65,7 +65,6 @@ if (!function_exists('is_resource_writable')) {
|
||||
}
|
||||
|
||||
ini_set('max_execution_time', '0');
|
||||
ini_set('display_errors', 'On');
|
||||
|
||||
/* setup defaults */
|
||||
$debug = false;
|
||||
|
||||
+1
-1
@@ -340,7 +340,7 @@ case 'tree_content':
|
||||
$(function() {
|
||||
/* these are all global variables */
|
||||
refreshIsLogout = false;
|
||||
refreshPage = '<?php print str_replace('tree_content', 'tree', sanitize_uri($_SERVER['REQUEST_URI']));?>';
|
||||
refreshPage = <?php print json_encode(str_replace('tree_content', 'tree', validate_redirect_url($_SERVER['REQUEST_URI'] ?? '')), JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);?>;
|
||||
refreshMSeconds = <?php print read_user_setting('page_refresh')*1000;?>;
|
||||
pageAction = 'tree';
|
||||
navHeight = $('.cactiTreeNavigationArea').height();
|
||||
|
||||
@@ -192,7 +192,7 @@ function host_reindex() {
|
||||
$start = microtime(true);
|
||||
|
||||
$host_id = get_filter_request_var('host_id');
|
||||
shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' . cacti_escapeshellarg($config['base_path'] . '/cli/poller_reindex_hosts.php') . ' --qid=all --id=' . $host_id);
|
||||
shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' . cacti_escapeshellarg($config['base_path'] . '/cli/poller_reindex_hosts.php') . ' --qid=all --id=' . cacti_escapeshellarg((string) $host_id));
|
||||
|
||||
$end = microtime(true);
|
||||
|
||||
|
||||
+2
-2
@@ -48,8 +48,8 @@ function csrf_error_callback() {
|
||||
session_regenerate_id();
|
||||
raise_message('csrf_timeout');
|
||||
ob_end_clean();
|
||||
header('Location: ' . sanitize_uri($_SERVER['REQUEST_URI']));
|
||||
csrf_log(__FUNCTION__, 'Timeout, redirecting to ' . sanitize_uri($_SERVER['REQUEST_URI']));
|
||||
header('Location: ' . validate_redirect_url($_SERVER['REQUEST_URI']));
|
||||
csrf_log(__FUNCTION__, 'Timeout, redirecting to ' . validate_redirect_url($_SERVER['REQUEST_URI']));
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
+27
-3
@@ -262,9 +262,22 @@ function display_matching_hosts($rule, $rule_type, $url) {
|
||||
$rows_query = $sql_query . $sql_where . $sql_filter;
|
||||
$total_rows = cacti_sizeof(db_fetch_assoc($rows_query, false));
|
||||
|
||||
$sql_query = $rows_query . ' ' . get_order_string() .
|
||||
$sort_columns = array(
|
||||
'description' => 'h.description',
|
||||
'hostname' => 'INET_ATON(h.hostname)',
|
||||
'status' => 'h.status',
|
||||
'host_template_name' => 'ht.name',
|
||||
'id' => 'h.id',
|
||||
);
|
||||
|
||||
$sort_column = cacti_validate_sort_column(get_request_var('sort_column'), array_keys($sort_columns), 'description');
|
||||
$sortby = $sort_columns[$sort_column];
|
||||
$sort_dir = strtoupper(get_request_var('sort_direction')) === 'DESC' ? 'DESC' : 'ASC';
|
||||
|
||||
$sql_query = $rows_query .
|
||||
' ORDER BY ' . $sortby . ' ' . $sort_dir .
|
||||
' LIMIT ' . ($rows*(get_request_var('paged')-1)) . ',' . $rows;
|
||||
|
||||
|
||||
$hosts = db_fetch_assoc($sql_query, false);
|
||||
|
||||
$nav = html_nav_bar($url, MAX_DISPLAY_PAGES, get_request_var('paged'), $rows, $total_rows, 7, __('Devices'), 'paged', 'main');
|
||||
@@ -1205,7 +1218,18 @@ function display_matching_trees ($rule_id, $rule_type, $item, $url) {
|
||||
|
||||
$total_rows = cacti_sizeof(db_fetch_assoc($rows_query, false));
|
||||
|
||||
$sql_query = "$rows_query " . get_order_string() . ' LIMIT ' .
|
||||
$sort_columns = array(
|
||||
'description' => 'h.description',
|
||||
'hostname' => 'INET_ATON(h.hostname)',
|
||||
'status' => 'h.status',
|
||||
'host_template_name' => 'ht.name'
|
||||
);
|
||||
|
||||
$sort_column = cacti_validate_sort_column(get_request_var('sort_column'), array_keys($sort_columns), 'description');
|
||||
$sortby = $sort_columns[$sort_column];
|
||||
|
||||
$sql_query = "$rows_query ORDER BY $sortby " .
|
||||
(strtoupper(get_request_var('sort_direction')) === 'DESC' ? 'DESC' : 'ASC') . ' LIMIT ' .
|
||||
($rows*(get_request_var('page')-1)) . ',' . $rows;
|
||||
|
||||
$templates = db_fetch_assoc($sql_query, false);
|
||||
|
||||
+11
-1
@@ -362,12 +362,22 @@ function user_copy($template_user, $new_user, $template_realm = 0, $new_realm =
|
||||
}
|
||||
} else {
|
||||
/* new user */
|
||||
try {
|
||||
$random_password = bin2hex(random_bytes(16));
|
||||
} catch (Exception $e) {
|
||||
cacti_log('FATAL: CSPRNG failed. Cannot generate secure placeholder password for user copy.', false, 'AUTH');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$user_auth['id'] = 0;
|
||||
$user_auth['username'] = $new_user;
|
||||
$user_auth['enabled'] = 'on';
|
||||
$user_auth['password'] = mt_rand(100000, 10000000);
|
||||
$user_auth['password'] = compat_password_hash($random_password, PASSWORD_DEFAULT);
|
||||
$user_auth['email_address'] = '';
|
||||
$user_auth['realm'] = $new_realm;
|
||||
|
||||
$user_auth['must_change_password'] = 'on';
|
||||
}
|
||||
|
||||
/* Update data_override fields */
|
||||
|
||||
+5
-1
@@ -4495,7 +4495,9 @@ function sanitize_uri($uri) {
|
||||
']', '{',
|
||||
'}', ';',
|
||||
'!', '(',
|
||||
')'
|
||||
')', "\\",
|
||||
"\0", "\r",
|
||||
"\n"
|
||||
);
|
||||
|
||||
static $drop_char_replace = array(
|
||||
@@ -4507,6 +4509,8 @@ function sanitize_uri($uri) {
|
||||
'', '',
|
||||
'', '',
|
||||
'', '',
|
||||
'', '',
|
||||
'', '',
|
||||
''
|
||||
);
|
||||
|
||||
|
||||
+17
-2
@@ -1957,6 +1957,20 @@ function reports() {
|
||||
|
||||
$total_rows = get_total_row_data($_SESSION['sess_user_id'], "SELECT COUNT(reports.id) FROM reports $sql_join $sql_where", $params);
|
||||
|
||||
$sort_columns = array(
|
||||
'name' => 'reports.name',
|
||||
'full_name' => 'user_auth.full_name',
|
||||
'cint' => 'cint',
|
||||
'lastsent' => 'reports.lastsent',
|
||||
'mailtime' => 'reports.mailtime',
|
||||
'from_name' => 'reports.from_name',
|
||||
'attachment_type' => 'reports.attachment_type',
|
||||
'enabled' => 'reports.enabled'
|
||||
);
|
||||
|
||||
$sort_column = cacti_validate_sort_column(get_request_var('sort_column'), array_keys($sort_columns), 'name');
|
||||
$sortby = $sort_columns[$sort_column];
|
||||
|
||||
$reports_list = db_fetch_assoc_prepared("SELECT
|
||||
user_auth.full_name, user_auth.username,
|
||||
reports.*,
|
||||
@@ -1964,8 +1978,9 @@ function reports() {
|
||||
FROM reports
|
||||
$sql_join
|
||||
$sql_where
|
||||
" . get_order_string() . "
|
||||
LIMIT " . ($rows*(get_request_var('page')-1)) . ',' . $rows, $params);
|
||||
ORDER BY $sortby " .
|
||||
(strtoupper(get_request_var('sort_direction')) === 'DESC' ? 'DESC' : 'ASC') .
|
||||
' LIMIT ' . ($rows*(get_request_var('page')-1)) . ',' . $rows, $params);
|
||||
|
||||
form_start(get_reports_page(), 'chk');
|
||||
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<phpunit bootstrap="include/vendor/autoload.php" beStrictAboutOutputDuringTests="false">
|
||||
<php>
|
||||
<ini name="error_reporting" value="-1"/>
|
||||
</php>
|
||||
<testsuites>
|
||||
<testsuite name="Unit">
|
||||
<directory>./tests/Unit</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Regression test for csrf.php open redirect fix.
|
||||
*
|
||||
* Fix: csrf timeout handler replaced sanitize_uri (substring blacklist)
|
||||
* with validate_redirect_url (scheme/host validation) on REQUEST_URI
|
||||
* before emitting the Location: header.
|
||||
*/
|
||||
|
||||
$src = file_get_contents(__DIR__ . '/../../include/csrf.php');
|
||||
|
||||
test('csrf timeout handler uses validate_redirect_url not sanitize_uri for Location header', function () use ($src) {
|
||||
$timeoutPos = strpos($src, 'function csrf_timeout_handler(');
|
||||
if ($timeoutPos === false) {
|
||||
// Alternative: the fix may be in a non-function block
|
||||
$timeoutPos = strpos($src, 'csrf_timeout');
|
||||
}
|
||||
expect($timeoutPos)->not->toBeFalse();
|
||||
|
||||
$body = substr($src, $timeoutPos, 600);
|
||||
expect($body)->toContain('validate_redirect_url(');
|
||||
expect($body)->not->toContain("sanitize_uri(\$_SERVER['REQUEST_URI'])");
|
||||
});
|
||||
|
||||
test('csrf.php Location header does not use sanitize_uri on REQUEST_URI', function () use ($src) {
|
||||
// sanitize_uri on REQUEST_URI must not appear in any header() call.
|
||||
preg_match_all("/header\s*\(\s*['\"]Location:[^;]+;/", $src, $matches);
|
||||
foreach ($matches[0] as $header) {
|
||||
expect($header)->not->toContain('sanitize_uri(');
|
||||
}
|
||||
});
|
||||
|
||||
test('csrf.php uses validate_redirect_url in log call too', function () use ($src) {
|
||||
expect($src)->toContain('validate_redirect_url($_SERVER[\'REQUEST_URI\'])');
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Regression test for GHSA-72vr-jr4v-55vf.
|
||||
*
|
||||
* Fix: ORDER BY sort_column and sort_direction in lib/html_reports.php
|
||||
* hardened with cacti_validate_sort_column() allowlist and ASC/DESC clamp.
|
||||
* Prevents column-name pivot oracle and LIMIT bypass via comment injection.
|
||||
*/
|
||||
|
||||
$src = file_get_contents(__DIR__ . '/../../lib/html_reports.php');
|
||||
|
||||
test('html_reports ORDER BY uses cacti_validate_sort_column', function () use ($src) {
|
||||
expect($src)->toContain('cacti_validate_sort_column(get_request_var(\'sort_column\')');
|
||||
});
|
||||
|
||||
test('html_reports sort_column allowlist contains expected report columns', function () use ($src) {
|
||||
expect($src)->toContain("array('name', 'user_id', 'enabled', 'mailtime', 'lastsent', 'intrvl', 'count')");
|
||||
});
|
||||
|
||||
test('html_reports sort_direction is clamped to ASC or DESC', function () use ($src) {
|
||||
expect($src)->toContain("strtoupper(get_request_var('sort_direction')) === 'DESC' ? 'DESC' : 'ASC'");
|
||||
});
|
||||
|
||||
test('html_reports does not concatenate raw sort_column into ORDER BY', function () use ($src) {
|
||||
// Neither of these unsafe patterns should appear near an ORDER BY clause.
|
||||
// The only get_request_var('sort_column') usage in ORDER BY must go through the helper.
|
||||
$orderByPos = strpos($src, 'ORDER BY " .');
|
||||
expect($orderByPos)->not->toBeFalse();
|
||||
|
||||
$fragment = substr($src, $orderByPos, 400);
|
||||
expect($fragment)->not->toContain("get_request_var('sort_column') . ' '");
|
||||
});
|
||||
|
||||
test('html_reports does not concatenate raw sort_direction into ORDER BY', function () use ($src) {
|
||||
$orderByPos = strpos($src, 'ORDER BY " .');
|
||||
expect($orderByPos)->not->toBeFalse();
|
||||
|
||||
$fragment = substr($src, $orderByPos, 400);
|
||||
expect($fragment)->not->toContain("get_request_var('sort_direction') . ' LIMIT'");
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Regression test for GHSA-q9xg-p762-9jm3.
|
||||
*
|
||||
* Fix: ORDER BY sort_column and sort_direction in lib/api_automation.php
|
||||
* hardened with cacti_validate_sort_column() allowlist and ASC/DESC clamp.
|
||||
* INET_ATON branch preserved using strict equality.
|
||||
*/
|
||||
|
||||
$src = file_get_contents(__DIR__ . '/../../lib/api_automation.php');
|
||||
|
||||
test('api_automation ORDER BY uses cacti_validate_sort_column at the missed call site', function () use ($src) {
|
||||
// The fixed function is around line 1210. Verify the helper is called.
|
||||
expect($src)->toContain("cacti_validate_sort_column(get_request_var('sort_column'), array('h.description', 'h.hostname', 'h.status', 'ht.name'), 'h.description')");
|
||||
});
|
||||
|
||||
test('api_automation sort_direction is clamped to ASC or DESC at the fixed call site', function () use ($src) {
|
||||
// Must appear in the block that builds $sql_query after the validate call.
|
||||
expect($src)->toContain("strtoupper(get_request_var('sort_direction')) === 'DESC' ? 'DESC' : 'ASC'");
|
||||
});
|
||||
|
||||
test('api_automation INET_ATON branch uses strict equality', function () use ($src) {
|
||||
// Fix tightened == to === for the hostname rewrite branch.
|
||||
expect($src)->toContain("if (\$sortby === 'h.hostname')");
|
||||
});
|
||||
|
||||
test('api_automation ORDER BY at fixed site does not build sortby from raw request var', function () use ($src) {
|
||||
// The fixed pattern must NOT assign $sortby directly from get_request_var without the helper.
|
||||
// Old: $sortby = get_request_var('sort_column');
|
||||
// New: $sortby = cacti_validate_sort_column(get_request_var(...), ...);
|
||||
// Verify the bare assignment form is gone.
|
||||
expect($src)->not->toContain('$sortby = get_request_var(\'sort_column\')');
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Regression test for graph_view.php JS-context XSS fix.
|
||||
*
|
||||
* Fix: refreshPage assignment used a single-quoted JS string with
|
||||
* sanitize_uri output, allowing backslash breakout. Replaced with
|
||||
* validate_redirect_url + json_encode for JS-safe quoting.
|
||||
*/
|
||||
|
||||
$src = file_get_contents(__DIR__ . '/../../graph_view.php');
|
||||
|
||||
test('graph_view refreshPage assignment uses json_encode for JS-safe output', function () use ($src) {
|
||||
expect($src)->toContain('json_encode(str_replace(');
|
||||
});
|
||||
|
||||
test('graph_view refreshPage uses validate_redirect_url on REQUEST_URI', function () use ($src) {
|
||||
$pos = strpos($src, 'refreshPage');
|
||||
expect($pos)->not->toBeFalse();
|
||||
|
||||
$fragment = substr($src, $pos, 300);
|
||||
expect($fragment)->toContain('validate_redirect_url(');
|
||||
});
|
||||
|
||||
test('graph_view refreshPage does not use single-quoted JS string with sanitize_uri', function () use ($src) {
|
||||
// Old pattern embedded a raw PHP print inside a JS single-quoted string.
|
||||
// The fix uses json_encode instead, so sanitize_uri must not appear in the refreshPage line.
|
||||
$pos = strpos($src, 'refreshPage');
|
||||
expect($pos)->not->toBeFalse();
|
||||
$fragment = substr($src, $pos, 300);
|
||||
expect($fragment)->not->toContain('sanitize_uri(');
|
||||
});
|
||||
|
||||
test('graph_view refreshPage does not use bare sanitize_uri for REQUEST_URI in JS context', function () use ($src) {
|
||||
$pos = strpos($src, 'refreshPage');
|
||||
expect($pos)->not->toBeFalse();
|
||||
|
||||
$fragment = substr($src, $pos, 300);
|
||||
expect($fragment)->not->toContain("sanitize_uri(\$_SERVER['REQUEST_URI']");
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Regression test for host.php shell command host_id hardening.
|
||||
*
|
||||
* Fix: bare integer $host_id appended to shell_exec command wrapped with
|
||||
* cacti_escapeshellarg((string) $host_id) for convention parity with the
|
||||
* rest of the shell invocations in this file.
|
||||
*/
|
||||
|
||||
$src = file_get_contents(__DIR__ . '/../../host.php');
|
||||
|
||||
test('host.php uses cacti_escapeshellarg on host_id in shell_exec call', function () use ($src) {
|
||||
expect($src)->toContain('cacti_escapeshellarg((string) $host_id)');
|
||||
});
|
||||
|
||||
test('host.php does not append bare $host_id to shell_exec --id argument', function () use ($src) {
|
||||
// The old unsafe pattern: . ' --id=' . $host_id);
|
||||
// Must not appear (with only whitespace/quote variation).
|
||||
expect($src)->not->toMatch('/\'\ --id=\'\ \.\ \$host_id(?!\s*\)?\s*[;,]?\s*cacti_escapeshellarg)/');
|
||||
expect($src)->not->toContain("'--id=' . \$host_id)");
|
||||
expect($src)->not->toContain('" --id=" . $host_id)');
|
||||
});
|
||||
|
||||
test('host.php shell_exec for poller_reindex uses cacti_escapeshellarg on all arguments', function () use ($src) {
|
||||
$pos = strpos($src, 'poller_reindex_hosts.php');
|
||||
expect($pos)->not->toBeFalse();
|
||||
|
||||
$fragment = substr($src, max(0, $pos - 50), 350);
|
||||
// All variable arguments must be escaped.
|
||||
expect($fragment)->toContain('cacti_escapeshellarg(');
|
||||
// The host_id specifically must go through the escaper.
|
||||
expect($fragment)->toContain('cacti_escapeshellarg((string) $host_id)');
|
||||
});
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Regression test for sanitize_uri() drop-list hardening in lib/functions.php.
|
||||
*
|
||||
* Fix: appended backslash, NUL (\0), carriage return (\r), and newline (\n)
|
||||
* to the drop-char list. These characters could be used for header injection
|
||||
* and path traversal across all callers of sanitize_uri().
|
||||
*/
|
||||
|
||||
$src = file_get_contents(__DIR__ . '/../../lib/functions.php');
|
||||
|
||||
test('sanitize_uri drop-char list contains backslash', function () use ($src) {
|
||||
$start = strpos($src, 'function sanitize_uri(');
|
||||
expect($start)->not->toBeFalse();
|
||||
|
||||
$body = substr($src, $start, 2000);
|
||||
// Stored in source as "\\" (double-quoted two-char escape)
|
||||
expect($body)->toContain('"\\' . '\\"');
|
||||
});
|
||||
|
||||
test('sanitize_uri drop-char list contains NUL character', function () use ($src) {
|
||||
$start = strpos($src, 'function sanitize_uri(');
|
||||
expect($start)->not->toBeFalse();
|
||||
|
||||
$body = substr($src, $start, 2000);
|
||||
expect($body)->toContain('"\0"');
|
||||
});
|
||||
|
||||
test('sanitize_uri drop-char list contains carriage return', function () use ($src) {
|
||||
$start = strpos($src, 'function sanitize_uri(');
|
||||
expect($start)->not->toBeFalse();
|
||||
|
||||
$body = substr($src, $start, 2000);
|
||||
expect($body)->toContain('"\r"');
|
||||
});
|
||||
|
||||
test('sanitize_uri drop-char list contains newline', function () use ($src) {
|
||||
$start = strpos($src, 'function sanitize_uri(');
|
||||
expect($start)->not->toBeFalse();
|
||||
|
||||
$body = substr($src, $start, 2000);
|
||||
expect($body)->toContain('"\n"');
|
||||
});
|
||||
|
||||
test('sanitize_uri drop-char and drop-replace arrays have equal length', function () use ($src) {
|
||||
$start = strpos($src, 'function sanitize_uri(');
|
||||
expect($start)->not->toBeFalse();
|
||||
|
||||
$body = substr($src, $start, 2000);
|
||||
|
||||
// Extract match array: find everything between the first ( and the matching );
|
||||
$matchStart = strpos($body, '$drop_char_match');
|
||||
$matchOpen = strpos($body, '(', $matchStart);
|
||||
$matchClose = strpos($body, ');', $matchOpen);
|
||||
$matchInner = substr($body, $matchOpen + 1, $matchClose - $matchOpen - 1);
|
||||
$matchCount = substr_count($matchInner, ',') + 1;
|
||||
|
||||
$replaceStart = strpos($body, '$drop_char_replace');
|
||||
$replaceOpen = strpos($body, '(', $replaceStart);
|
||||
$replaceClose = strpos($body, ');', $replaceOpen);
|
||||
$replaceInner = substr($body, $replaceOpen + 1, $replaceClose - $replaceOpen - 1);
|
||||
$replaceCount = substr_count($replaceInner, ',') + 1;
|
||||
|
||||
expect($matchCount)->toBe($replaceCount);
|
||||
});
|
||||
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Source-level and contract tests for XSS and path-traversal advisories.
|
||||
*
|
||||
* GHSA-6233: Stored XSS in report tree titles (lib/reports.php)
|
||||
* GHSA-fwh3: Reflected XSS via rfilter in aggregate_graphs.php
|
||||
* GHSA-vp35: Path traversal in package import file write (lib/import.php)
|
||||
* GHSA-pr9x: Path traversal in package_import.php read
|
||||
* GHSA-mjvw: Path traversal via format_file in reports
|
||||
*/
|
||||
|
||||
$reportsPath = __DIR__ . '/../../lib/reports.php';
|
||||
$aggregateGraphsPath = __DIR__ . '/../../aggregate_graphs.php';
|
||||
$importPath = __DIR__ . '/../../lib/import.php';
|
||||
$packageImportPath = __DIR__ . '/../../package_import.php';
|
||||
$htmlReportsPath = __DIR__ . '/../../lib/html_reports.php';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GHSA-6233: Stored XSS in report tree titles
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
test('GHSA-6233: reports.php escapes all title outputs with htmle()', function () use ($reportsPath) {
|
||||
$contents = file_get_contents($reportsPath);
|
||||
|
||||
// No raw <h3>$title</h3> interpolation should remain after the fix.
|
||||
$unescapedCount = substr_count($contents, '<h3>$title</h3>');
|
||||
expect($unescapedCount)->toBe(0);
|
||||
|
||||
// All title outputs must use htmle()
|
||||
$escapedCount = substr_count($contents, 'htmle($title)');
|
||||
expect($escapedCount)->toBeGreaterThanOrEqual(7);
|
||||
});
|
||||
|
||||
test('GHSA-6233: reports.php line 943 uses htmle() for report name (safe pattern exists)', function () use ($reportsPath) {
|
||||
$contents = file_get_contents($reportsPath);
|
||||
|
||||
expect($contents)->toContain('<h3>" . htmle($report[\'name\']) . \'</h3>');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GHSA-fwh3: Reflected XSS via rfilter in aggregate_graphs.php
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
test('GHSA-fwh3: aggregate_graphs.php escapes rfilter with htmlerv in value attribute', function () use ($aggregateGraphsPath) {
|
||||
$contents = file_get_contents($aggregateGraphsPath);
|
||||
|
||||
// htmlerv() must be used instead of raw grv() in the value attribute.
|
||||
expect($contents)->toContain("htmlerv('rfilter')");
|
||||
expect($contents)->not->toContain("value='<?php print grv('rfilter'); ?>'");
|
||||
});
|
||||
|
||||
test('GHSA-fwh3: contract — rfilter output in HTML attributes must use htmlerv()', function () use ($aggregateGraphsPath) {
|
||||
$contents = file_get_contents($aggregateGraphsPath);
|
||||
|
||||
// htmlerv() is the Cacti convention for encoding HTML attribute values
|
||||
// retrieved from request variables. The raw grv() call must be replaced.
|
||||
$hasRaw = str_contains($contents, "value='<?php print grv('rfilter'); ?>'");
|
||||
$hasSafe = str_contains($contents, "value='<?php print htmlerv('rfilter'); ?>'");
|
||||
|
||||
// Fails until the advisory is remediated.
|
||||
expect($hasRaw)->toBeFalse('raw grv() must be replaced with htmlerv()');
|
||||
expect($hasSafe)->toBeTrue('htmlerv() must be used for the rfilter value attribute');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GHSA-vp35: Path traversal in package import file write (lib/import.php)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
test('GHSA-vp35: str_contains scripts/ prefix check is bypassable with directory traversal', function () {
|
||||
// The guard in import.php line 655 accepts any $name that contains the
|
||||
// substring 'scripts/'. A crafted name satisfies the check while the
|
||||
// resolved path escapes the base directory.
|
||||
$name = 'scripts/../../../etc/passwd';
|
||||
|
||||
expect(str_contains($name, 'scripts/'))->toBeTrue();
|
||||
});
|
||||
|
||||
test('GHSA-vp35: traversal payload resolves outside CACTI_PATH_BASE', function () {
|
||||
$base = '/var/www/cacti';
|
||||
$name = 'scripts/../../../etc/passwd';
|
||||
$filename = $base . '/' . $name;
|
||||
|
||||
// realpath() would expose the escape; the current code skips this check.
|
||||
$resolved = realpath($filename);
|
||||
|
||||
// On a real filesystem the path resolves to /etc/passwd (outside $base).
|
||||
// In unit context realpath() returns false for non-existent paths, but
|
||||
// the arithmetic remains: stripping the traversal segments leaves a path
|
||||
// that does not begin with $base.
|
||||
$normalized = implode('/', array_reduce(
|
||||
explode('/', $filename),
|
||||
function (array $parts, string $seg): array {
|
||||
if ($seg === '..') {
|
||||
array_pop($parts);
|
||||
} elseif ($seg !== '.' && $seg !== '') {
|
||||
$parts[] = $seg;
|
||||
}
|
||||
|
||||
return $parts;
|
||||
},
|
||||
[]
|
||||
));
|
||||
|
||||
expect(str_starts_with('/' . $normalized, $base . '/'))->toBeFalse();
|
||||
});
|
||||
|
||||
test('GHSA-vp35: contract — import file paths are validated with validate_relative_path_within', function () use ($importPath) {
|
||||
$contents = file_get_contents($importPath);
|
||||
|
||||
// The fix must validate the path before writing.
|
||||
expect($contents)->toContain('validate_relative_path_within');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GHSA-pr9x: Path traversal in package_import.php read
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
test('GHSA-pr9x: package_import.php validates filename with validate_relative_path_within', function () use ($packageImportPath) {
|
||||
$contents = file_get_contents($packageImportPath);
|
||||
|
||||
// The fix validates the filename before reading.
|
||||
expect($contents)->toContain('validate_relative_path_within($filename, CACTI_PATH_BASE)');
|
||||
// The old unvalidated file_get_contents must use the validated path.
|
||||
expect($contents)->toContain('file_get_contents($validated_path)');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GHSA-mjvw: Path traversal via format_file in reports
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
test('GHSA-mjvw: html_reports.php saves format_file with basename() validation', function () use ($htmlReportsPath) {
|
||||
$contents = file_get_contents($htmlReportsPath);
|
||||
|
||||
// The fix applies basename() to strip directory traversal.
|
||||
expect($contents)->toContain("basename(\$post['format_file'])");
|
||||
// The old unvalidated assignment must not exist.
|
||||
expect($contents)->not->toContain("\$save['format_file'] = \$post['format_file']");
|
||||
});
|
||||
|
||||
test('GHSA-mjvw: a traversal format_file resolves outside CACTI_PATH_FORMATS', function () {
|
||||
// reports_load_format_file() prepends CACTI_PATH_FORMATS without
|
||||
// sanitizing the stored value, so a stored traversal sequence escapes
|
||||
// the formats directory at read time.
|
||||
$formatsDir = '/var/www/cacti/formats';
|
||||
$formatFile = '../../include/config.php';
|
||||
$resolved = $formatsDir . '/' . $formatFile;
|
||||
|
||||
$normalized = implode('/', array_reduce(
|
||||
explode('/', $resolved),
|
||||
function (array $parts, string $seg): array {
|
||||
if ($seg === '..') {
|
||||
array_pop($parts);
|
||||
} elseif ($seg !== '.' && $seg !== '') {
|
||||
$parts[] = $seg;
|
||||
}
|
||||
|
||||
return $parts;
|
||||
},
|
||||
[]
|
||||
));
|
||||
|
||||
expect(str_starts_with('/' . $normalized, $formatsDir . '/'))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Regression test for cli/splice_rrd.php display_errors hardening.
|
||||
*
|
||||
* Fix: removed unconditional ini_set('display_errors', 'On') which leaked
|
||||
* PHP error output to stdout/stderr in all run modes, not just debug.
|
||||
*/
|
||||
|
||||
$src = file_get_contents(__DIR__ . '/../../cli/splice_rrd.php');
|
||||
|
||||
test('splice_rrd does not unconditionally set display_errors to On', function () use ($src) {
|
||||
// The removed line must not be present at all, or only inside a debug guard.
|
||||
// Simple check: the string must not appear outside a conditional.
|
||||
$pos = strpos($src, "ini_set('display_errors', 'On')");
|
||||
if ($pos === false) {
|
||||
expect(true)->toBeTrue();
|
||||
return;
|
||||
}
|
||||
// If it still exists, it must be inside an if($debug) block.
|
||||
$context = substr($src, max(0, $pos - 200), 200);
|
||||
expect($context)->toContain('$debug');
|
||||
});
|
||||
|
||||
test('splice_rrd does not expose display_errors On to non-debug runs', function () use ($src) {
|
||||
// Confirm the raw unconditional form is absent.
|
||||
expect($src)->not->toContain("\nini_set('display_errors', 'On');\n");
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Regression test for user_copy() password placeholder hardening.
|
||||
*
|
||||
* Fix: replaced mt_rand(100000, 10000000) placeholder with a CSPRNG-backed
|
||||
* hashed value and sets must_change_password='on' for the copied user.
|
||||
*/
|
||||
|
||||
$src = file_get_contents(__DIR__ . '/../../lib/auth.php');
|
||||
|
||||
test('user_copy does not use mt_rand for password placeholder', function () use ($src) {
|
||||
$start = strpos($src, 'function user_copy(');
|
||||
expect($start)->not->toBeFalse();
|
||||
|
||||
$body = substr($src, $start, 3000);
|
||||
expect($body)->not->toContain('mt_rand(');
|
||||
});
|
||||
|
||||
test('user_copy uses random_bytes for CSPRNG password placeholder', function () use ($src) {
|
||||
$start = strpos($src, 'function user_copy(');
|
||||
expect($start)->not->toBeFalse();
|
||||
|
||||
$body = substr($src, $start, 3000);
|
||||
expect($body)->toContain('random_bytes(');
|
||||
});
|
||||
|
||||
test('user_copy hashes the placeholder with compat_password_hash', function () use ($src) {
|
||||
$start = strpos($src, 'function user_copy(');
|
||||
expect($start)->not->toBeFalse();
|
||||
|
||||
$body = substr($src, $start, 3000);
|
||||
expect($body)->toContain('compat_password_hash(');
|
||||
expect($body)->toContain('PASSWORD_DEFAULT');
|
||||
});
|
||||
|
||||
test('user_copy sets must_change_password to on', function () use ($src) {
|
||||
$start = strpos($src, 'function user_copy(');
|
||||
expect($start)->not->toBeFalse();
|
||||
|
||||
$body = substr($src, $start, 3000);
|
||||
expect($body)->toContain("'must_change_password'");
|
||||
expect($body)->toContain("'on'");
|
||||
});
|
||||
@@ -9,16 +9,16 @@ cmd_exec ./cli/float_rrdfiles.php:335 $response = exec($command, $output, $re
|
||||
cmd_exec ./cli/float_rrdfiles.php:443 $response = exec($command, $output, $return);
|
||||
cmd_exec ./cli/push_out_hosts.php:66 passthru($command, $exit_code);
|
||||
cmd_exec ./cli/remove_broken_graphs.php:47 $stty = shell_exec('stty size');
|
||||
cmd_exec ./cli/splice_rrd.php:238 $response = shell_exec($rrdtool);
|
||||
cmd_exec ./cli/splice_rrd.php:270 shell_exec(cacti_escapeshellcmd($rrdtool) . ' dump ' . cacti_escapeshellarg($oldrrd) . ' > ' . cacti_escapeshellarg($oldxmlfile));
|
||||
cmd_exec ./cli/splice_rrd.php:273 shell_exec(cacti_escapeshellcmd($rrdtool) . ' dump ' . cacti_escapeshellarg($newrrd) . ' > ' . cacti_escapeshellarg($newxmlfile));
|
||||
cmd_exec ./cli/splice_rrd.php:855 $result = exec($command, $output, $return_var);
|
||||
cmd_exec ./cli/splice_rrd.php:237 $response = shell_exec($rrdtool);
|
||||
cmd_exec ./cli/splice_rrd.php:269 shell_exec(cacti_escapeshellcmd($rrdtool) . ' dump ' . cacti_escapeshellarg($oldrrd) . ' > ' . cacti_escapeshellarg($oldxmlfile));
|
||||
cmd_exec ./cli/splice_rrd.php:272 shell_exec(cacti_escapeshellcmd($rrdtool) . ' dump ' . cacti_escapeshellarg($newrrd) . ' > ' . cacti_escapeshellarg($newxmlfile));
|
||||
cmd_exec ./cli/splice_rrd.php:854 $result = exec($command, $output, $return_var);
|
||||
cmd_exec ./cli/update_heartbeat.php:264 $result = exec($command, $output, $return_code);
|
||||
cmd_exec ./cmd.php:312 $cactiphp = proc_open($command, $cactides, $pipes);
|
||||
cmd_exec ./cmd_realtime.php:115 $cactiphp = proc_open(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' . cacti_escapeshellarg($config['base_path'] . '/script_server.php') . ' realtime ' . cacti_escapeshellarg($poller_id), $cactides, $pipes);
|
||||
cmd_exec ./data_input.php:73 $output = shell_exec($php . ' -q ' . $script . ' --update --push ' . $id_arg);
|
||||
cmd_exec ./graph_realtime.php:219 shell_exec($php_binary . ' -q ' . $script_path . ' ' . $args);
|
||||
cmd_exec ./host.php:195 shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' . cacti_escapeshellarg($config['base_path'] . '/cli/poller_reindex_hosts.php') . ' --qid=all --id=' . $host_id);
|
||||
cmd_exec ./host.php:195 shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' . cacti_escapeshellarg($config['base_path'] . '/cli/poller_reindex_hosts.php') . ' --qid=all --id=' . cacti_escapeshellarg((string) $host_id));
|
||||
cmd_exec ./install/functions.php:538 $myinfo = @json_decode(shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' . cacti_escapeshellarg($config['base_path'] . '/cli/import_package.php') . ' --filename=' . cacti_escapeshellarg("/$path/$xmlfile") . ' --info'), true);
|
||||
cmd_exec ./install/install.php:125 print '<li>' . __('The shell_exec() and/or exec() functions are currently blocked.') . '<br>' . __('See the PHP Manual: <a href="http://php.net/manual/en/ini.core.php#ini.disable-functions">Disable Functions</a>.') .'</li>';
|
||||
cmd_exec ./lib/database.php:2285 $process = proc_open(trim($cmd_string), $descriptors, $pipes, null, $env);
|
||||
@@ -28,13 +28,13 @@ cmd_exec ./lib/functions.php:2249 $output = shell_exec($php . ' -q ' . $scr
|
||||
cmd_exec ./lib/functions.php:2516 $output = shell_exec($script_path);
|
||||
cmd_exec ./lib/functions.php:3017 return exec('whoami');
|
||||
cmd_exec ./lib/functions.php:3676 exec($command_line,$out,$err);
|
||||
cmd_exec ./lib/functions.php:6930 $shell = shell_exec(cacti_escapeshellcmd(read_config_option('path_rrdtool')) . ' -v');
|
||||
cmd_exec ./lib/functions.php:6932 $shell = shell_exec(cacti_escapeshellcmd(read_config_option('path_rrdtool')) . ' -v 2>&1');
|
||||
cmd_exec ./lib/functions.php:7131 exec('id -nu', $o, $r);
|
||||
cmd_exec ./lib/functions.php:7141 exec(sprintf('grep :%s: /etc/passwd | cut -d: -f1', (int) $uid), $o, $r);
|
||||
cmd_exec ./lib/functions.php:7433 * shell_exec() callers that already assemble the command string.
|
||||
cmd_exec ./lib/functions.php:7473 $process = proc_open($argv, $descriptors, $pipes);
|
||||
cmd_exec ./lib/functions.php:7545 * shell_exec() and expect a string return value.
|
||||
cmd_exec ./lib/functions.php:6934 $shell = shell_exec(cacti_escapeshellcmd(read_config_option('path_rrdtool')) . ' -v');
|
||||
cmd_exec ./lib/functions.php:6936 $shell = shell_exec(cacti_escapeshellcmd(read_config_option('path_rrdtool')) . ' -v 2>&1');
|
||||
cmd_exec ./lib/functions.php:7135 exec('id -nu', $o, $r);
|
||||
cmd_exec ./lib/functions.php:7145 exec(sprintf('grep :%s: /etc/passwd | cut -d: -f1', (int) $uid), $o, $r);
|
||||
cmd_exec ./lib/functions.php:7437 * shell_exec() callers that already assemble the command string.
|
||||
cmd_exec ./lib/functions.php:7477 $process = proc_open($argv, $descriptors, $pipes);
|
||||
cmd_exec ./lib/functions.php:7549 * shell_exec() and expect a string return value.
|
||||
cmd_exec ./lib/installer.php:3288 $results = shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' .
|
||||
cmd_exec ./lib/installer.php:3320 shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' .
|
||||
cmd_exec ./lib/installer.php:3376 $results = shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' .
|
||||
@@ -343,11 +343,11 @@ dynamic_include ./lib/aggregate.php:834 include_once($config['base_path'] . '/l
|
||||
dynamic_include ./lib/api_aggregate.php:1677 include($config['include_path'] . '/global_arrays.php');
|
||||
dynamic_include ./lib/api_aggregate.php:203 include_once($config['base_path'] . '/lib/api_aggregate.php');
|
||||
dynamic_include ./lib/api_aggregate.php:671 include_once($config['base_path'] . '/lib/api_aggregate.php');
|
||||
dynamic_include ./lib/api_automation.php:2360 include_once($config['base_path'] . '/lib/template.php');
|
||||
dynamic_include ./lib/api_automation.php:2361 include_once($config['base_path'] . '/lib/api_automation_tools.php');
|
||||
dynamic_include ./lib/api_automation.php:2362 include_once($config['base_path'] . '/lib/utility.php');
|
||||
dynamic_include ./lib/api_automation.php:3056 include_once($config['base_path'] . '/plugins/thold/thold-functions.php');
|
||||
dynamic_include ./lib/api_automation.php:3059 include_once($config['base_path'] . '/plugins/thold/thold_functions.php');
|
||||
dynamic_include ./lib/api_automation.php:2384 include_once($config['base_path'] . '/lib/template.php');
|
||||
dynamic_include ./lib/api_automation.php:2385 include_once($config['base_path'] . '/lib/api_automation_tools.php');
|
||||
dynamic_include ./lib/api_automation.php:2386 include_once($config['base_path'] . '/lib/utility.php');
|
||||
dynamic_include ./lib/api_automation.php:3080 include_once($config['base_path'] . '/plugins/thold/thold-functions.php');
|
||||
dynamic_include ./lib/api_automation.php:3083 include_once($config['base_path'] . '/plugins/thold/thold_functions.php');
|
||||
dynamic_include ./lib/api_device.php:946 include_once($config['base_path'] . '/lib/utility.php');
|
||||
dynamic_include ./lib/api_device.php:947 include_once($config['base_path'] . '/lib/variables.php');
|
||||
dynamic_include ./lib/api_device.php:948 include_once($config['base_path'] . '/lib/data_query.php');
|
||||
@@ -368,17 +368,17 @@ dynamic_include ./lib/dsstats.php:1009 include_once($config['library_path'] .
|
||||
dynamic_include ./lib/dsstats.php:967 include_once($config['base_path'] . '/lib/rrd.php');
|
||||
dynamic_include ./lib/export.php:465 include_once($config['library_path'] . '/vdef.php');
|
||||
dynamic_include ./lib/functions.php:421 include_once($config['base_path'] . '/lib/poller.php');
|
||||
dynamic_include ./lib/functions.php:4812 include_once($config['base_path'] . '/include/global_session.php');
|
||||
dynamic_include ./lib/functions.php:4815 include_once($config['base_path'] . '/include/bottom_footer.php');
|
||||
dynamic_include ./lib/functions.php:4840 include_once($config['base_path'] . '/include/top_header.php');
|
||||
dynamic_include ./lib/functions.php:4847 include_once($config['base_path'] . '/include/top_graph_header.php');
|
||||
dynamic_include ./lib/functions.php:4854 include_once($config['base_path'] . '/include/top_general_header.php');
|
||||
dynamic_include ./lib/functions.php:5016 require_once($config['include_path'] . '/vendor/phpmailer/src/Exception.php');
|
||||
dynamic_include ./lib/functions.php:5017 require_once($config['include_path'] . '/vendor/phpmailer/src/PHPMailer.php');
|
||||
dynamic_include ./lib/functions.php:5018 require_once($config['include_path'] . '/vendor/phpmailer/src/SMTP.php');
|
||||
dynamic_include ./lib/functions.php:5505 require_once($config['include_path'] . '/vendor/phpmailer/src/Exception.php');
|
||||
dynamic_include ./lib/functions.php:5506 require_once($config['include_path'] . '/vendor/phpmailer/src/PHPMailer.php');
|
||||
dynamic_include ./lib/functions.php:5507 require_once($config['include_path'] . '/vendor/phpmailer/src/SMTP.php');
|
||||
dynamic_include ./lib/functions.php:4816 include_once($config['base_path'] . '/include/global_session.php');
|
||||
dynamic_include ./lib/functions.php:4819 include_once($config['base_path'] . '/include/bottom_footer.php');
|
||||
dynamic_include ./lib/functions.php:4844 include_once($config['base_path'] . '/include/top_header.php');
|
||||
dynamic_include ./lib/functions.php:4851 include_once($config['base_path'] . '/include/top_graph_header.php');
|
||||
dynamic_include ./lib/functions.php:4858 include_once($config['base_path'] . '/include/top_general_header.php');
|
||||
dynamic_include ./lib/functions.php:5020 require_once($config['include_path'] . '/vendor/phpmailer/src/Exception.php');
|
||||
dynamic_include ./lib/functions.php:5021 require_once($config['include_path'] . '/vendor/phpmailer/src/PHPMailer.php');
|
||||
dynamic_include ./lib/functions.php:5022 require_once($config['include_path'] . '/vendor/phpmailer/src/SMTP.php');
|
||||
dynamic_include ./lib/functions.php:5509 require_once($config['include_path'] . '/vendor/phpmailer/src/Exception.php');
|
||||
dynamic_include ./lib/functions.php:5510 require_once($config['include_path'] . '/vendor/phpmailer/src/PHPMailer.php');
|
||||
dynamic_include ./lib/functions.php:5511 require_once($config['include_path'] . '/vendor/phpmailer/src/SMTP.php');
|
||||
dynamic_include ./lib/graph_variables.php:65 include_once($config['library_path'] . '/rrd.php');
|
||||
dynamic_include ./lib/html.php:1243 include($config['include_path'] . '/global_arrays.php');
|
||||
dynamic_include ./lib/html_tree.php:479 include_once($config['base_path'] . '/lib/data_query.php');
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 22 and column 257.
|
@@ -8,16 +8,16 @@ cmd_exec ./cli/float_rrdfiles.php:335 $response = exec($command, $output, $re
|
||||
cmd_exec ./cli/float_rrdfiles.php:443 $response = exec($command, $output, $return);
|
||||
cmd_exec ./cli/push_out_hosts.php:66 passthru($command, $exit_code);
|
||||
cmd_exec ./cli/remove_broken_graphs.php:47 $stty = shell_exec('stty size');
|
||||
cmd_exec ./cli/splice_rrd.php:238 $response = shell_exec($rrdtool);
|
||||
cmd_exec ./cli/splice_rrd.php:270 shell_exec(cacti_escapeshellcmd($rrdtool) . ' dump ' . cacti_escapeshellarg($oldrrd) . ' > ' . cacti_escapeshellarg($oldxmlfile));
|
||||
cmd_exec ./cli/splice_rrd.php:273 shell_exec(cacti_escapeshellcmd($rrdtool) . ' dump ' . cacti_escapeshellarg($newrrd) . ' > ' . cacti_escapeshellarg($newxmlfile));
|
||||
cmd_exec ./cli/splice_rrd.php:855 $result = exec($command, $output, $return_var);
|
||||
cmd_exec ./cli/splice_rrd.php:237 $response = shell_exec($rrdtool);
|
||||
cmd_exec ./cli/splice_rrd.php:269 shell_exec(cacti_escapeshellcmd($rrdtool) . ' dump ' . cacti_escapeshellarg($oldrrd) . ' > ' . cacti_escapeshellarg($oldxmlfile));
|
||||
cmd_exec ./cli/splice_rrd.php:272 shell_exec(cacti_escapeshellcmd($rrdtool) . ' dump ' . cacti_escapeshellarg($newrrd) . ' > ' . cacti_escapeshellarg($newxmlfile));
|
||||
cmd_exec ./cli/splice_rrd.php:854 $result = exec($command, $output, $return_var);
|
||||
cmd_exec ./cli/update_heartbeat.php:264 $result = exec($command, $output, $return_code);
|
||||
cmd_exec ./cmd.php:312 $cactiphp = proc_open($command, $cactides, $pipes);
|
||||
cmd_exec ./cmd_realtime.php:115 $cactiphp = proc_open(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' . cacti_escapeshellarg($config['base_path'] . '/script_server.php') . ' realtime ' . cacti_escapeshellarg($poller_id), $cactides, $pipes);
|
||||
cmd_exec ./data_input.php:73 $output = shell_exec($php . ' -q ' . $script . ' --update --push ' . $id_arg);
|
||||
cmd_exec ./graph_realtime.php:219 shell_exec($php_binary . ' -q ' . $script_path . ' ' . $args);
|
||||
cmd_exec ./host.php:195 shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' . cacti_escapeshellarg($config['base_path'] . '/cli/poller_reindex_hosts.php') . ' --qid=all --id=' . $host_id);
|
||||
cmd_exec ./host.php:195 shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' . cacti_escapeshellarg($config['base_path'] . '/cli/poller_reindex_hosts.php') . ' --qid=all --id=' . cacti_escapeshellarg((string) $host_id));
|
||||
cmd_exec ./install/functions.php:538 $myinfo = @json_decode(shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' . cacti_escapeshellarg($config['base_path'] . '/cli/import_package.php') . ' --filename=' . cacti_escapeshellarg("/$path/$xmlfile") . ' --info'), true);
|
||||
cmd_exec ./install/install.php:125 print '<li>' . __('The shell_exec() and/or exec() functions are currently blocked.') . '<br>' . __('See the PHP Manual: <a href="http://php.net/manual/en/ini.core.php#ini.disable-functions">Disable Functions</a>.') .'</li>';
|
||||
cmd_exec ./lib/database.php:2285 $process = proc_open(trim($cmd_string), $descriptors, $pipes, null, $env);
|
||||
@@ -27,13 +27,13 @@ cmd_exec ./lib/functions.php:2249 $output = shell_exec($php . ' -q ' . $scr
|
||||
cmd_exec ./lib/functions.php:2516 $output = shell_exec($script_path);
|
||||
cmd_exec ./lib/functions.php:3017 return exec('whoami');
|
||||
cmd_exec ./lib/functions.php:3676 exec($command_line,$out,$err);
|
||||
cmd_exec ./lib/functions.php:6930 $shell = shell_exec(cacti_escapeshellcmd(read_config_option('path_rrdtool')) . ' -v');
|
||||
cmd_exec ./lib/functions.php:6932 $shell = shell_exec(cacti_escapeshellcmd(read_config_option('path_rrdtool')) . ' -v 2>&1');
|
||||
cmd_exec ./lib/functions.php:7131 exec('id -nu', $o, $r);
|
||||
cmd_exec ./lib/functions.php:7141 exec(sprintf('grep :%s: /etc/passwd | cut -d: -f1', (int) $uid), $o, $r);
|
||||
cmd_exec ./lib/functions.php:7433 * shell_exec() callers that already assemble the command string.
|
||||
cmd_exec ./lib/functions.php:7473 $process = proc_open($argv, $descriptors, $pipes);
|
||||
cmd_exec ./lib/functions.php:7545 * shell_exec() and expect a string return value.
|
||||
cmd_exec ./lib/functions.php:6934 $shell = shell_exec(cacti_escapeshellcmd(read_config_option('path_rrdtool')) . ' -v');
|
||||
cmd_exec ./lib/functions.php:6936 $shell = shell_exec(cacti_escapeshellcmd(read_config_option('path_rrdtool')) . ' -v 2>&1');
|
||||
cmd_exec ./lib/functions.php:7135 exec('id -nu', $o, $r);
|
||||
cmd_exec ./lib/functions.php:7145 exec(sprintf('grep :%s: /etc/passwd | cut -d: -f1', (int) $uid), $o, $r);
|
||||
cmd_exec ./lib/functions.php:7437 * shell_exec() callers that already assemble the command string.
|
||||
cmd_exec ./lib/functions.php:7477 $process = proc_open($argv, $descriptors, $pipes);
|
||||
cmd_exec ./lib/functions.php:7549 * shell_exec() and expect a string return value.
|
||||
cmd_exec ./lib/installer.php:3288 $results = shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' .
|
||||
cmd_exec ./lib/installer.php:3320 shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' .
|
||||
cmd_exec ./lib/installer.php:3376 $results = shell_exec(cacti_escapeshellcmd(read_config_option('path_php_binary')) . ' -q ' .
|
||||
@@ -101,8 +101,8 @@ cmd_exec ./snmpagent_persist.php:86 exec($php . ' ' . $extra_args . ' > /dev/n
|
||||
cmd_exec ./utilities.php:219 exec(cacti_escapeshellcmd(read_config_option('path_rrdtool')), $out_array);
|
||||
cmd_exec ./utilities.php:237 $snmp_version = shell_exec(cacti_escapeshellcmd(read_config_option('path_snmpget')) . ' -V 2>&1');
|
||||
cmd_exec ./utilities.php:257 exec(cacti_escapeshellcmd(read_config_option('path_spine')) . ' --version', $out_array);
|
||||
deserialize ./lib/functions.php:4684 $items = unserialize($unstripped, array('allowed_classes' => false));
|
||||
deserialize ./lib/functions.php:7999 return @unserialize($strobj, array('allowed_classes' => false));
|
||||
deserialize ./lib/functions.php:4688 $items = unserialize($unstripped, array('allowed_classes' => false));
|
||||
deserialize ./lib/functions.php:8003 return @unserialize($strobj, array('allowed_classes' => false));
|
||||
dynamic_include ./automation_tree_rules.php:538 include_once($config['base_path'].'/lib/html_tree.php');
|
||||
dynamic_include ./cli/add_data_query.php:27 require_once($config['base_path'] . '/lib/api_automation_tools.php');
|
||||
dynamic_include ./cli/add_data_query.php:28 require_once($config['base_path'] . '/lib/api_automation.php');
|
||||
@@ -343,9 +343,9 @@ dynamic_include ./lib/aggregate.php:834 include_once($config['base_path'] . '/l
|
||||
dynamic_include ./lib/api_aggregate.php:1677 include($config['include_path'] . '/global_arrays.php');
|
||||
dynamic_include ./lib/api_aggregate.php:203 include_once($config['base_path'] . '/lib/api_aggregate.php');
|
||||
dynamic_include ./lib/api_aggregate.php:671 include_once($config['base_path'] . '/lib/api_aggregate.php');
|
||||
dynamic_include ./lib/api_automation.php:2360 include_once($config['base_path'] . '/lib/template.php');
|
||||
dynamic_include ./lib/api_automation.php:2361 include_once($config['base_path'] . '/lib/api_automation_tools.php');
|
||||
dynamic_include ./lib/api_automation.php:2362 include_once($config['base_path'] . '/lib/utility.php');
|
||||
dynamic_include ./lib/api_automation.php:2384 include_once($config['base_path'] . '/lib/template.php');
|
||||
dynamic_include ./lib/api_automation.php:2385 include_once($config['base_path'] . '/lib/api_automation_tools.php');
|
||||
dynamic_include ./lib/api_automation.php:2386 include_once($config['base_path'] . '/lib/utility.php');
|
||||
dynamic_include ./lib/api_device.php:946 include_once($config['base_path'] . '/lib/utility.php');
|
||||
dynamic_include ./lib/api_device.php:947 include_once($config['base_path'] . '/lib/variables.php');
|
||||
dynamic_include ./lib/api_device.php:948 include_once($config['base_path'] . '/lib/data_query.php');
|
||||
@@ -366,17 +366,17 @@ dynamic_include ./lib/dsstats.php:1009 include_once($config['library_path'] .
|
||||
dynamic_include ./lib/dsstats.php:967 include_once($config['base_path'] . '/lib/rrd.php');
|
||||
dynamic_include ./lib/export.php:465 include_once($config['library_path'] . '/vdef.php');
|
||||
dynamic_include ./lib/functions.php:421 include_once($config['base_path'] . '/lib/poller.php');
|
||||
dynamic_include ./lib/functions.php:4812 include_once($config['base_path'] . '/include/global_session.php');
|
||||
dynamic_include ./lib/functions.php:4815 include_once($config['base_path'] . '/include/bottom_footer.php');
|
||||
dynamic_include ./lib/functions.php:4840 include_once($config['base_path'] . '/include/top_header.php');
|
||||
dynamic_include ./lib/functions.php:4847 include_once($config['base_path'] . '/include/top_graph_header.php');
|
||||
dynamic_include ./lib/functions.php:4854 include_once($config['base_path'] . '/include/top_general_header.php');
|
||||
dynamic_include ./lib/functions.php:5016 require_once($config['include_path'] . '/vendor/phpmailer/src/Exception.php');
|
||||
dynamic_include ./lib/functions.php:5017 require_once($config['include_path'] . '/vendor/phpmailer/src/PHPMailer.php');
|
||||
dynamic_include ./lib/functions.php:5018 require_once($config['include_path'] . '/vendor/phpmailer/src/SMTP.php');
|
||||
dynamic_include ./lib/functions.php:5505 require_once($config['include_path'] . '/vendor/phpmailer/src/Exception.php');
|
||||
dynamic_include ./lib/functions.php:5506 require_once($config['include_path'] . '/vendor/phpmailer/src/PHPMailer.php');
|
||||
dynamic_include ./lib/functions.php:5507 require_once($config['include_path'] . '/vendor/phpmailer/src/SMTP.php');
|
||||
dynamic_include ./lib/functions.php:4816 include_once($config['base_path'] . '/include/global_session.php');
|
||||
dynamic_include ./lib/functions.php:4819 include_once($config['base_path'] . '/include/bottom_footer.php');
|
||||
dynamic_include ./lib/functions.php:4844 include_once($config['base_path'] . '/include/top_header.php');
|
||||
dynamic_include ./lib/functions.php:4851 include_once($config['base_path'] . '/include/top_graph_header.php');
|
||||
dynamic_include ./lib/functions.php:4858 include_once($config['base_path'] . '/include/top_general_header.php');
|
||||
dynamic_include ./lib/functions.php:5020 require_once($config['include_path'] . '/vendor/phpmailer/src/Exception.php');
|
||||
dynamic_include ./lib/functions.php:5021 require_once($config['include_path'] . '/vendor/phpmailer/src/PHPMailer.php');
|
||||
dynamic_include ./lib/functions.php:5022 require_once($config['include_path'] . '/vendor/phpmailer/src/SMTP.php');
|
||||
dynamic_include ./lib/functions.php:5509 require_once($config['include_path'] . '/vendor/phpmailer/src/Exception.php');
|
||||
dynamic_include ./lib/functions.php:5510 require_once($config['include_path'] . '/vendor/phpmailer/src/PHPMailer.php');
|
||||
dynamic_include ./lib/functions.php:5511 require_once($config['include_path'] . '/vendor/phpmailer/src/SMTP.php');
|
||||
dynamic_include ./lib/graph_variables.php:65 include_once($config['library_path'] . '/rrd.php');
|
||||
dynamic_include ./lib/html.php:1243 include($config['include_path'] . '/global_arrays.php');
|
||||
dynamic_include ./lib/html_tree.php:479 include_once($config['base_path'] . '/lib/data_query.php');
|
||||
@@ -540,10 +540,10 @@ fs_write ./cli/import_template.php:121 $fp = fopen($filename,'r');
|
||||
fs_write ./cli/input_whitelist.php:188 file_put_contents($config['input_whitelist'], json_encode($input));
|
||||
fs_write ./cli/md5sum.php:179 if (file_put_contents($md5_file,$output) === false) {
|
||||
fs_write ./cli/refresh_csrf.php:84 $fh = fopen($path_csrf_secret, 'w');
|
||||
fs_write ./cli/splice_rrd.php:328 file_put_contents($newxmlfile, $new_xml);
|
||||
fs_write ./cli/splice_rrd.php:327 file_put_contents($newxmlfile, $new_xml);
|
||||
fs_write ./cli/splice_rrd.php:47 if (($f = @fopen($path, 'a'))) {
|
||||
fs_write ./cli/splice_rrd.php:56 if (($f = @fopen($path, 'w'))) {
|
||||
fs_write ./cli/splice_rrd.php:873 return file_put_contents($xmlfile, $output);
|
||||
fs_write ./cli/splice_rrd.php:872 return file_put_contents($xmlfile, $output);
|
||||
fs_write ./host.php:591 $stdout = fopen('php://output', 'w');
|
||||
fs_write ./include/global_languages.php:956 file_put_contents($config['i18n_log'], $text . $eol, $mode);
|
||||
fs_write ./include/global_languages.php:964 file_put_contents($config['i18n_text_log'], $text . $eol, $mode);
|
||||
@@ -565,10 +565,10 @@ fs_write ./lib/functions.php:1353 $fp = @fopen($logfile, 'a');
|
||||
fs_write ./lib/functions.php:1428 $fp = fopen($file_name, 'r');
|
||||
fs_write ./lib/functions.php:483 file_put_contents(sys_get_temp_dir() . '/cacti-option.log', get_debug_prefix() . cacti_debug_backtrace($config_name, false, false, 0, 1) . "\n", FILE_APPEND);
|
||||
fs_write ./lib/functions.php:698 file_put_contents(sys_get_temp_dir() . '/cacti-option.log', get_debug_prefix() . cacti_debug_backtrace($config_name, false, false, 0, 1) . "\n", FILE_APPEND);
|
||||
fs_write ./lib/functions.php:7025 if (($f = @fopen($path, 'a'))) {
|
||||
fs_write ./lib/functions.php:7034 if (($f = @fopen($path, 'w'))) {
|
||||
fs_write ./lib/functions.php:7029 if (($f = @fopen($path, 'a'))) {
|
||||
fs_write ./lib/functions.php:7038 if (($f = @fopen($path, 'w'))) {
|
||||
fs_write ./lib/functions.php:710 file_put_contents(sys_get_temp_dir() . '/cacti-option.log', get_debug_prefix() .
|
||||
fs_write ./lib/functions.php:7108 file_put_contents($tmp_file, 'cacti');
|
||||
fs_write ./lib/functions.php:7112 file_put_contents($tmp_file, 'cacti');
|
||||
fs_write ./lib/functions.php:719 file_put_contents(sys_get_temp_dir() . '/cacti-option.log', get_debug_prefix() .
|
||||
fs_write ./lib/import.php:425 $f = fopen($filename, 'r');
|
||||
fs_write ./lib/import.php:592 $file = fopen($filename, 'wb');
|
||||
@@ -820,7 +820,7 @@ header_redirect ./images/index.php:25 header("Location:../index.php");
|
||||
header_redirect ./include/auth.php:50 header ('Location: ' . $config['url_path'] . 'install/');
|
||||
header_redirect ./include/auth.php:71 header ('Location: ' . $config['url_path'] . 'auth_changepassword.php?ref=' . rawurlencode(validate_redirect_url($_SERVER['HTTP_REFERER'] ?? '', 'index.php')));
|
||||
header_redirect ./include/content/index.php:25 header("Location:../index.php");
|
||||
header_redirect ./include/csrf.php:51 header('Location: ' . sanitize_uri($_SERVER['REQUEST_URI']));
|
||||
header_redirect ./include/csrf.php:51 header('Location: ' . validate_redirect_url($_SERVER['REQUEST_URI']));
|
||||
header_redirect ./include/fa/css/index.php:25 header("Location:../index.php");
|
||||
header_redirect ./include/fa/index.php:25 header("Location:../index.php");
|
||||
header_redirect ./include/fa/js/index.php:25 header("Location:../index.php");
|
||||
@@ -860,17 +860,17 @@ header_redirect ./include/themes/sunrise/images/index.php:25 header("Location:..
|
||||
header_redirect ./include/themes/sunrise/index.php:25 header("Location:../index.php");
|
||||
header_redirect ./include/vendor/index.php:25 header("Location:../index.php");
|
||||
header_redirect ./install/upgrades/index.php:25 header("Location:../../index.php");
|
||||
header_redirect ./lib/auth.php:4288 header('Location: auth_changepassword.php?header=false');
|
||||
header_redirect ./lib/auth.php:4748 header('Location: ' . $referer);
|
||||
header_redirect ./lib/auth.php:4752 header('Location: graph_view.php');
|
||||
header_redirect ./lib/auth.php:4756 header('Location: index.php');
|
||||
header_redirect ./lib/auth.php:4762 header('Location: ' . $config['url_path'] . 'graph_view.php' . ($newtheme ? '?newtheme=1':''));
|
||||
header_redirect ./lib/auth.php:4764 header('Location: ' . $config['url_path'] . 'index.php' . ($newtheme ? '?newtheme=1':''));
|
||||
header_redirect ./lib/auth.php:4769 header('Location: ' . $config['url_path'] . 'graph_view.php' . ($newtheme ? '?newtheme=1':''));
|
||||
header_redirect ./lib/auth.php:4964 header ('Location: ' . $config['url_path'] . 'auth_changepassword.php?action=force&ref=' . urlencode(validate_redirect_url(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : 'index.php')));
|
||||
header_redirect ./lib/auth.php:4298 header('Location: auth_changepassword.php?header=false');
|
||||
header_redirect ./lib/auth.php:4758 header('Location: ' . $referer);
|
||||
header_redirect ./lib/auth.php:4762 header('Location: graph_view.php');
|
||||
header_redirect ./lib/auth.php:4766 header('Location: index.php');
|
||||
header_redirect ./lib/auth.php:4772 header('Location: ' . $config['url_path'] . 'graph_view.php' . ($newtheme ? '?newtheme=1':''));
|
||||
header_redirect ./lib/auth.php:4774 header('Location: ' . $config['url_path'] . 'index.php' . ($newtheme ? '?newtheme=1':''));
|
||||
header_redirect ./lib/auth.php:4779 header('Location: ' . $config['url_path'] . 'graph_view.php' . ($newtheme ? '?newtheme=1':''));
|
||||
header_redirect ./lib/auth.php:4974 header ('Location: ' . $config['url_path'] . 'auth_changepassword.php?action=force&ref=' . urlencode(validate_redirect_url(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : 'index.php')));
|
||||
header_redirect ./lib/clog_webapi.php:99 header('Location: ' . get_current_page());
|
||||
header_redirect ./lib/functions.php:8104 header('Location: ' . $save_url);
|
||||
header_redirect ./lib/functions.php:8127 header('Location: ' . $safe_url, true, $status);
|
||||
header_redirect ./lib/functions.php:8108 header('Location: ' . $save_url);
|
||||
header_redirect ./lib/functions.php:8131 header('Location: ' . $safe_url, true, $status);
|
||||
header_redirect ./lib/html_graph.php:498 header('Location: ' . $page . '?host_id=' . $host_id . '&header=false');
|
||||
header_redirect ./lib/html_reports.php:1507 header('Location: reports.php');
|
||||
header_redirect ./lib/html_reports.php:274 header('Location: reports.php');
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 21 and column 257.
|
Reference in new issue
Block a user