
Exploit para CVE-2022-46169
Exploit para CVE-2022-46169 Cacti versiones anteriores a 1.2.3
Aquí remote_client_authorized verifica el nombre del host del cliente en la tabla poller para la entrada
function remote_client_authorized() {
// ...
$client_addr = get_client_addr();
// ...
$client_name = gethostbyaddr($client_addr);
// ...
$pollers = db_fetch_assoc('SELECT * FROM poller', true, $poller_db_cnn_id);
foreach($pollers as $poller) {
if (remote_agent_strip_domain($poller['hostname']) == $client_name) {
return true;
// ...
La función get_client_addr se utiliza para obtener la dirección del cliente, la cual puede ser modificada por el atacante al determinar la dirección IP. Usa la IP para resolverla al nombre de host correspondiente y verifica si la tabla poller contiene una entrada con este nombre de host autorizando al cliente.
<?php
// ...
function get_client_addr($client_addr = false) {
$http_addr_headers = array(
// ...
'HTTP_X_FORWARDED',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'HTTP_CLIENT_IP',
'REMOTE_ADDR',
);
$client_addr = false;
foreach ($http_addr_headers as $header) {
// ...
$header_ips = explode(',', $_SERVER[$header]);
foreach ($header_ips as $header_ip) {
// ...
$client_addr = $header_ip;
break 2;
}
}
return $client_addr;
}
por lo que modificar la cabecera de la solicitud nos permite evitar la autenticación.
Y aquí se utiliza entrada de usuario sin sanitizar para ejecutar un comando externo
// ... recuperar items del poller de la base de datos ...
foreach($items as $item) {
switch ($item['action']) {
// ...
case POLLER_ACTION_SCRIPT_PHP: /* script (servidor de script php) */
// ...
$cactiphp = proc_open(read_config_option('path_php_binary') . ' -q ' . $config['base_path'] . '/script_server.php realtime ' . $poller_id, $cactides, $pipes);
configurar qué cabeceras HTTP deben usarse al determinar la IP utilizada de un cliente
dado que el valor de poller_id debe ser un entero, validarlo antes de pasarlo a proc_open