
CVE-2022-46169용 익스플로잇
CVE-2022-46169에 대한 익스플로잇 (Cacti 1.2.3 이전 버전 대상)
여기서 remote_client_authorized는 폴러(poller) 테이블에서 클라이언트의 호스트 이름을 확인합니다.
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;
// ...
get_client_addr 함수는 클라이언트의 주소를 가져오는 데 사용되며, 공격자가 IP 주소를 결정할 때 이를 조작할 수 있습니다. 이 함수는 IP를 사용하여 해당 호스트 이름을 확인하고, 폴러 테이블에 이 호스트 이름과 일치하는 항목이 있는지 확인하여 클라이언트를 인가합니다.
<?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;
}
따라서 요청 헤더를 수정하면 인증을 우회할 수 있습니다.
그리고 여기서는 사용자 입력을 소독하지 않고 외부 명령어 실행에 사용합니다.
// ... 폴러 항목을 데이터베이스에서 가져옴 ...
foreach($items as $item) {
switch ($item['action']) {
// ...
case POLLER_ACTION_SCRIPT_PHP: /* script (php script server) */
// ...
$cactiphp = proc_open(read_config_option('path_php_binary') . ' -q ' . $config['base_path'] . '/script_server.php realtime ' . $poller_id, $cactides, $pipes);
클라이언트의 IP 주소를 결정할 때 사용할 HTTP 헤더를 구성합니다.
poller_id 값은 정수여야 하므로 proc_open에 전달하기 전에 검증해야 합니다.