
BeyondTrust Remote SupportおよびPRAにおける未認証RCEのための非破壊的検出器で、引数インジェクションとPostgreSQLエスケープバイパスを連鎖させ、時間ベースの差分により悪用可能性を検証します。
倫理的警告: 研究、教育、および許可されたテスト目的のみに使用してください。許可なくシステムに対して使用しないでください。
BeyondTrust Remote Support (RS) および Privileged Remote Access (PRA) は、組織の内部システムへの特権リモートセッションを仲介するアプライアンスであり、インターネットに頻繁に露出し、ネットワーク上で信頼された位置を占めています。
アプライアンスの WebSocket エンドポイントに到達できる未認証の攻撃者は、2 つの欠陥を連鎖させることで、サイトユーザーとしてオペレーティングシステムコマンドを実行できます。それは、アプライアンスの thin-scc-wrapper スクリプトにおける引数インジェクション (CVE-2024-12356) と、無効な UTF-8 バイトを早期の SQL リテラル区切りに変える PostgreSQL 文字列エスケープ回避 (CVE-2025-1094) です。脆弱なパスには、認証前に到達します。
このリポジトリの bt_rs_rce_check.py は、その連鎖に対する非破壊的な検出器です。これは、実際のエクスプロイトが使用する正確な未認証コードパスを駆動しますが、到達可能性の証明で停止します。ターゲットに実行させるのは、無害な sleep (時間ベースの差分) または、あなたが制御する帯域外コレクタへの無害なホスト名/HTTP ルックアップのみです。シェルを開いたり、ファイルを書き込んだり、データを読み取ったり、永続化したり、横移動したりすることは決してありません。
psql の無効な UTF-8 SQL インジェクションの欠陥。RCE を完成させるために連鎖BT24-10-ONPREM1 / BT24-10-ONPREM2; クラウドインスタンスは BeyondTrust によってパッチ適用済み)。CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:Hこの連鎖により、内部システムへの特権アクセスを仲介することだけを目的としたアプライアンス上で、サイトユーザーとして未認証のリモートコード実行が可能になります。そのため、単一の匿名リクエストによって、露出した RS または PRA ホストが足場となり、アプライアンスが仲介するすべての下流システムへのピボットポイントに変わります。
認証情報、ユーザー操作、事前アクセスは一切不要です。攻撃者は外部の匿名ユーザーであり、唯一の前提条件はアプライアンスの WebSocket エンドポイントへのネットワーク到達可能性です。
この脆弱性は、実際に悪用されていることが発見された後に開示され、2024 年 12 月 19 日に CISA Known Exploited Vulnerabilities カタログに追加され、国家支援を受けた攻撃者によるものとされる 2024 年 12 月の米国財務省への侵害に公に関連付けられています。
脆弱なロジックは、アプライアンスの thin-scc-wrapper シェルスクリプトに存在し、未認証の WebSocket フレームから攻撃者が制御するセッションキー (gskey) を読み取り、データベースに向けて渡します。完全な RCE は、3 つの異なる問題の連鎖です。
1. thin-scc-wrapper における引数インジェクション (CVE-2024-12356)。 ラッパーは、信頼できない gskey をヘルパーに引用符なしで渡すため、echo が実行される前にシェルがそれを引数に単語分割します:
quoted=$(export PHPRC="$BG_app_root/config/php-cli.ini"; echo $gskey | $ingrediRoot/app/dbquote)
-e で始まるキーは echo を echo -e に変え、バックスラッシュエスケープを解釈し、攻撃者が次のステージに流れるデータに任意の生バイト — 最も重要なのは \xC0 — を出力できるようにします。攻撃者は、新しいコマンドを注入するのではなく、既存のコマンドのフラグを制御します。これが、古典的なコマンドインジェクションではなく、引数インジェクション (CWE-88) である理由です。
2. 無効な UTF-8 による PostgreSQL エスケープ回避 (CVE-2025-1094)。 dbquote は、libpq の PQescapeStringInternal() を呼び出す PHP の pg_escape_string() で値をエスケープします。マルチバイト文字の場合、pg_encoding_mblen() によって報告された長さを信頼し、文字のバイトを検証せずにそのままコピーします:
len = pg_encoding_mblen(encoding, source);
for (i = 0; i < len; i++) /* copy the character */
*target++ = *source++;
0xC0 のようなバイトは 2 バイト文字を宣言するため、エスケープ処理は次のバイトをその「継続」バイトとして飲み込みます — そのバイトが一重引用符 (0x27) であってもです。したがって、シーケンス 0xC0 0x27 は、「エスケープされた」文字列にエスケープされていない一重引用符バイトが埋め込まれたまま通過します。
3. psql がリテラルから抜け出して \! を実行する (CVE-2025-1094)。 「エスケープされた」文字列は psql にパイプされますが、psql は 0xC0 0x27 を 1 文字として扱わないため、0x27 が SQL 文字列リテラルを早期に閉じ、それ以降はすべて新しい入力として解析されます。攻撃者はこれを使用して、サイトユーザーとしてシェルコマンドを実行する psql の \! メタコマンドに到達します:
<0xC0>'; \! <cmd> #
Rapid7 は、実際の RCE は常に CVE-2025-1094 に依存しており、それ単独で十分であることを発見しました。バイナリ WebSocket フレーム内で生の 0xC0 バイトを配信すると (UTF-8 検証によって除去されるテキストフレームではなく)、gskey に変更されずに到達し、echo -e ステップを一切使わずに SQL ブレイクアウトを引き起こします。この検出器は、このバイナリフレームアプローチを使用します。
連鎖全体は、単一の WebSocket を介して認証前に到達可能です:
/nw への未認証 WebSocket (アプライアンス上の Tornado ハンドラー)。Sec-WebSocket-Protocol: ingredi support desk customer thin ヘッダーで選択され、URL エンコードされた ingredi%20support%20desk%20customer%20thin として送信されます。Host ヘッダー (インストール済みの会社にマッピング) から解決されるか、フォールバックとして X-Ns-Company ヘッダーから解決されます。どちらもインストール済みの会社にマッピングされない場合、アプライアンスは gskey が処理される前にソケットを閉じます。1、thinMint UUID、authType 0 (gskey 認証)、次に悪意のある gskey を運ぶ、改行区切りのバイナリフレーム (バージョン 1 は locale_code 行がないことを意味します):1
<thinMint UUID>
0
<0xC0>'; \! <cmd> #
BT24-10 は、dbquote/psql に到達する前に、英数字以外の gskey を拒否する入力検証ゲートを追加します:
elif [[ ! "$gskey" =~ ^[a-zA-Z0-9]{32}$ ]]; then
blog "bad session key given"
...
exit 1
0xC0、引用符、またはシェルメタ文字を含むキーは拒否され、スクリプトは終了するため、パッチ適用済みのアプライアンスは 1 failure 応答もコマンド実行も生成しません。検出器は、この動作の違いを、ターゲットからのアウトバウンド接続を必要としないエグレス非依存の時間ベースの差分に変換します:
A × 32)。パッチ適用済みと未適用の両方のビルドで、これは DB ルックアップに到達し、['2\n', '1 failure\n'] を迅速に返します。<0xC0>'; \! sleep <delay> #。脆弱なホストでは、psql が注入された sleep を実行するため、1 failure 応答はおよそ <delay> 秒遅延します。パッチ適用済みのホストでは、gskey 正規表現がキーを拒否し、スクリプトが終了し、ソケットは応答なしで高速に閉じます。判定はアプライアンス自身の応答のタイミングに依存するため、ターゲットがアウトバウンド DNS/HTTP をブロックしている場合でも有効です — この場合、OAST コールバックだけでは誤検知 (偽陰性) になります。オプションのコールバックモードは、エグレスを許可するホストに対する裏付けのみです。
1 つの依存関係をインストールします:
pip install -r requirements.txt
差分モード (推奨、エグレス非依存):
python3 bt_rs_rce_check.py --target rs.example.com --mode differential
OAST 裏付け付き差分:
python3 bt_rs_rce_check.py --target rs.example.com \
--oast <your-collector>.oast.pro --mode both
Host ヘッダーがテナントに解決されない場合は、明示的なスラッグ、または X-Ns-Company ヘッダーを介して順に試行される候補スラッグのファイル (1 行に 1 つ) を提供します:
python3 bt_rs_rce_check.py --target rs.example.com --company acme
python3 bt_rs_rce_check.py --target rs.example.com --company-list slugs.txt
主要なオプション:
| オプション | 意味 |
|---|---|
--target <host> | アプライアンスの仮想ホスト / FQDN (必須)。 |
--company <slug> | 明示的なテナントスラッグ。X-Ns-Company として送信されます。 |
--company-list <file> | 候補スラッグのファイル。1 つが解決されるまで試行されます。 |
--oast <domain> | コールバックの裏付け用の帯域外コレクタドメイン。 |
--mode {differential,callback,both} | 検出戦略 (デフォルト differential)。 |
--delay <seconds> | 時間ベースのテスト用の sleep 時間 (デフォルト 9)。 |
--timeout <seconds> | プローブあたりのソケットタイムアウト (デフォルト 25)。 |
--header 'H: v' | 追加の生リクエストヘッダー。繰り返し可能。 |
結果の解釈:
VULNERABLE — 注入された 1 failure 応答が、コントロールと比較しておよそ --delay 秒遅延しました。sleep が実行されました。このホストでは未認証 RCE 連鎖が悪用可能です。PATCHED — コントロールは 1 failure を高速に返しましたが、インジェクションは応答なしで拒否されました。BT24-10 の gskey 正規表現が有効であり、インジェクションは psql シンクに到達しません。UNRESOLVED ("company did not resolve") — どちらのプローブも 1 failure を生成しなかったため、コントロールも gskey ハンドラーに到達しませんでした。これはパッチ適用済みの結果ではありません。Host/会社がインストール済みの会社にマッピングされなかったため、アプライアンスがソケットを閉じました。正しい仮想ホスト (--target) または有効なスラッグ (--company / --company-list) で再試行してください。BT24-10 (BT24-10-ONPREM1 / BT24-10-ONPREM2) を適用するか、24.3.1 以降にアップグレードしてください。この連鎖は PostgreSQL の psql の欠陥 (CVE-2025-1094) にも依存するため、PostgreSQL クライアントツールもパッチ適用済みに保ち、可能な場合はアプライアンスの WebSocket エンドポイントへのネットワーク露出を制限してください。
psql の無効な UTF-8 / SQL インジェクションの欠陥。RCE を完成させるために連鎖。rapid7/metasploit-framework PR #19877、BeyondTrust RS/PRA に対する未認証 RCE。このソフトウェアは、許可されたセキュリティテストおよび防御的研究のみを目的として提供されます。所有しているシステム、または書面で明示的にテストを許可されたシステムに対してのみ実行してください。これは、武器化されたコマンド実行、データアクセス、および永続化を意図的に回避する非破壊的な検出器です。適用されるすべての法律の遵守および適切な許可の取得については、利用者が単独で責任を負います。著者は誤用に対する責任を負いません。