遠隔実行によるワーム攻撃の可能性、リモートデスクトップの脆弱性「CVE-2019-0708」を詳細解説

Microsoftは、2019年5月の月例セキュリティ情報において、リモート・デスクトップ・サービス(Remote Desktop Services、RDS)における脆弱性「CVE-2019-0708」を修正する更新プログラムを公開しました。「BlueKeep」とも呼ばれるこの脆弱性は、細工したメッセージを遠隔から対象のサーバに送信することで攻撃に利用可能です。この脆弱性を利用した攻撃に成功すると、管理者権限で任意のコードを実行できます。これはつまり、2017年に登場し現在に至るまで拡散を続けている「WannaCry」のように、自律的なワーム活動による自動的な拡散が容易に可能になることを意味します。外部のセキュリティ研究者の調査では、リモートデスクトップ機能が標準で使用するポート3389を露出させているデバイスが100万台近く存在していることが分かっており、攻撃発生の危険性が高まっています。前出の通り、既に本脆弱性に対する修正プログラムは公開済みですので、速やかに修正プログラムを適用することを推奨します。

緩和策と防御策に焦点を当てた初期調査の一方で、Trend Micro ResearchのPengsu Cheng、Kamlapati Choubey、Saran Netiは、この脆弱性に対する詳細な解析に取り組みました。本記事は、CVE-2019-0708に関するトレンドマイクロの詳細解析結果をまとめたものです。

■「CVE-2019-0708」の仕組み

以前はTerminal Servicesと呼ばれていたMicrosoftのRDSは、遠隔からセッションを開始しWindowsを操作することを可能にします。RDSは、複数のターミナル(クライアント)が単一のホスト(サーバ)に接続するターミナルベースの環境に似た機能も提供します。ユーザは遠隔からホストコンピュータにログオンし、データへのアクセスやアプリケーションの実行のような操作を行うことが可能です。クライアントは、初期設定で、遠隔サーバの3389/TCPポートに対してリモート・デスクトップ・プロトコル(Remote Desktop Protocol、RDP)を使用して通信します。

RDPは、共有されたプログラムを閲覧および共同で操作するカンファレンスの参加人数を指定します。RDPは「ITU-T T.128 Application Sharing Protocol」をMicrosoftが拡張したプロトコルで、「T.124 Generic Conference Control(GCC)」や「T.122 Multipoint Communication Services(MCS)」などの「T.120標準」の下位プロトコルが提供するその他のサービスを利用します。

RDP接続は、図1のように「Remote Desktop Protocol: Basic Connectivity and Graphics

Remoting」で定義された接続シーケンスメッセージによって開始されます。各メッセージのフォーマットは同資料を参照してください。

RDPの接続シークエンスメッセージ

図1:RDPの接続シークエンスメッセージ

問題の脆弱性は、「MCS Connect Initial and GCC Create」リクエストに関連しています。このリクエストは、クライアントが「X.224 Connection Confirm」レスポンスを受信した後にサーバに送信されます。この「MCS Connect Initial and GCC Create」リクエストにはセキュリティ関連の情報、仮想チャンネルの作成に関する情報、対応しているRDPクライアントの機能に関する情報が含まれます。図2は「MCS Connect Initial and GCC Create」リクエストの構造です。

「MCS Connect Initial and GCC Create」の構造

図2:「MCS Connect Initial and GCC Create」の構造

「tpktHeader」フィールドを除くすべてのマルチバイト整数のバイトオーダーはリトルエンディアンです。

  • X.224レイヤは一般に任意の長さから成るいくつかのProtocol Data Unit(PDU)タイプを持つことができますが、「MCS Connect Initial and GCC Create」パケットは3バイトのx224構造体を持ちます。
  • 「mcsCi」構造体は、「ASN.1 DER」でエンコードされた「T.125 MULTIPOINT-COMMUNICATION-SERVICE Connect-Initial PDU」です。この構造体の定義はこちらを参照してください。
  • 「gccCrq」構造体は「T.124 Generic Conference Control ConnectData」です。この構造体の定義はこちらを参照してください。

「Settings Data Blocks」は1つ以上の「Settings Data Block」を連結したものです。各「Settings Data Block」は図3のフォーマットに従います。

