
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 を使用して対応するホスト名に解決し、poller テーブルにこのホスト名を持つエントリが存在するかどうかをチェックしてクライアントを認証します。
<?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;
}
そのため、リクエストヘッダーを改ざんすることで認証をバイパスできます。
そして、ここではサニタイズされていないユーザー入力が外部コマンドの実行に使用されています。
// ... retrieve poller items from database ...
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 に渡す前に検証する