ブログに戻る

フォロー&ご登録

CVE-2023-30534 : Cacti のバージョン 1.2.24 以前に存在する安全でない逆シリアル化の脆弱性

Fastly Security Research Team

Fastly Security Research Team, Fastly

Matthew Mathur

Senior Security Researcher, Fastly

概要 

Cacti のバージョン 1.2.24 以前に安全でない逆シリアル化の2つのインスタンス</u>があることを私たちは発見しました。この脆弱性は CVE-2023-30534</u> として知られています。安全でない逆シリアル化の各インスタンスはリモートでトリガーされますが、実行環境の制限により悪用されることはありません。これについては「悪用の試み」のセクションで詳しくご説明します。

Cacti</u> は RRDtool のデータストレージとグラフ化機能を利用するオープンソースのネットワーク管理・グラフ化ソリューションで、グラフの作成やデバイスの発見などに利用されます。Cacti のインスタンスの一部は外部からのアクセスが可能ですが、Cacti の主な用途は内部ネットワークシステムのモニタリングです。

技術面についてもう少し詳しくみてみましょう。シリアル化とは、PHP や Java オブジェクトなど複雑なデータ構造を持つオブジェクトを、ネットワーク経由で送信しやすい形式に変換するプロセスを指します。一方、逆シリアル化は、変換されたデータを元の複雑なデータ構造に再構築することをいいます。安全でない逆シリアル化は、ユーザーが制御するデータが逆シリアル化される場合に発生し、攻撃者による任意のオブジェクトのインスタンス化やファイルの読み込み/書き込みに加えて、リモートコードの実行さえも可能になるおそれがあります。

注 : Cacti のバージョン 1.2.25 (および 1.3.0) では、Cacti に存在するその他の17件の脆弱性 (深刻で影響力の大きいものも含まれます) も修正されているので、管理者はできる限り早急にアップグレードすることが推奨されます。

影響を受けるバージョン

私たちはまず Cacti のバージョン 1.2.10 に安全でない逆シリアル化の脆弱性があることを発見し、バージョン 1.2.25 より前のすべてのバージョンにこの脆弱性が存在することが分かっています。Cacti のバージョン 1.2.5 に加えて 1.3.5 でも安全でない逆シリアル化の問題が修正されています。

安全でない逆シリアル化の脆弱性の詳細

安全でない逆シリアル化の各インスタンスは、ユーザーが指定した入力を適切にサニタイズせずに unserialize 関数を使用することで発生します。Cacti は、unserialize 関数を呼び出す前にサニタイズを行い、文字列が特定の値のみを含むことを確認しようとすることで安全な逆シリアル化を行うユーティリティ機能を提供していますが、この機能はこれらのインスタンスでは使用されていません。

注 : コードブロックを簡潔にするため、参照されないコードは削除されています。

managers.php

脆弱なコードが managers.php ファイルの form_actions 関数内に存在します。以下のコードスニペットは Cacti のバージョン 1.2.10 のものです。