「Settings Data Block」の構造

図3:「Settings Data Block」の構造

Settings Data Block」には「CS_CORE (0xC001)」、「CS_SECURITY (0xC002)」、「CS_NET (0xC003)」のようなさまざまな種類が存在します。

tpktHeader」フィールドの構造は図4の通りです。

「tpktHeader」フィールドの構造

図4:「tpktHeader」フィールドの構造

「tpktHeader」フィールド内のすべてのマルチバイト整数のバイトオーダーはビッグエンディアンです。「version」は「0x03」でなければならず、「tpktLength」がパケット全体の長さを定義します。問題の脆弱性は「clientNetworkData」とも呼ばれる「CS_NET Settings Data Block」に関連しています。

clientNetworkData」には、リクエストされた仮想チャンネルのリストが含まれています。「clientNetworkData」の構造は図5の通りです。

「clientNetworkData」の構造

図5:「clientNetworkData」の構造

「clientNetworkData」のための「CS_NETHeader」フィールドは「0xC003」です。これをリトルエンディアンで表現すると「\x03\xc0」となります。「channelCount」フィールドは、リクエストされた静的な仮想チャンネルを示しています。「channelNamen(nは1,2,…,N)」フィールドは、終端がnull値の8バイトのチャンネル名を定義し、「channelOption_n」フィールドは当該チャンネルの属性を指定します。

RDPは静的な仮想チャンネルに対応しています。これは、さまざまなRDPコンポーネントとユーザの拡張機能との通信を接続するための使用を想定したものです。これらのチャンネルは8バイトのチャンネル名によって識別され、Microsoftがサポートしている「rdpdr(リダイレクト)」、「rdpsnd(音声)」、「cliprdr(クリップボードの共有)」のような標準的なチャンネルを含みます。ユーザはその他のチャンネルに対応するためにRDP APIを使用してモジュールを作成することが可能です。前述したチャンネルに加え、Microsoftは初期設定で「MS_T120(RDP自体のために使用)」および「CTXTW(Citrix ICAで使用)」という2つのチャンネルを作成します。これらのチャンネルは、ネットワーク上でクライアントによって作成されることは期待されていません。代わりに、接続が確立された際に、Windows RDPによって内部的に初期化されます。

チャンネルは「termdd!IcaCreateChannel()」を使用して作成されます。この関数は指定されたチェンネル名が存在するかチェックし、存在しない場合チャンネル構造体を割り当てます。このチャンネル構造体へのポインタ(「ChannelControlStructure」と呼ぶことにします)は、あるテーブル(「ChannelPointerTable」と呼ぶことにします)に格納されます。すべてのRDP接続は、図6のような「ChannelPointerTable」から始まります。最初の5つのスロットはユーザが操作することができないため表示されていません。クライアントが書き込むことのできる最初のチャンネルが「Slot Number」が「0」のチャンネルです。

RDP接続開始時の「ChannelPointerTable」

図6:RDP接続開始時の「ChannelPointerTable」

図6のテーブルは、各スロットに「ChannelControlStructure」ポインタを格納することができます。「Empty」と表示されているスロットにはNULLポインタが格納されています。RDPクライアントが「clientNetworkData」内でチャンネルを指定することにより、接続を開始してチャンネルを開く際、対応する「ChannelControlStructure」が作成され、それらのポインタがスロット0から「ChannelPointerTable」に格納されます。ただし、CTXTWへのポインタは常にスロット7、「MS_T120」へのポインタは常にスロット0x1Fであることに留意してください。

