- Cisco Talos は、Apple macOS および VMware vCenter での MSRPC の実装にメモリ破損の脆弱性を 12 件発見しました。
– 7 件の脆弱性は Apple macOS に影響します。
– 2 件の脆弱性は VMware vCenter に影響します。
– 3 件の脆弱性は両方に影響します。 - 個々の脆弱性の詳細については、この問題に関する Talos のアドバイザリをご覧ください。
- macOS と vCenter での MSRPC の実装は同じ DCERPC コードベースに基づいていますが、異なる時期に分岐し、別々のユースケースに合わせて変更されています。
- 今回発見された問題は、解放済みメモリ使用(use-after-free)、バッファオーバーフロー、情報漏洩、サービス拒否の脆弱性に分類されます。一部の脆弱性を組み合わせることで、リモートコード実行や特権昇格が可能になる場合があります。
- Apple 社は 2023 年の 3 回(1 月、3 月、5 月)の月例セキュリティアップデートで、すべての脆弱性に対処しました。VMware 社は 6 月 22 日の更新で、報告されていたすべての問題に対処しました。Talos は今回、シスコのサードパーティ脆弱性開示ポリシーに従ってすべての脆弱性を開示しています。
- このブログでは、標的のアタックサーフェス(攻撃対象領域)にレイヤごとにアプローチし、単一のパケット解析に起因する脆弱性、相互に影響する複数のセッションでの時間的な問題による脆弱性、具体的な整形式の RPC コールを実行することによってのみ到達できる複雑な脆弱性について説明します。
目次
DCE/RPC の概要
DCE/RPC は「Distributed Computing Environment/Remote Procedure Calls」の略で、リモートプロシージャコール(RPC)の仕組みを実装するための標準化プロトコルです。Windows のエコシステム全体で使用されている Microsoft RPC の仕組みは DCE/RPC の仕様に基づいているため、DCE/RPC は現在も注目されています。一方、DCERPC は Microsoft RPC(MSRPC)の仕様と互換性のあるオープンソースの実装です。このブログでは、オープンソースの実装を DCERPC、プロトコルの仕様を MSRPC と呼びます。
MSRPC は、RPC 通信を確立するために使用されるメッセージ構文とシーケンスを定義します。RPC 通信は通常、TCP 接続、SMB 接続、名前付きパイプ、ソケット、およびその他のチャネルを介して実行されます。公開されているサービス上でクライアントがリモートプロシージャコールを実行する際は、利用可能なチャネルを介して RPC サーバーと通信し、サービスにバインドして、定義済みのメソッドを呼び出します。これは、一連の BIND/BIND_ACK および REQ/RESP プロトコルデータユニット(PDU)を交換することで実行されます。RPC サービスは UUID で識別され、リモートで呼び出すことのできる特定のメソッドや関数は操作番号(opnum)で識別されます。
リモートで呼び出し可能なプロシージャは、引数を取り、結果を返すことができます。MSRPC は、これらの値やデータ構造がどのようにシリアル化および逆シリアル化されるかを規定します。
RPC サービスを開発する場合、公開される操作、その入出力、関連するデータ構造は、インターフェイス定義言語(IDL)と呼ばれるドメイン固有の言語で規定されます。サービス用の IDL ファイルは、IDL コンパイラを介してサービスの定型コードを生成するためのベースとして機能します。
このような例として、管理リモートインターフェイス IDL があります。
[uuid(afa8bd80-7d8a-11c9-bef4-08002b102989), version(1)] interface mgmt { import "dce/rpctypes.idl"; /* * R P C _ _ M G M T _ I N Q _ I F _ I D S */ [idempotent] void rpc__mgmt_inq_if_ids ( [in] handle_t binding_handle, [out] rpc_if_id_vector_p_t *if_id_vector, [out] error_status_t *status ); /* * R P C _ _ M G M T _ I N Q _ S T A T S */ [idempotent] void rpc__mgmt_inq_stats ( [in] handle_t binding_handle, [in, out] unsigned32 *count, [out, size_is (*count)] unsigned32 statistics[*], [out] error_status_t *status );
たとえば上記のコードの抜粋では、afa8bd80-7d8a-11c9-bef4-08002b102989 という UUID と、2 つのメソッド(rpc__mgmt_inq_if_ids および rpc__mgmt_inq_stats)が指定されています。定義されているメソッドはいずれも、パラメータの前に in、out、またはその両方が付いており、パラメータが入力引数であるか戻り値であるかを表しています。
RPC クライアントがこれらのメソッドを呼び出すには、UUID afa8bd80-7d8a-11c9-bef4-08002b102989 を指定した BIND リクエストを送信し、次に opnum を指定した RPC コールリクエストを送信する必要があります。opnum は IDL 内のメソッドに対応し、シーケンシャルになります。
Windows プラットフォーム上で MSRPC を介して提供される一般的なサービスとしては、ワークステーションサービス、ディレクトリサービス、LSAS、NETLOGON があり、その他多くのサービスがサードパーティによって実装されています。サードパーティがサービスを実装する際は Windows 上の MSRPC ライブラリを利用します。コードのスタブは IDL ファイルを介して生成され、実際の機能は手動で実装されます。このように見てみると、トランスポート層(SMB 経由の名前付きパイプなど)を処理するコード、RPC リクエストと応答メッセージとサービスの呼び出しを処理するコード、実際のサービス機能を実装するコードが、公開されているサービスのアタックサーフェスだと言えます。ここでは、vCenter と macOS のコンテキストでこれらのコードについて調べていきます。
VMware のユースケース
VMware vCenter はよく攻撃者の標的になるため、ローカルネットワークからアクセス可能なサービスを探すことにしました。vCenter は、セキュリティや認証、証明書管理などのために統一されたフレームワークを提供する Lightwave プロジェクトを採用しています。よくよく調べてみると、実装されているサービスは非常に興味深いものでした。具体的に名前を挙げると、VMware 証明書管理サービス(vmcad ポート 2014)、VMware ディレクトリサービス(vmdird ポート 2012)、VMware 認証フレームワーク(vmafdd ポート 2020)で、いずれもデフォルトでローカルネットワークからアクセス可能です。
root@localhost [ ~ ]# ss -ntlp ... LISTEN 0 128 0.0.0.0:2012 0.0.0.0:* users:(("vmdird",pid=19454,fd=16)) LISTEN 0 128 0.0.0.0:2014 0.0.0.0:* users:(("vmcad",pid=10879,fd=13)) LISTEN 0 128 0.0.0.0:2020 0.0.0.0:* users:(("vmafdd",pid=1701,fd=14)) …
名前からもわかるように、これらのサービスはセキュリティに関する重要な機能を実装していると思われるため、実装方法をさらに詳しく調べました。権限を分離するために、各サービスは独自のユーザーとして実行されるようになっていましたが、攻撃者が証明書管理サービス(vmcad など)に独自の証明書を挿入すれば壊滅的な被害が生じるでしょう。
さらに調べていくと、これらのサービスはネットワーク上で RPC インターフェイスを実装しており、大半の機能は認証の背後で公開されていることが明らかになりました。そのため、認証されていない攻撃者が対象コードへ到達できるのかを評価するのに、当初は手こずりました。しかし、これらのサービスがネットワーク機能を有効にするために DCERPC を使用していること、具体的には Likewise-Open ライブラリが実装されていることをすぐに突き止めました。これは、認証の前にネットワークのパケットを解析する下位層のネットワークのコードであり、その後の調査の焦点となりました。
macOS のユースケース
Talos は以前、macOS に組み込まれている SMB サーバーのコードを監査し、数件の脆弱性を発見しました。その後、これらの脆弱性にはパッチが適用されています。最初に VMware vCenter 上の MSRPC サービスを調査した際、macOS の実装とコードベースを共有していることにすぐに気が付いたため、さらに調査を進めることにしました。
macOS では、RPC サービスは rpcsvchost システムサービスによってホストされており、同サービスは launchd によって管理されています。rpcsvchost サービスは、/System/Library/PrivateFrameworks/ にあるプライベート DCERPC.framework に大きく依存しています。DCERPC.framework はオープンソースで、Apple のオープンソースソフトウェアのリポジトリにあります。macOS では、DCERPC.framework と rpcsvchost 自体が通信チャネルとして UNIX ソケットをサポートしており、RPC サービスが開始されると、/var/rpc/ にソケットが作成されます。
$ ls -lR /var/rpc/ total 0 drwxr-xr-x 6 root wheel 192 Nov 29 15:23 ncacn_np drwxr-xr-x 6 root wheel 192 Nov 29 15:23 ncalrpc /var/rpc//ncacn_np: total 0 srw-rw-rw- 1 root daemon 0 Nov 29 15:23 lsarpc srw-rw-rw- 1 root daemon 0 Nov 29 15:23 mdssvc srw-rw-rw- 1 root daemon 0 Nov 29 15:23 srvsvc srw-rw-rw- 1 root daemon 0 Nov 29 15:23 wkssvc /var/rpc//ncalrpc: total 0 srw-rw-rw- 1 root daemon 0 Nov 29 15:23 NETLOGON srw-rw-rw- 1 root daemon 0 Nov 29 15:23 lsarpc srw-rw-rw- 1 root daemon 0 Nov 29 15:23 srvsvc srw-rw-rw- 1 root daemon 0 Nov 29 15:23 wkssvc
上記のリストには、ncacn_np と ncalrpc という 2 つのエンドポイントがあり、サービスが含まれています。前者は SMB 経由で利用できる名前付きパイプ用、後者はローカル専用の RPC サービス用です。
サービス自体はバンドルとして実装されており、/usr/lib/rpcsvc にあります。
[:/usr/lib/rpcsvc ] $ ls -l total 2248 -rwxr-xr-x 1 root wheel 237440 Oct 13 01:06 dssetup.bundle -rwxr-xr-x 1 root wheel 169920 Oct 13 01:06 echosvc.bundle -rwxr-xr-x 1 root wheel 868864 Oct 13 01:06 lsarpc.bundle -rwxr-xr-x 1 root wheel 368176 Oct 13 01:06 mdssvc.bundle -rwxr-xr-x 1 root wheel 1057488 Oct 13 01:06 netlogon.bundle -rwxr-xr-x 1 root wheel 959936 Oct 13 01:06 srvsvc.bundle -rwxr-xr-x 1 root wheel 304736 Oct 13 01:06 wkssvc.bundle
それぞれのバンドルは、IDL で生成されたスケルトンコードと、実際のサービス実装から構築されています。
デフォルトのサービスは、ドメインネットワークに接続する macOS のインスタンスに必要な Active Directory 操作をサポートするためのものです。mdssvc を除き、上記のサービスはすべて Windows プラットフォームに存在し、十分に文書化されています。mdssvc は Apple 独自のものであり、Spotlight 検索を実装しています。
攻撃者の観点からすると、rpcsvchost は(サンドボックス化されてはいますが)ルート権限で実行されています。悪意のあるローカルユーザーが公開されている UNIX ソケットに接続し、脆弱性をエクスプロイトして特権を昇格しようとする可能性があります。サービスは直接ネットワークに公開されていませんが、SMB でアクセスすることが可能であり、アクセスに成功すればリモートの潜在的なアタックサーフェスが拡大することになります。名前付きパイプへのアクセスに必要な認証は、設定によって異なります。デフォルトでは認証が必要です。
コードの調査
主なアタックサーフェスは DCERPC ライブラリであり、ファジング(不正データを入力して脆弱性を検出するテスト手法)を行ううえでは、コードのレイアウトや重要なエントリポイントに関する基本的な知識が重要になります。
ライブラリはスレッドの使用に大きく依存し、適切な関数で処理されるようにイベントをディスパッチします。受信データを処理する主なエントリポイントは標準で規定されており、dcerpc/ncklib/cnrcvr.c に rpc__cn_network_receiver として実装されています。
このルーチンはトップレベルの受信スレッド(クライアントとサーバーの両方)を構成し、受信パケットを処理するために「association lookaside alloc」ルーチンの「thread create」によって呼び出されます。
着信パケットを受信すると、以下のコードに到達します。
receive_dispatch 関数は、メッセージの解析とハンドラのディスパッチを行います。ここで注目すべき点がいくつかあります。まず、このコードベースは RPC_CN_STATS_INCR のようなマクロに大きく依存しています。さらに、サーバーの状態、接続数、その他の統計情報を追跡するために、多数のグローバル変数が使用されています。これらはほとんどが、初期化されていないメモリに割り当てられています。
ファジングを厄介にするコードパターン
意図的ではありませんが、このコードベース全体で使用されているいくつかのコードパターンが原因で、ファジングと根本原因の解析が、困難とまではいかなくても少し厄介になります。問題のコードの 1 つは、スレッドの管理をマクロに依存しています。そのため、コールスタックが非常に短いことが原因で、デバッガで捕捉されるクラッシュの状況が非常に限定されてしまうことになります。これはトレースやコードカバレッジの分析にも影響します。上記のコードが、マクロとして作成された try/catch ブロックを使用することで、擬似的な例外処理を実装していることにご注意ください。これらも MSRPC 仕様の一部です。
#define DCETHREAD_TRY RpcTryExcept
RpcTryExcept 関数はライブラリのユーザーによって提供され、プラットフォームによって異なります。
ファジングを厄介にしている 2 番目の要因は、エラー報告がコードによって処理される方法です。以下にその例を示します。
rpc_dce_svc_printf 関数は、例外によって発生したエラーを出力またはログに記録するために使用されます。5 番目の引数 svc_c_sev_fatal | svc_c_action_abort は、エラーがどのように処理されるかを指定します。この場合、エラーは致命的で、デバッガがクラッシュとみなすようなサービスは強制的に破棄されます。これはありがちですが非常に残念なやり方であり、簡単にサービス拒否状態になります。ファジングを成功させるためには、これらの致命的な例外にパッチを適用する必要があります。
vCenter サービスの実装
VMware vCenter の簡単な概要として、DCERPC を使用するサービスは IDL ファイルを作成する必要があります。IDL ファイルには、RPC インターフェイス、つまり外部クライアントに公開する必要がある関数とそれに対応する引数を記述します。サービスをビルドする際の中間ステップとして、IDL コンパイラは IDL ファイルを標準 C のヘッダーファイルと実装ファイルにコンパイルします。この実装ファイルは、マーシャリング/アンマーシャリングのパラメータに使用され(入力の場合は [in]、出力の場合は [out] とマークされます)、サービス機能を実装する実際の関数呼び出しのための適切なスタブになります。以下は、証明書管理サービス vmcad のサービス定義から関連する部分を抜粋したものです。
//Version history 1.0 to 2.0 - change in VMCA_FILE_BUFFER to container [ uuid(7a98c250-6808-11cf-b73b-00aa00b677a7), version(3.0), pointer_default(unique) ] interface vmca { ... unsigned32 RpcVMCAGetServerVersion( [out] unsigned32 *dwCertLength, [out] VMCA_CERTIFICATE_CONTAINER **pServerVersion ); unsigned32 RpcVMCAInitEnumCertificatesHandle( [out] unsigned32 * pdwHandle ); unsigned32 RpcVMCAEnumCertificates( [in] CERTIFICATE_STATUS dwStatus, [in] unsigned32 dwStartIndex, [in] unsigned32 dwNumCertificates, [out] PVMCA_CERTIFICATE_ARRAY *ppCertContainer ); ... }
上記のインターフェイスで宣言されたそれぞれの関数について op_ssr() 関数が自動生成され、パラメータを適切な型にアンマーシャリングし、関連する RPC 関数を呼び出し、最後に戻り値をマーシャリングして結果をクライアントに送信します。以下は、vmcad の RpcVMCAGetServerVersion() の op0_ssr() スタブです(わかりやすくするために編集しています)。
RpcVMCAGetServerVersion() の実際の実装は次のとおりです。
macOS サービスの実装
前述のとおり、macOS 上の個々のサービスはバンドルとして /usr/lib/rpcsvc に実装されています。これらのバンドルを逆アセンブルしてリバースエンジニアリングすると、パターンが明らかになってコードをナビゲートしやすくなります。リバースエンジニアリングは、オープンソースの DCERPC コードベースの構造定義や、既知のサービスの IDL ファイルの調査で確認された構造定義によって強化できます。
典型的なサービスは、初期化を実行して rpcsvchost にサービスを登録する *_load 関数を実装しています。バイナリには、インターフェイスを記述するデータ構造が含まれています。
これをたどっていくと、実際の操作の実装を見つけることができます。
このサービスが実装しているメソッドは 4 つあります。これらのメソッドは(おそらく)、Apple 独自のサービスである mdssvc の IDL に、入力および出力パラメータとともに定義されています。実装されていないもの、単にエラーを返すもの、スタブでありテスト時にスキップできるものなどがあるため、メソッドの概要を確認するのは有益です。
別の見方をすると、rpcsvchost は受信するリクエストの解析を処理し、プロシージャ名ではなく opnum によって、該当するプロシージャコールを mdssvc にディスパッチします。mdssvc.bundle の関数のリストでは、次のようになっています。
_op0_ssr _op1_ssr _op2_ssr _op3_ssr
これらは IDL から生成された操作呼び出しのスタブであり、具体的なプロシージャを実装する実際の関数呼び出しに使用されます。受信パケットデータを引数にアンマーシャリングしたり、応答データをマーシャリングしたりするため、実装がかなり複雑になる場合があります。
実装について十分に理解していると、根本原因を分析したり、コードカバレッジを調べたりするときに便利です。
UNIX ソケットにサービスが実装されていることには興味深い点があり、サービスが利用可能で到達可能である限り、どの UNIX ソケットを介してもすべてのサービスにアクセスできます。単なるソケットなので、標準的なツールを使用して以下のようにサービスを操作することができます。
perl -e 'print "\x09\x01\x0e\xff\xff\xff\xff\xff\x00\x21\x00\x00\x41\x41\x41\x41\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\x00" . "\x05\x01\x1d\x02\x05\x2e\x00\x00\x00\x00"' | nc -v -U /var/rpc/ncalrpc/NETLOGON | xxd
vCenter バージョンのファジング
ビルドの問題
Lightwave プロジェクトと Likewise-Open ライブラリは、比較的最近コミットされたものを GitHub から簡単に入手できます。そこで、コードをダウンロードし、デバッグシンボルをフルに付けて AddressSanitizer を有効にしてからコンパイルを試すことにしました。目的は、脆弱性の検出能力を大幅に高めることです。残念ながらオープンソースソフトウェアの場合はほとんどそうですが、通常は特定のバージョンのライブラリやツールチェーンが必要なため、言うは易く行うは難しです。HyperMake と Docker を文書化されているとおりに使用してソフトウェアをビルドすることに成功したものの、これは長期的には研究を遅らせることになるため、Photon OS の仮想マシンをセットアップすることにしました。Photon OS は VMware 社が提供する GNU/Linux ディストリビューションで、VMware vCenter イメージのベースでもあります。テストには Photon OS バージョン 3.0 を使用しました。
標準的なインストールを行い、適切な DNS 設定で VM がインターネットにアクセスできることを確認した後、ソフトウェアリポジトリの URL を変更して Photon VM にパッケージを簡単にインストールできるようにする必要がありました。
cd /etc/yum.repos.d sed -i 's/dl.bintray.com\/vmware/packages.vmware.com\/photon\/3.0/g' *.repo echo distroverpkg=photon-release >> /etc/tdnf/tdnf.conf tdnf makecache && tdnf update && tdnf upgrade
これで、Lightwave をダウンロードできるようになります。
git clone https://github.com/vmware-archive/lightwave.git
lightwave/support/toolchain/docker/photon3/Dockerfile を参照して、ビルドに必要なものをすべてインストールできます。こうしてようやく、Lightwave のビルドが可能になります。
cd lightwave/build/ ./bootstrap.sh && make -j8
この方法では、Likewise-Open が提供するディストリビューションで Lightwave をコンパイルすることになりますが、目指しているのは、ライブラリを独自にビルドして、デバッグシンボルと AddressSanitizer の完全なメリットを得ることです。そこで、Likewise-Open をダウンロードしました。
git clone https://github.com/vmware/likewise-open.git
さまざまな Makefile にハードコードされている -Werror を -Wno-error に変更したら準備は完了で、以下のようにコンパイルできます(変更しなければ、かなり最近のコンパイラでも Likewise-Open をビルドできません)。
./configure \ --prefix=/opt/likewise \ --libdir=/opt/likewise/lib64 \ --datadir=/opt/likewise/share \ --datarootdir=/opt/likewise/share \ --build-isas=x86_64 \ --lw-bundled-libs='libedit' \ --enable-vmdir-provider=yes make -j8
最後に、上記で使用した Likewise-Open のビルドディレクトリに基づいて Lightwave のパス $PATH_TO_LIKEWISE を設定し、次のように実行します。
autoreconf -vif ../../../ ./configure \ --prefix="$(pwd)/$DIR" \ --enable-debug=yes \ --libdir="$(pwd)/$DIR/opt/vmware/lib64" \ --libdir="$(pwd)/$DIR/var/lib/vmware" \ --with-config=./config \ --with-likewise="$PATH_TO_LIKEWISE" make -j8
ASAN でのビルド
ASAN は gcc でも使用できますが、テストには clang を使用することにしました。ASAN を有効にするのは比較的簡単でしたが、コンパイルを成功させるためにはコンパイラのパラメータを調整する必要がありました。
export CC="clang -Qunused-arguments -fuse-ld=/usr/bin/ld" export CXX="clang++ -Qunused-arguments -fuse-ld=/usr/bin/ld" export CFLAGS="-fsanitize=address" export LDFLAGS="-fsanitize=address" export CXXFLAGS="-fsanitize=address" export ASAN_OPTIONS=detect_leaks=0
ASAN のメモリリーク検出を無効にしたことにご注意ください。Likewise-Open ライブラリのコンパイル中に、dceidl バイナリが中間ステップとしてビルドされ、IDL ファイルを C コードにコンパイルするために使用されます。このバイナリにはメモリリークがあるらしく、ASAN はビルドプロセスを停止して実行を終了しました。今回の調査の目的ではないので、メモリリークの検出は無効にしました。また、ASAN はソースのセキュリティ強化ではうまく機能しないため、FORTIFY_SOURCE コンパイルフラグは削除しました。
Mutiny でのファジング
常に扱いにくいネットワークコードをファジングしたかったため、シンプルなファジング設定を選択することにしました。コードを詳細に調べながら、調査を迅速に進めるためです。そこで、Mutiny を使用することにしました。Mutiny は簡単に設定できるように設計されたネットワークファジングツールであり、入力としてネットワークパケットを取得し、Radamsa で変更を加えてから、最後にネットワークサーバーに送信します。
ファジングの初期シードを得るには、バイナリの 1 つと通信し、送信されたパケットをキャプチャするクライアントが必要でした。設定が簡単なため、証明書管理サービスの vmcad をテスト対象として選択し、クライアントとしては Impacket を使用しました。これには、DCERPC エンドポイントと通信するための非常に便利なスクリプトが含まれています。Impacket を使用して DCERPC の機能(RPC コールやサービス検出など)を実行し、tcpdump でパケットをキャプチャしました。次に、パケットのキャプチャを Mutiny に送信し、一連のシンプルなファジングを開始しました。この時点でのファジング設定は単なるブラックボックスで、コードカバレッジのフィードバックはまったく得られませんでした。ただ、それでもわずかな労力で非常に優れた初期結果が得られました。
AFL++ でのファジング
テスト対象に効果的かつ徹底的なファジングを行うために、AFL++ を使用することにしました。これは AFL のフォークであり、コミュニティによる有用な改良が多数含まれているものです。AFL で想定しているシナリオは、ファイルから入力を受け取って正常に終了するという従来のテスト対象のファジングですが、ネットワークサーバーの場合は状況が異なります。標準的な手順は、ファイルから入力を受け取る代わりに、Preeny のような別のフレームワークを使用してネットワークから入力を受け取る関数をフックすることですが、成功率はテスト対象によって異なります。もう 1 つの方法は、ネットワーク アプリケーションのファジングに AFL-Net のようなフレームワークを使用することですが、この時点では他のツールに合わせて最新にすることは難しそうでした。これらの理由から、Likewise-Open コードにパッチを適用して、ネットワークではなく stdin からデータを取得することにしました。
コードを詳しく調べてテスト用に簡単な変更を行ったところ、すぐにわかったことがありました。ネットワークコードの大部分は、簡単に無効にすることができないのです。予想したとおり、このライブラリはソケットに関連する多くのシステムコールを実行します。たとえば bind()/listen()/accept() コールを実行したり、ネットワークからデータを取得できるタイミングを把握するためにオープンソケット上で select() コールを実行したりします。ただし、アプリケーションロジックの大部分はネットワークを処理しており、このライブラリをネットワークなしで実行させるには、多大な労力と時間が必要になります。
時間を最大に有効利用するために、ネットワークからのデータを待つ select() コードにパッチを適用し、stdin からのデータを待つようにしました。ここで、dcerpc/ncklib/comnlsn.c の関連するコードを見てみましょう。
select() のドキュメントに従って、stdin のファイル記述子だけが含まれている新しい fd_set を作成し、それを select()、つまりここでは dcethread_select() に渡します。ライブラリは複数のスレッドを使用するため、already_select をグローバル設定してパケットの受信成功後に実行が続行されないようにします。
また、ライブラリのソケットの内部表現に新しいフィールドを設定することで、別の変更も行っています。
新しい afl_fd_shim により、ネットワークではなく stdin から読み込む必要があるソケットを簡単に区別できるようになります。また、区別しないと実行が停止してしまうコードをスキップできます。
dcerpc/ncklib/comsoc_bsd.c で、ポート番号に基づいて置き換えるネットワークソケットを区別します。ここでは、vmcad がリッスンしているポートは 2014 です。
次に、アプリケーションがネットワークから読み込むタイミングで stdin から読み込む必要があります。readv() は recvmsg() と同じ iovec 型の入力を使用するため、stdin(ファイル記述子 0)からの読み取りには readv() を使用します。
最後に、Likewise-Open と Lightwave を AFL++ 向けにビルドするときに次のオプションを使用します。
export CC="afl-clang-fast -Qunused-arguments -Wl,--allow-shlib-undefined" export CXX="afl-clang-fast++ -Qunused-arguments -Wl,--allow-shlib-undefined" export AFL_USE_ASAN=1 export CFLAGS="-DAFL"
これでファジングの準備ができました。
afl-fuzz -M main -i inputs -o outputs -- ./bin/vmcad
AFL++ のスケーリング
理想的には、複数のプロセスを使用してファジングを行いたいものです。そうすれば、ハードウェアの潜在能力がすべて引き出され、より良い結果が得られます。しかし、アプリケーションを正しく動作させるためのすべてのネットワーキングコードを含めるという前述の方法は、アプリケーションがポート 2014 にバインドしようとするため、スケーリングの障害となります。複数のプロセスを使用することで、アプリケーションのすべてのインスタンスがポート 2014 へのバインドを試行し、その結果、最初のインスタンスだけがバインドに成功し、他のプロセスはそのまま続行して最終的に終了することになります。プロセスごとにランダムなポートにバインドするスキームを使うこともできますが、ポートが絶対に衝突しないようにするのはかなり面倒です。各プロセスが異なるネットワーク インターフェイスにバインドすれば、目的を果たすうえでは非常に便利です。
そこで Linux の名前空間の登場です。プロセスごとに異なる名前空間を使用することで、意図したとおりにシステムの新しいネットワークビューが作成されます。異なるインターフェイスとルーティングテーブルを持っているので、完璧にニーズを満たしています。ソースコードにアクセスできるため、unshare(CLONE_NEWNET) コールを使用して新しい名前空間に入ることができます。なお、作成された新しい名前空間ではループバック インターフェイスが設定されていないため、正しく初期化する必要があります。
これで、AFL で生成されたすべてのプロセスに対して、独自のループバック インターフェイスを持つ新しいネットワークの名前空間が作成されました。アプリケーションはそれぞれの名前空間にバインドすることができます。これは数秒間のファジングではうまく機能しましたが、ほとんどの時間、CPU がカーネルコンテキストにあるためファジングが非常に遅くなり、実質的には停止してしまうことに気が付きました。1 秒間に何千ものネットワークの名前空間を作成して破棄することは、あまり一般的なユースケースではないようです。
ただし、すべてが失われたわけではありません。デフォルトでは、AFL は main() の直前に初期化プロセスの fork() を実行し、テストケースごとに新しいプロセスを生成します。実際には、fork() の場所は変更できます。そのためには、新しい名前空間が作成された後、テスト対象で __AFL_INIT() を手動で呼び出します。その結果、新しいネットワーク名前空間がまず作成され、その後 AFL が fork() を実行します。新しく生成された対象プロセス(ネットワークポートにバインドするプロセス)によってテストケースが処理され、そのプロセスが終了して(ポートが解放されて)、また新しい対象プロセスが生成されます。実質的に、ドキュメントに従って AFL を使用して N 個のコアまでファジングをスケーリングできるようになりました。N 個のネットワーク名前空間が作成、破棄されるのは、幸いなことに 1 回だけです。
macOS バージョンのファジング
macOS の環境であること、また DCERPC.framework を使用したことにより、macOS バージョンのファジングは vCenter の実装に対して行ったものとは異なります。独自のバイナリのリバースエンジニアリングに加え、Impacket、Frida、AddressSanitizer など、追加で多くのツールを導入しました。
Impacket の変更
Impacket は、事実上 Python の標準ライブラリであり、下位層の Microsoft ネットワーク プロトコルを扱うスクリプトを実装するためのものです。Impacket には MSRPC の下位層の実装が含まれており、テストや概念実証を記述する場合には特に便利でした。
MSRPC の macOS 独自の実装は、通常のチャネルではなく UNIX ソケットに依存しているため、rpcsvchos で動作するよう Impacket を変更する必要がありました。
この変更は比較的簡単で、名前付きパイプを処理するコードを利用しますが、既存の Impacket スクリプトを使用して実装されたサービスを操作できるようになります。たとえば rpcmap.py を使用して、利用可能なサービスとそのメソッドをリストにすることができます。
rpcmap.py ncalocal:/var/rpc/ncalrpc/NETLOGON -auth-level 1 -debug -brute-opnums
上記のスクリプトは、NETLOGON ソケットに接続して、すべてのサービスとその利用可能な操作をリストします。
Protocol: [MS-NRPC]: Netlogon Remote ProtocolProvider: netlogon.dll
UUID: 12345678-1234-ABCD-EF00-01234567CFFB v1.0
Opnum 0: success
Opnum 1: success
Opnum 2: Unknown DCE RPC fault status code: 00000000
Opnum 3: Unknown DCE RPC fault status code: 00000000
Opnum 4: Unknown DCE RPC fault status code: 00000000
Opnum 5: Unknown DCE RPC fault status code: 00000000
Opnum 6: Unknown DCE RPC fault status code: 00000000
Opnum 7: Unknown DCE RPC fault status code: 00000000
Opnum 8: Unknown DCE RPC fault status code: 00000000
Opnum 9: success
Opnum 10: success
…
Opnum 47: success
Opnum 48: Unknown DCE RPC fault status code: 00000000
Opnum 49: Unknown DCE RPC fault status code: 00000000
Opnums 50-64: nca_s_op_rng_error (opnum not found)
Protocol: [MS-LSAT]: Local Security Authority (Translation Methods) Remote
Provider: lsasrv.dll
UUID: 12345778-1234-ABCD-EF00-0123456789AB v0.0
Opnum 0: Unknown DCE RPC fault status code: 00000000
Opnum 1: success
Opnum 2: Unknown DCE RPC fault status code: 00000000
Opnum 3: Unknown DCE RPC fault status code: 00000000
Opnum 4: Unknown DCE RPC fault status code: 00000000
Opnum 5: success
Opnum 6: Unknown DCE RPC fault status code: 00000000
Opnum 7: Unknown DCE RPC fault status code: 00000000
Opnum 8: Unknown DCE RPC fault status code: 00000000
Opnum 9: success
…
Opnums 60-64: success
Protocol: [MS-DSSP]: Directory Services Setup Remote Protocol
Provider: lsasrv.dll
UUID: 3919286A-B10C-11D0-9BA8-00C04FD92EF5 v0.0
Opnum 0: Unknown DCE RPC fault status code: 00000000
Opnums 1-64: nca_s_op_rng_error (opnum not found)
Protocol: [MS-SRVS]: Server Service Remote Protocol
Provider: srvsvc.dll
UUID: 4B324FC8-1670-01D3-1278-5A47BF6EE188 v3.0
Opnum 0: success
Opnum 1: success
Opnum 2: success
Opnum 3: success
Opnum 4: success
Opnum 5: success
…
Opnums 54-64: nca_s_op_rng_error (opnum not found)
Procotol: N/A
Provider: N/A
UUID: 5AB2E9B4-3D48-11D2-9EA4-80C5140AAA77 v1.0
Opnum 0: Unknown DCE RPC fault status code: 00000000
Opnums 1-64: nca_s_op_rng_error (opnum not found)
Protocol: [MS-WKST]: Workstation Service Remote Protocol
Provider: wkssvc.dll
UUID: 6BFFD098-A112-3610-9833-46C3F87E345A v1.0
Opnum 0: Unknown DCE RPC fault status code: 00000000
Opnum 1: Unknown DCE RPC fault status code: 00000000
Opnum 2: Unknown DCE RPC fault status code: 00000000
Opnum 3: success
Opnum 4: success
Opnum 5: Unknown DCE RPC fault status code: 00000000
Opnum 29: Unknown DCE RPC fault status code: 00000000
Opnum 30: Unknown DCE RPC fault status code: 00000000
Opnums 31-64: nca_s_op_rng_error (opnum not found)
Procotol: N/A
Provider: N/A
UUID: 885D85FB-C754-4062-A0E7-6872CE0064F4 v2.0
Opnum 0: Unknown DCE RPC fault status code: 00000000
Opnum 1: Unknown DCE RPC fault status code: 00000000
Opnum 2: Unknown DCE RPC fault status code: 00000000
Opnum 3: Unknown DCE RPC fault status code: 00000000
Opnums 4-64: nca_s_op_rng_error (opnum not found)
Protocol: [MS-RPCE]: Remote Management Interface
Provider: rpcrt4.dll
UUID: AFA8BD80-7D8A-11C9-BEF4-08002B102989 v1.0
Opnum 0: success
Opnum 1: Unknown DCE RPC fault status code: 00000000
Opnum 2: success
Opnum 3: success
Opnum 4: Unknown DCE RPC fault status code: 00000000
Opnum 5: Unknown DCE RPC fault status code: 00000000
Opnum 6: success
Opnums 7-64: nca_s_op_rng_error (opnum not found)
他にも Impacket に変更を加え、送受信メッセージをバイナリファイルとしてダンプするようにしました。このバイナリはファジングのシードとして使用できます。
ソースの使用
macOS 上で DCERPC.framework が使用しているコードベースはかなり古く、安定しているようです。Apple 社がソースコードを公開しているので、カスタムデバッグビルドを作成してオリジナルの rpcsvchost バイナリの代わりに使用することができます。rpcsvchost バイナリ自体とサービスバンドルはオープンソースではないためリビルドできませんが、調べたいコードの大部分は DCERPC.framework に存在します。
最初のステップは、異常なパケットを受信したときに処理の中断とサービスの強制終了が起きないようソースを変更してパッチを適用することでした。次に、変更したソースを AddressSanitizer を有効にしてコンパイルします。これにより、メモリ破損の問題を発見できる可能性が飛躍的に向上します。最後にソースコードにアクセスすることで、発見されたバグに簡単にパッチを適用できるようになり、ファジングツールが何度もバグを発見して動かなくなることがなくなります。以下のとおり、コードのビルドは非常に簡単です。
xcodebuild -configuration Debug -target DCERPC -enableAddressSanitizer YES
次に、launchd によって起動された rpcsvchost のインスタンスを無効化した後、DYLD ライブラリインジェクションを使用して、オリジナルの代わりに DCERPC フレームワークの独自のコピーを移植することができます。
DYLD_INSERT_LIBRARIES=./DCERPC:./libclang_rt.asan_osx_dynamic.dylib /usr/libexec/rpcsvchost -nolaunchd netlogon.bundle -debug -stdout
デバッガを rpcsvchost に接続するのは簡単で、標準のツールを使用して操作できます。
Frida を使用して、基本的なカバレッジガイド付きのファジングツールを作成しました。macOS SMBd の調査記事で紹介したものと同じようなツールです。receive_dispatch 関数をフックし、DCERPC.framework バイナリとテスト対象のサービスバンドル(netlogon.bundle など)のコードカバレッジをトレースすることで、かなり高速なメモリ内カバレッジガイド付きファジングツールができます。
発見された脆弱性
この調査の過程で、12 件の注目すべき脆弱性を発見しました。macOS にのみ影響する脆弱性が 7 件、vCenter にのみ影響する脆弱性が 2 件、両方に影響する脆弱性が 3 件です。発見された脆弱性は、バッファオーバーフロー、解放済みメモリ使用、情報漏洩などに分類されます。2 件の脆弱性によりサービス拒否状態が発生する可能性があり、そのうち 1 件はシステム全体をダウンさせる恐れがあります。他の 2 件は初期化されていないメモリの内容を漏洩させる脆弱性で、これによってエクスプロイト対策が回避される可能性があります。最後に取り上げる合計 8 件の脆弱性は、境界外のメモリが変更されてしまう可能性があるというものです。
認証トレーラのポインタの不適切な計算
TALOS-2022-1658(CVE-2023-20894)として追跡されています。
この脆弱性は VMware vCenter に影響し、認証ポインタを計算する際に DCERPC コードがオフセットを検証しないことに起因します。
SWAB_IN_PLACE32 の背後のマクロは、潜在的に無効なポインタを使用して動作し、任意の 4 バイトを並べ替えます。
DCERPC プレゼンテーション層の結果リストの境界外メモリアクセス
Apple 社では TALOS-2022-1659(CVE-2023-23539)、VMware 社では TALOS-2023-1800(CVE-2023-20896)として追跡されています。
この脆弱性はサービス拒否につながる可能性があり、VMware vCenter と Apple macOS の両方に影響します。
先に取り上げたバグと同様に、パケットデータが範囲の検証なしでポインタ計算に使用されます。続いて境界外のポインタが以降の操作に使用されます。潜在的に無効なポインタはメモリの変更に使用される前に検証されるため、この脆弱性はサービス拒否に限定されます。
SWAB_IN_PLACE32 とは異なり、SWAB_INPLACE_16 はポインタがパケット内にあるかどうかを実際に検証します。ただし、無効なポインタの逆参照によってアクセス違反やサービス拒否が発生する可能性があります。
Apple DCERPC パケットの統計バッファオーバーフローの脆弱性
TALOS-2022-1660(CVE-2023-23513)として追跡されています。
プロセスの有効期間中、DCERPC ライブラリは多数の重要な統計情報を記録します。ここに、受信パケットの値がテーブルのインデックスとして直接使用される脆弱性が存在します。
上記のコードは、攻撃者が管理するデータから直接取得されるパケットタイプの値が、検証なしでどのように配列のインデックスとして使用されるかを示しています。この配列は固定サイズであり、脆弱性によって境界外のメモリが変更される可能性があります。メモリレイアウトによっては、機密性の高い他のグローバルデータ構造が近くに存在し、それらの変更がプロセスの状態に悪影響を及ぼしてエクスプロイトを助長する可能性があります。この脆弱性は macOS にのみ影響します。
Apple DCERPC alloc_hint フィールドの初期化されていないメモリが漏洩する脆弱性
TALOS-2022-1675 として追跡されています。
プロトコル仕様では、初期化されていないメモリがオプションのフィールドによって流出することがよくあります。パケット構造には以前使用した雑多なデータが含まれますが、本来はゼロ化する必要があります。この種の脆弱性は、アドレス空間のレイアウトをランダム化するような確率的なエクスプロイト対策を無効化する場合に有効です。
この例では、オプションの 4 バイトの alloc_hint フィールドに、以前使用した特定のチャンクのデータやメモリポインタが含まれる可能性があります。メモリレイアウトやサービスの使用履歴によっては、他のリクエストからの機密情報、ポインタ、ヒープメタデータなどさまざまなデータがリークしたバイトに含まれる可能性があります。
Apple DCERPC 関連グループのヒープオーバーフロー
TALOS-2022-1676(CVE-2023-27935)として追跡されています。
この脆弱性は macOS のみに影響します。これも典型的な整数オーバーフローの一例であり、サイズの小さいメモリの割り当てに続いて、バッファオーバーフローが発生します。バッファ割り当てのサイズの計算に、検証されていない算術演算が使用されています。整数オーバーフローが発生するよう、サイズの小さいバッファが割り当てられる可能性があります。
上記のコードでは、乗算で new_count が使用されており、整数のラップアラウンドが発生する可能性があります。割り当て直後に、memcpy の呼び出しでサイズの小さいバッファが使用され、ヒープベースのバッファオーバーフローが発生する場合があります。
new_count は RPC_C_ASSOC_GRP_ALLOC_SIZE の増分(10)でしか増えないため、この脆弱性を引き起こすには非常に多くの同時接続が必要です。ただし別の脆弱性(TALOS-2022-1679)をエクスプロイトすれば、1 つのネットワークパケットでこの脆弱性を発生させることができます。
Apple DCERPC ゼロ長 BIND パケットの無限ループ
TALOS-2022-1679 として追跡されています。
無限ループの脆弱性は通常、リソースの枯渇攻撃とサービス拒否攻撃に限定されます。ただし TALOS-2022-1676 で概説したように、この脆弱性をエクスプロイトすれば他の脆弱性を発生させることが可能です。断片化されたパケット処理に起因する脆弱性であり、一連の複雑な計算によって、パケット解析コードがパケットの同じ部分を無限ループで繰り返し解析するようにすることができます。
基本的に、予想されるバイト数を計算するとき、パケットデータは信頼され、コードはゼロバイトが消費されている状態になりますが、解析は継続されます。これにより、悪用される可能性がある別の影響を引き起こす無限ループが構成されます。
DCERPC コールリクエストにおける初期化されていないメモリヒープオーバーフローの脆弱性
Apple 社では TALOS-2022-1677(CVE-2023-27934)、VMware 社では TALOS-2023-1801(CVE-2023-20892)として追跡されています。
この脆弱性は、Apple macOS と VMware vCenter に影響します。コールのコンテキストを保持する大きなデータ構造の初期化されていない部分が、健全性チェックで使用される可能性があります。割り当てをクリーンアップするとき、DCERPC ではよく次のようなコードを使用します。
上記のコードでは、まず buff_dealloc が NULL でないかをチェックし、次に buff_dealloc を関数ポインタとして逆参照します。buff_dealloc が有効な割り当て解除ルーチンではなく、実際には初期化されていないデータ(以前使用されたデータ)を含む状態にすることができます。デバッガで確認されるように、攻撃者がメモリのレイアウトを独自に制御して、直接的なコード実行のハイジャックを引き起こす可能性があります。
* thread #16, stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT) frame #0: 0x00007fff4d47aa85 DCERPC`rpc__cn_call_end + 480 DCERPC`rpc__cn_call_end: -> 0x7fff4d47aa85 <+480>: callq *%rcx 0x7fff4d47aa87 <+482>: movzwl 0x108(%r13), %eax 0x7fff4d47aa8f <+490>: movq $0x0, (%rbx) 0x7fff4d47aa96 <+497>: incq %r14 Target 0: (rpcsvchost) stopped. (lldb) bt * thread #16, stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT) * frame #0: 0x00007fff4d47aa85 DCERPC`rpc__cn_call_end + 480 frame #1: 0x00007fff4d483a4e DCERPC`receive_dispatch + 3999 frame #2: 0x00007fff4d4826dd DCERPC`rpc__cn_network_receiver + 1155 frame #3: 0x00007fff4d42f671 DCERPC`proxy_start + 67 frame #4: 0x00007fff6d7d3109 libsystem_pthread.dylib`_pthread_start + 148 frame #5: 0x00007fff6d7ceb8b libsystem_pthread.dylib`thread_start + 15 (lldb) reg read rcx rcx = 0xaaaaaaaaaaaaaaaa
Apple DCERPC の Alter Context 応答における解放済みメモリ使用の脆弱性
TALOS-2022-1678(CVE-2023-28180)として追跡されています。
MSRPC プロトコルの状態図はかなり複雑であるため、実装は複雑なステートマシンを持つことになります。DCERPC も例外ではありません。このステートマシンをショートさせ、パケットのバッキングバッファを早期解放させる DCERPC パケットのシーケンスが存在します。解放されたメモリへのポインタは、その後に再利用されます。これにより、解放済みメモリ使用の状態が発生し、これが任意コード実行のために悪用される可能性があります。この場合も、プロセスの実行をハイジャックする可能性のある構造体内の関数ポインタを利用することができます。
ここでは、freebuf ポインタは解放されたメモリを指しています。fragbuf_dealloc のコールに到達する前にこの解放済みメモリが再割り当てされ、攻撃者の制御下に置かれると、プログラムの実行が任意のコードにリダイレクトされる可能性があります。
Apple DCERPC 配列マーシャリング機能における初期化されていないメモリリークの脆弱性
TALOS-2022-1688(CVE-2023-27953)として追跡されています。
エクスプロイト対策を回避しようとする場合に、初期化されていないメモリリークがいかに有用であるかは、すでに説明しました。TALOS-2022-1688 もその一例であり、関数を経由する複雑なパスが原因で構造体の一部が初期化されずに残る可能性があります。この脆弱性は、RPC コールに対する応答のマーシャリングを行うコード内に存在します。脆弱なコードに到達して、その脆弱性を実証するには、適切な対象サービスが必要でした。macOS 上の rpcsvchost を通じて到達できる spotlight mdssvc サービスには、適切な入力/出力パラメータを持つ関数があります。これは、リバースエンジニアリングされた IDLでは次のようになっています。
void mdssvc_open( [in,out,ref] uint32 *device_id, [in,out,ref] uint32 *unkn2, /* always 0x17 ? */ [in,out,ref] uint32 *unkn3, /* always 0 ? */ [in][string,charset(UTF8),size_is(1025)] uint8 share_mount_path[], [in][string,charset(UTF8),size_is(1025)] uint8 share_name[], [out,string,charset(UTF8),size_is(1025)] uint8 share_path[], [out,ref] policy_handle *handle );
この脆弱性は、文字列型の可変サイズの配列である out パラメータ share_path を通じて悪用される可能性があります。攻撃者がメモリのレイアウトを独自に制御して、境界外の任意の量のデータを漏洩させる可能性があります。
Apple DCERPC の固定配列の解放済みメモリ使用の脆弱性
TALOS-2022-1689(CVE-2023-27958)として追跡されています。
コードの深いところには、入力/出力パラメータのマーシャリング/アンマーシャリング処理に起因する別の脆弱性が存在します。この脆弱性の核心は、(RPC コールを実行する際に)受信する入力パラメータのアンマーシャリングと、応答を作成する際の出力パラメータのマーシャリングの両方において、同じデータ構造が使用されていることです。この脆弱性は、メモリを指す構造体を更新せずにメモリが解放される経路が存在することにあり、解放済みメモリ使用につながる可能性があります。脆弱性を引き起こす可能性のある経路には、出力引数として固定サイズの配列を持つ RPC メソッドの呼び出しがあります。このような関数として使用できるのは、netr_ServerReqChallenge、すなわち NETLOGON サービス(macOS では、NETLOGON は netlogon.bundle に実装されています)の関数 0x04 です。IDL では、悪用が可能なデータ構造は次のようになっています。
さらに、解放済みメモリ使用の脆弱性が悪用されると、メモリ破損が発生します。
DCERPC 関連グループの解放済みメモリ使用の脆弱性
Apple 社では TALOS-2023-1717(CVE-2023-32387)、VMware 社では TALOS-2023-1799(CVE-2023-20893)として追跡されています。
macOS と vCenter の両方に影響を与える脆弱性がもう 1 件ありますが、これは複数のクライアントを処理する際の時間的な問題に起因しています。接続はバッチで処理され、クライアントの切断やセッションの終了によって解放されます。この処理で不一致が生じると、リンクされているリストが解放済みのメモリを指すことになり、ヒープメモリの破損につながる可能性があります。
==72659==ERROR: AddressSanitizer: heap-use-after-free on address 0x616000020488 at pc 0x7ffff6e6ac40 bp 0x7fffc8f60c70 sp 0x7fffc8f60c68 WRITE of size 8 at 0x616000020488 thread T92 #0 0x7ffff6e6ac3f in rpc__cn_assoc_grp_create ../../../dcerpc/ncklib/cnassoc.c:4958 #1 0x7ffff6e6b059 in rpc__cn_assoc_grp_alloc ../../../dcerpc/ncklib/cnassoc.c:5086 #2 0x7ffff6e993d9 in do_assoc_req_action_rtn ../../../dcerpc/ncklib/cnsassm.c:2006 #3 0x7ffff6e9b4b2 in do_assoc_action_rtn ../../../dcerpc/ncklib/cnsassm.c:3461 #4 0x7ffff6ea5d69 in rpc__cn_sm_eval_event ../../../dcerpc/ncklib/cnsm.c:771 #5 0x7ffff6ea980a in _RPC_CN_ASSOC_EVAL_NETWORK_EVENT ../../../dcerpc/ncklib/cninline.c:129 #6 0x7ffff6e933c1 in receive_dispatch ../../../dcerpc/ncklib/cnrcvr.c:1256 #7 0x7ffff6e8d7d1 in rpc__cn_network_receiver ../../../dcerpc/ncklib/cnrcvr.c:348 #8 0x7ffff6cc73fd in proxy_start ../../../dcerpc/libdcethread/dcethread_create.c:100 #9 0x7ffff631ff86 (/lib/libpthread.so.0+0x7f86) #10 0x7ffff621062e in __clone (/lib/libc.so.6+0xf362e)
AddressSanitizer のログに、無効なメモリへ書き込もうとしてクラッシュしたことが示されています。
VMware vCenter サーバーの DCERPC save_sec_fragment における境界外ポインタの脆弱性
TALOS-2023-1740(CVE-2023-20895)として追跡されています。
データ漏洩やメモリ破損を発生させる他の脆弱性とは異なり、この脆弱性は認証をバイパスする可能性があります。脆弱性の中核は、認証トレーラの計算方法にあります。
auth_tlr = header + frag_len - (auth_len + 8)
上記のすべての演算はパケットデータに基づいており、攻撃者の管理下にあってチェックされていません。そのため攻撃者は、バッファの制限を超えて auth_tlr ポインタを任意に設定することができます。さらにコードを調査すると、攻撃者がこの脆弱性を悪用して、境界外の任意のデータを認証に使用するようコードに指示を与えられることが判明しました。複数のクライアントが使用するサーバーにおいて、境界外のデータが別のクライアントの有効な認証データを指すように設定され、機密性に影響を与えることが考えられます。
この脆弱性は、DCERPC コードベースの vCenter バージョンのみに存在します。
カバレッジ
今回の脆弱性のエクスプロイトは、Snort ルール(60934 ~ 60941、60966、60967、60970、60971、61193、61201)で検出できます。今後、脆弱性に関する新たな情報が追加されるまでの間は、ルールが追加されたり、現行のルールが変更されたりする場合がありますのでご注意ください。最新のルールの詳細については、Cisco Secure Firewall Management Center または Snort.org を参照してください。
本稿は 2023 年 07 月 13 日に Talos Group のブログに投稿された「Uncovering weaknesses in Apple macOS and VMWare vCenter: 12 vulnerabilities in RPC implementation」の抄訳です。