function form_actions() {
	global $manager_actions, $manager_notification_actions;
	
	if (isset_request_var('selected_items')) {
		if (isset_request_var('action_receivers')) {
			...
			...
			...
		} elseif (isset_request_var('action_receiver_notifications')) {
			get_filter_request_var('id');
			$selected_items = unserialize(stripslashes(get_nfilter_request_var('selected_items')));
			...
		}
	...
}

POST リクエストの変数 action_receiver_notifications を設定することで、form_actions 関数で unserialize の呼び出しを実行するようにコードフローを仕向けることができます。form_actions をトリガーするには、「action」変数を「actions」に設定する必要があります。undefinedundefinedこれにより、以下のように switch ステートメントで適切な case を実行できます。

switch (get_request_var('action')) {
	case 'save':
		form_save();
		break;
	case 'actions':
		form_actions();
		break;
	...
	...

脆弱な unserialize 関数を悪用するには、以下のように URL がエンコードされシリアル化された PHP オブジェクトが「selected_items」変数に使用されている POST リクエストを、認証済みユーザーが送信する必要があります。

無効なオブジェクト (誤った形式や、Cacti によって認識されないクラスを含むものなど) を「selected_items」変数の値として入力した場合、Cacti がペイロードを逆シリアル化できなかったことがログで確認できます。

この時点でコードフローをコントロールし、managers.php でユーザーが制御するシリアル化されたオブジェクトに対して unserialize 関数を呼び出すことができます。

graphs_new.php

脆弱なコードが graphs_new.php ファイルの host_new_graphs_save 関数に存在します。以下のコードスニペットは Cacti のバージョン 1.2.10 のものです。

function host_new_graphs_save($host_id) {
	$selected_graphs_array = unserialize(stripslashes(get_nfilter_request_var('selected_graphs_array')));

	$values = array();

この関数は、ユーザーが制御するパラメーター selected_graphs_array を逆シリアル化します。stripslashes が最初に実行されますが、これは単に前処理中に文字列で必要だった余分なスラッシュを取り除くためのものです。 

上記の関数を呼び出すには、action=savesave_component_new_graphs=1 の2つのパラメータを使用して graphs_new.php にリクエストを送信します。これにより、以下のコードスニペットが示すように脆弱な関数が呼び出されます。

switch (get_request_var('action')) {
	case 'save':
          form_save();
          break;
      case 'query_reload':
      ...
      ...
      ...
function form_save() {
	...
      ...
	...
	if (isset_request_var('save_component_new_graphs')) {
		host_new_graphs_save(get_filter_request_var('host_id'));

		header('Location: graphs_new.php?host_id=' . get_filter_request_var('host_id') . &header=false');
	}
}

脆弱な unserialize 関数を悪用するには、以下のように URL がエンコードされシリアル化された PHP オブジェクトが selected_graphs_array 変数に使用されている POST リクエストを、認証済みユーザーが送信する必要があります。

無効なオブジェクト (誤った形式や、Cacti によって認識されないクラスを含むものなど) を selected_graphs_array 変数の値として入力した場合、Cacti がペイロードを逆シリアル化できなかったことがログで確認できます。

この時点でコードフローをコントロールし、graphs_new.php でユーザーが制御するシリアル化されたオブジェクトに対して unserialize 関数を呼び出すことができます。

悪用の試み

PHP のマジックメソッド

PHP の逆シリアル化の脆弱性を悪用するには「マジックメソッド</u>」が実装されたオブジェクトにアクセスする必要があります。  マジックメソッドは、オブジェクトが作成されたり破棄されたりする際に自動的に呼び出されます。このようなメソッドには __construct__unserialize__destruct__wake などがあります。ペイロードがオブジェクトに逆シリアル化される際にこれらの関数の一部が自動的に呼び出されるので、これらの関数を使用するオブジェクトにアクセスできる必要があります。このコンテキストでは、「ガジェット」はこれらのメソッドのひとつが実装され、ペイロードで使用可能なオブジェクトです。ネストされたオブジェクトをペイロードで使用することで、これらのガジェットを組み合わせて「ガジェットチェーン」を構成し、ファイルの読み込みや書き込み、コードの実行といった望み通りのアクションを実行できるようになります。 

ガジェットチェーンを探す

これまでに多くのガジェットチェーンが人気の高いライブラリで発見されています。PHPGCC</u> ツールは、安全でない逆シリアル化のペイロードを作成するのに使用できる既知のガジェットチェーンのリストを提供しています。Cacti の PHP ベンダーである PHPSecLib には、既知の利用可能なガジェットチェーンがひとつ含まれています。しかし、Cacti は PHPSecLib のガジェットチェーンを使用するのに必要なガジェット (TripleDES、AES、SSH1) のいずれも必要とせず、含んでいません。

既存のガジェットチェーンの利用に加えて、使用可能なマジックメソッドが実装されたオブジェクトがプロジェクトにある場合は、新しいガジェットチェーンを作成することが可能です。例えば、Cacti の __construct メソッドの実装</u>をソースコードで確認し、これらのなかで使用可能なものがあるかを見てみましょう。Cacti の PHP オブジェクトで実装されたマジックメソッドを調べたところ、新しいガジェットチェーンで使用可能なものは見つかりませんでした。

利用可能なガジェットチェーンを見つけられない場合、この脆弱性は悪用することが不可能であることを意味します。

CVE-2023-30534 のための Nuclei テンプレート

この脆弱性の迅速なテストを促進するため、また修復の取り組みをサポートするため、私たちは CVE-2023-30534 のためのテストを実行する Nuclei のテンプレート</u>を作成しました。このテンプレートは認証を要求し、オブジェクトに対して unserialize 関数が呼び出されたことを示すログメッセージを生成するために無効な PHP オブジェクトを送信します。テンプレートはログのエラーメッセージを確認して unserialize 関数が呼び出されたことを検証し、unserialize 関数がペイロードで呼び出されたことを確認します。以下のように、このテンプレートはローカルで実行されます。

Cacti の管理者はバージョン 1.2.5 以降 (1.3.0 など) にアップグレードすることで、この脆弱性を修復できます。Cacti の標準インストールではこの脆弱性が悪用されることはありませんが、Cacti のセキュリティアドバイザリで修復に関する詳細を確認し、Cacti のアドバイスに従うことをお勧めします。

: Cacti のバージョン 1.2.25 (および 1.3.0) では、Cacti に存在するその他の17件の脆弱性 (深刻で影響力の大きいものも含まれます) も修正されているので、管理者はできる限り早急にアップグレードすることが推奨されます。