Microsoft WindowsのRDPカーネルドライバ「termdd.sys」には解放後使用の脆弱性が存在します。「clientNetworkData」と「ChannelControlStructure」を含む「MCS Connect Initial and GCC Create」パケットを受信した際に、そこで指定されたチャンネルが作成されます。例えばスロット10で「MS_T120\x00」というチャンネル名が指定された場合、「termdd!IcaCreateChannel()」は「termdd!IcaFindChannelByName()」を呼び出し、スロット0x1Fに格納された「MS_T120」構造体へのポインタが指す「ChannelControlStructure」を返します。スロット0x1Fと同一のこのポインタは、「termdd!IcaBindVirtualChannels()」の中でユーザが指定したスロット(この例ではスロット10)に格納されます。次に、「MCS Channel Join Request」を使用して各チャンネルが開かれる際、この「MS_T120」チャンネルも開かれます。攻撃者が細工したデータを「MS_T120」に送信すると、「termdd.sys」はエラーメッセージを返信し、「termdd!IcaCloseChannel()」を使用してこのチャンネルを閉じようとします。この関数は「termdd!_IcaFreeChannel()」を呼び出し、「MS_T120」チャンネルの「ChannelControlStructure」を開放してユーザが指定した「ChannelPointerTable」内のポインタ(この例ではスロット10)をクリアします。しかし、スロット0x1Fに格納された同一のポインタはクリアされません。その結果、接続が終了する際に、「RDPWD!SignalBrokenConnection()」が呼び出されます。続いて「RDPWD!SignalBrokenConnection()」は「termdd!IcaChannelInputInternal()」を呼び出し、スロット0x1Fのポインタを使用して、開放された「ChannelControlStructure」に書き込もうとします。これにより、解放後使用が発生します。

認証されていない遠隔の攻撃者は、対象サーバとRDP接続を確立して「MS_T120」チャンネルを開き、細工したデータを送信することでこの脆弱性を利用することができます。脆弱性の利用に成功すると、攻撃者はカーネルレベルの管理者権限で任意のコードを実行することが可能になります。

■ソースコードの概観:「CVE-2019-0708」を利用する攻撃を検出する方法

下の図は「termdd.sys version 6.1.7601.24056」のソースコードです。コメントはここまでの解説に沿ってトレンドマイクロが追加したものです。

「termdd.sys version 6.1.7601.24056」のソースコード

図7:「termdd.sys version 6.1.7601.24056」のソースコード

CVE-2019-0708を利用する攻撃を検出するために、検出デバイスは、割り当てられたポート上のトラフィックを監視して構文解析する必要があります。初期設定の使用ポートは3389/TCPです。

上述したように、RDP接続は一連の接続シーケンスメッセージから始まります。この接続シーケンスメッセージは下図のように「Remote Desktop Protocol: Basic Connectivity and Graphics Remoting(MS-RDPBCGR)」で定義されています。

RDPの接続シークエンスメッセージ

図8:RDPの接続シークエンスメッセージ(図1を再掲)

注:

  • この検出方法は「MCS Connect Initial and GCC Create」に関連したものです。
  • RDPには、カスタム暗号化方式およびTLSを使用した暗号化方式という2種類の暗号化方式があります。前者の場合、「MCS Connect Initial and GCC Create」メッセージは平文に含まれ、後者の場合は、TLS通信の確立後最初に送信されるパケットが「MCS Connect Initial and GCC Create」メッセージになります。
  • 後者の場合、最初のリクエストとレスポンスの交換後、トラフィックはTLSを使用して暗号化されています。これを確かめる最も簡単な方法は、サーバに送信される2番目のパケットが「\x16\x03」で始まるかチェックすることです。「\x16\x03」は、ハンドシェイクにおける「Client Hello」とTLSのバージョンを表します。

検出デバイスにはRDPサーバとRDPクライアント間のRDP通信を解析する機能が必要です。RDP通信がTLSを使用している場合、検出デバイスはまずトラフィックを復号しなければなりません。

検出デバイスは、入力トラフィックから「MCS Connect Initial and GCC Create」リクエストを見つける必要があります。「MCS Connect Initial and GCC Create」の構造は図9の通りです。

「MCS Connect Initial and GCC Create」の構造

図9:「MCS Connect Initial and GCC Create」の構造(図2を再掲)

「tpktHeader」フィールドを除くすべてのマルチバイト整数のバイトオーダーはリトルエンディアンです。

  • X.224レイヤは一般に任意の長さから成るいくつかのProtocol Data Unit(PDU)タイプを持つことができますが、「MCS Connect Initial and GCC Create」パケットは3バイトのx224構造体を持ちます。
  • 「mcsCi」構造体は、「ASN.1 DER」でエンコードされた「T.125 MULTIPOINT-COMMUNICATION-SERVICE Connect-Initial PDU」です。この構造体の定義はこちらを参照してください。
  • 「gccCrq」構造体は「T.124 Generic Conference Control ConnectData」です。この構造体の定義はこちらを参照してください。

「Settings Data Blocks」は1つ以上の「Settings Data Block」を連結したものです。各「Settings Data Block」は図3のフォーマットに従います。

「Settings Data Block」の構造

図10:「Settings Data Block」の構造(図3を再掲)

Settings Data Block」には「CS_CORE(0xC001)」、「CS_SECURITY(0xC002)」、「CS_NET(0xC003)」のようなさまざまな種類が存在します。

「MCS Connect Initial and GCC Create」リクエストが見つかった場合、検出デバイスは各「Settings Data Block」を解析し、「CS_NET (0xC003)」を探します。このような「Settings Data Block」は「clientNetworkData」と呼ばれ、以下の構造を持っています。

「CS_NET(0xC003)」を含む「clientNetworkData」の構造

図11:「CS_NET(0xC003)」を含む「clientNetworkData」の構造

「clientNetworkData」が見つかると、検出デバイスは各「channelName_n(nは1,2,…,N)」を列挙し、文字列「MS_T120」(大文字小文字を区別)が含まれていないかチェックします。もしそのようなチャンネルが見つかった場合、このトラフィックは不正なものだと考えられます。つまり、CVE-2019-0708を利用した攻撃が進行中だということです。

■「CVE-2019-0708」を利用した攻撃に関するデバッグ情報

対象システムにデバッガをアタッチし、CVE-2019-0708を利用した攻撃を実行したところ、以下のバクチェックが発生しました。

「CVE-2019-0708」を利用する攻撃のデバッグ情報

図12:「CVE-2019-0708」を利用する攻撃のデバッグ情報

■結論

Microsoftは、サポート対象のOSに対してCVE-2019-0708の修正プログラムを公開した際、サポート対象外のWindows XPとWindows Server 2003に対しても修正プログラムを公開することを決定しました。これは、同社がこの脆弱性の深刻度を非常に高いものだと考えているということを示しています。実際の攻撃の検出に関して議論が続けられてきましたが、脆弱性が利用可能だということについては疑いの余地はありませんでした。CVE-2019-0708の深刻度は明らかに「緊急(Critical)」であり、影響を受けるシステムには直ちに修正プログラムを適用するべきです。

Microsoftが修正プログラムを提供した「termdd.sys」には、「IcaBindVirtualChannels()」および「IcaReBindVirtualChannels()」という2つの脆弱な関数があるということに留意してください。これらの2つの関数は、異なるものの類似した2つの攻撃経路となります。本記事は「IcaBindVirtualChannels()」を利用した攻撃経路に焦点を当てた解説です。

■被害に遭わないためには

Microsoftでは既にCVE-2019-0708の修正プログラムを公開済みです。また、既にサポート終了したWindows XPとWindows Server 2003にも修正プログラムが公開されています。2017年5月に発生した「WannaCry」の事例では「MS17-010」の脆弱性が利用されていましたが、実際にはその2か月前の3月には既に修正プログラムが公開されていました。同様の被害に遭わないためにも、速やかに修正プログラムを適用してくだい。運用上の理由などにより、速やかに修正プログラムが適用できない場合には、RDSの使用を制限する、脆弱性を利用する攻撃をブロックする仮想パッチなどの対策を導入する、などの緩和策を行ってください。

■トレンドマイクロの対策

総合サーバセキュリティ「Trend Micro™ Deep Security™ 」や 「Trend Micro Virtual Patch for Endpoint(旧 Trend Micro 脆弱性対策オプション)」では以下の DPIルールによってこの脆弱性を利用する攻撃を検出します。

  • 1009749 – Microsoft Windows Remote Desktop Services Remote Code Execution Vulnerability

ネットワーク脅威防御ソリューション「TippingPoint」では、以下のMainlineDV filterによりこの脆弱性を利用する攻撃を検出します。

  • 35296: RDP: Microsoft Remote Desktop Services Negotiation Request Without CredSSP

※調査協力:Trend Micro ResearchのRichard Chen、Pengsu Cheng、Kamlapati Choubey、Saran Neti

参考記事:

翻訳: 澤山 高士(Core Technology Marketing, TrendLabs)