
CVE-2026-92744の公開記事です。Delinea Privilege ManagerのWindowsエージェントにおいて、空のWCF証明書バリデータを介して認証なしでリモートコード実行が可能となる脆弱性で、根本原因の分析と再現手順を掲載しています。
CVE-2026-92744 · 公開報告書 株式会社CyberCrew
| 項目 | 値 |
|---|---|
| CVE ID | CVE-2026-92744 (CNA: Delinea, Inc.) |
| タイトル | Delinea Privilege Manager エージェントの未認証リモートコード実行脆弱性 |
| 分類 | CWE-306 重要な機能に対する認証の欠如(主); CWE-295 不適切な証明書検証(機構) |
| 影響範囲 | Privilege Manager Windows Core エージェント 10.1.0 → 12.0.5796 および 13.0.0 → 13.0.1058 |
| 修正版 | エージェント 12.0.5804 (v12) および 13.0.2064 (v13); Privilege Manager 13.0.2 に同梱、2026年10月28日 |
| 公開 CVSS | 8.7 High (CVSS 4.0) — CVSS:4.0/AV:N/AC:H/AT:P/PR:H/UI:A/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H |
| 当社の評価 | 9.8 Critical(ネットワーク、推定)/ 7.8 High(ローカル、実証済み)— §6 参照 |
| 研究者 | Isuka Sanuj(リード)· Ishan Nim(コントリビューター)— 両名とも株式会社CyberCrew |
| ベンダーケース | #01416021(関連: 01418441) |
| 検証ビルド | 13.0.1041.338 (PMAgents_13_0_1041.exe)、SHA-256 9ED7660B9D994620B3ECADC524EB10122C42E3A932CCFD2988F16A5D76FF0457、Authenticode 有効 (CN=Delinea Inc.) |
| ステータス | 2026年9月14日報告 · ベンダーにより修正・公開・研究者クレジット適用済み — クローズ |
Privilege Manager Windows エージェントは、TCP 5593 上で WCF デュプレックスコールバックエンドポイントを公開しており、すべてのインターフェースにバインドされ、インストーラーがドメイン、プライベート、およびパブリックプロファイル向けにインバウンドファイアウォールルールを開きます。このエンドポイントは名目上クライアント証明書を要求しますが、それを検証するはずのバリデータ — AmsServerCertValidator.Validate() — は本体が空であり、コントラクトは ProtectionLevel.None を宣言しているため、メッセージ層の署名が排除されています。その結果、コントラクト上のすべての操作は、呼び出し元が数秒前に生成した証明書を提示するだけで受け入れられます。
これらの操作のうち2つを連鎖させることで、完全な侵害に至ります:
OnRegistrationComplete は攻撃者が提供した証明書を LocalMachine\Ams に書き込み — これはエージェントがポリシー署名の検証に使用するストアです — そして正規の証明書を削除します。OnClientTaskQueued はエージェントを操作して、設定されたサーバーからコマンドを取得させ、PowerShell 実行空間で nt authority\system として、ExecutionPolicy.Bypass を明示的に設定した状態で実行させます。この完全な連鎖は、2026年9月12日に Windows Sandbox(Windows 11 ビルド 26200)上のクリーンなデフォルトインストールでエンドツーエンドで再現され、nt authority\system での実行証明が取得されました。認証情報、事前のローカルアクセス、ユーザー操作はいずれも不要でした。
この製品の目的はどのプロセスを昇格実行できるかを決定することであるため、これは単なるホスト上のコード実行ではなく、セキュリティ上の意思決定そのものの制御です。
この発見は2026年9月14日に Delinea へ報告され、2026年10月28日のリリースで修正され、CVE-2026-92744 が割り当てられました(2026年10月29日公開)。クレジットの要請に応じ、Delinea は合意された研究者への謝辞を公開記録に追加しました。本開示はこれでクローズされます。§8〜§10 を参照してください。
| 製品 | 影響範囲 | 修正版 |
|---|---|---|
| Privilege Manager Windows Core エージェント (v12) | 10.1.0 → 12.0.5796 | 12.0.5804 |
| Privilege Manager Windows Core エージェント (v13) | 13.0.0 → 13.0.1058 | 13.0.2064 |
修正は2026年10月28日に Privilege Manager 13.0.2 とともに出荷されました。直ちにアップグレードできないお客様向けに、Delinea が文書化した緩和策はインバウンド TCP 5593 をブロックすることです(機能の損失はないとされており、エージェントはスケジュールに従ってサーバーから更新を取得する動作にフォールバックします)。
エージェントは System として実行され、すべてのインターフェースでコールバックリスナーをホストし、インストーラーが作成したファイアウォールルールはパブリックプロファイルをカバーしています:
--- listeners ---
:::5593 pid=4 proc=System <- all interfaces (http.sys)
--- firewall ---
[Domain, Private, Public] Arellia Agent (SSTP-In) | dir=Inbound action=Allow port=5593 prog=System
テスト対象の構成は、インストーラーの初期設定そのままの状態でした。何も弱められていませんでした:
HKLM\SOFTWARE\Policies\Arellia\AMS
BaseUrl = https://localhost/TMS/
InstallCode = testinstallcode
BaseUrlOverride = https://localhost/TMS/
ValidateServerCertificate と ValidateCertChain はどちらも存在しません(インストール時のデフォルト)。エンドポイントはホスト名にちなんで名付けられた自己署名証明書(CN=7D20AF86-E474-4)を提示します。
空の Validate() を持つ単一のバリデータクラスが、3つの信頼判断を支配しています:
internal class AmsServerCertValidator : X509CertificateValidator
{
public override void Validate(X509Certificate2 certificate)
{
}
}
| サイト | 統制されるパス |
|---|---|
_serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator | インバウンドコールバック呼び出し元 |
AgentRegistration2Client.CreateClient(...) | アウトバウンド登録 |
ClientBaseFactory.CreateClient<ClientItems2Client, ...> | アウトバウンドポリシー取得 |
インバウンドホストは、そのバリデータをカスタム検証モードとして組み込み、WCFのデフォルトのチェーン検証を空のメソッドに置き換えます:
wSHttpBinding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
wSHttpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
wSHttpBinding.Security.Message.EstablishSecurityContext = false;
...
_serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode
= X509CertificateValidationMode.Custom;
_serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator
= new AmsServerCertValidator();
[ServiceContract(Namespace = "http://schemas.arellia.com/agent/services/",
Name = "IAgentRegistration",
SessionMode = SessionMode.NotAllowed,
ProtectionLevel = ProtectionLevel.None)]
public interface IAgentRegistrationCallback
{
void OnRegistrationComplete(PlatformRegistration platformDetails);
void OnApplicablePolicyChange(ClientItemDigest[] applicablePolicyDigests);
void OnClientTaskQueued(PendingTaskExecutionInstance[] pendingTasks);
void OnBadRegistration(Guid suggestedNewId);
}
ProtectionLevel.None はメッセージ署名を削除し、クライアント証明書だけを呼び出し元のチェックとして残します — そしてそのチェックは上記の空のメソッドです。宣言された4つの操作すべてが、自己署名の呼び出し元から到達可能であることが確認されました(OnRegistrationComplete、OnClientTaskQueued、OnApplicablePolicyChange、OnBadRegistration — すべて accepted=True)。
OnRegistrationComplete)登録完了時、エージェントはサーバーの応答に含まれるすべての証明書を取り込み、チェーンの構築も、ピン留めも、既知の証明書との比較も行わずに Ams ストアへ保存します:
foreach (string serverCertificate in platformDetails.ServerCertificates)
{
byte[] raw = Convert.FromBase64String(serverCertificate);
ICertificate2 certificate2 = _cert2Factory.Create(raw);
list.Add(certificate2);
}
_certMgr.SaveServerCertificates(list);
唯一の catch は不正な base64 のみを対象としています。SaveServerCertificates は LocalMachine\Ams を読み書きモードで開き、攻撃者のリストに存在しないすべての証明書を削除してから、攻撃者の証明書を追加します。別々のクリーンインストール環境で2回再現済み:
[16:21:46] LocalMachine\Ams before: 0 cert(s):
[16:21:52] attacker cert: 13E298FDE814B0B34B1BBB83631BF54276FCF2FC CN=attacker.invalid
[16:21:53] --- INVOKING OnRegistrationComplete with our certificate ---
[16:21:54] call returned without exception
[16:22:06] LocalMachine\Ams after: 1 cert(s): 13E298FDE814B0B34B1BBB83631BF54276FCF2FC
植え付けられた証明書は自己署名であり、CN=attacker.invalid を持ち、呼び出しの数秒前に生成されたもので、エージェント、そのサーバー、または信頼された CA とのいかなる関係も持っていませんでした。これにより、攻撃者がポリシー上でエージェントが信頼する署名の権威となる——これが次の段階で RequireSignedClientItems を破る要因です。
OnClientTaskQueued → AgentController.RunTask)実行時にでっち上げた CommandId GUID を持つタスクをキューに入れると、エージェントは設定されたサーバーからそのコマンドを取得するよう駆り立てられます。この GUID はどのデータベース、設定、ファイルにも存在しません——エージェントがそれを知り得る唯一の方法は、認証されていない呼び出しです:
[18:03:10] --- calling OnClientTaskQueued (unauthenticated) ---
[18:03:12] call returned without exception
[18:03:22] MARKER SEEN after 10s
リスナーで観測されたリクエストシーケンス:
18:03:10 POST /TMS/Agent/AgentRegistration4.svc
18:03:17 POST /TMS/Agent/AgentRegistration4.svc
18:03:17 POST /TMS/Agent/ClientItems2.svc <- went to fetch the command
18:03:22 POST /TMS/Agent/AgentRegistration4.svc <- reported the result
AgentController.RunTask の実行プリミティブ — エージェントが報告した例外はマークされた行でスローされ、その直後のステートメントが PowerShell 実行空間を構築します:
if (!ClientItemManager.RegisterInterest(taskInstance.CommandId))
ClientItemManager.RefreshClientItems();
clientItem = ClientItemManager.GetRawClientItem(taskInstance.CommandId);
...
if (clientItem == null)
throw new Exception($"Failed to get ClientCommand {taskInstance.CommandId}"); // <-- reached here
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();
...
runspaceDispatcher.SetExecutionPolicy(ExecutionPolicy.Bypass, ExecutionPolicyScope.Process);
runspaceDispatcher.ImportModule("Arellia.Agent");
...
AgentPowershellScriptContract agentPowershellScriptContract =
(AgentPowershellScriptContract)clientItem.InnerContract;
pSCommand.AddScript(agentPowershellScriptContract.Script);
エンドツーエンドの再現では、エージェントを完全にその独自プロトコル経由で操作し、以下を実行させました: