** 本記事は、Remote Desktop Protocol: Executing the External RDP Query の翻訳です。最新の情報は英語記事をご覧ください。**
RDP Logins from External Ips.sql クエリの機能は、名前から容易に理解できます。本記事では、このクエリを使用して、外部 IP アドレス、つまり RFC 1918 以外の IP アドレスからの RDP 接続を調査します。今回のデモでは、クエリの作成と実行は Sophos Central サービスで行いますが、基本的な手順はどの調査ツールでも同じです。代わりに、以下にリンクする動画「外部 RDP クエリの実行」では、本記事で説明する手順ではなく、他の手順を示しています。
クエリの構築と実行
最初のステップは、クエリの作成です。Sophos Central では
[脅威解析センター] > [Live Discover] > [デザイナーモード]
から、図 1 に示すように [新しいクエリの作成] ボタンをクリックすることで行えます。
図 1: 新規クエリの作成ボタン
ボタンをクリックすると、SQL ボックスが表示されるので、そこに以下のクエリを貼り付けます (Github でもご利用いただけます)。
SELECT strftime('%Y-%m-%dT%H:%M:%SZ',datetime) AS date_time, eventid, CASE eventid WHEN 21 THEN eventid || ' - Session logon succeeded' WHEN 22 THEN eventid || ' - Shell start notification received' WHEN 25 THEN eventid || ' - Session reconnection successful' ELSE NULL END AS description, JSON_EXTRACT(data, '$.UserData.User') AS username, SUBSTR(JSON_EXTRACT(data, '$.UserData.User'), 1, INSTR(JSON_EXTRACT(data, '$.UserData.User'), '\') - 1) AS domain, JSON_EXTRACT(data, '$.UserData.Address') AS source_IP, JSON_EXTRACT(data, '$.UserData.SessionID') AS session_ID, CASE WHEN JSON_EXTRACT(data, '$.UserData.Address') GLOB '*[a-zA-Z]*' THEN 'private_IP' WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Address'), '192.168.') = 1 THEN 'private_IP' WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Address'), '172.') = 1 AND CAST(SUBSTR(JSON_EXTRACT(data, '$.UserData.Address'), 5, 2) AS INTEGER) BETWEEN 16 AND 31 THEN 'private_IP' WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Address'), '10.') = 1 THEN 'private_IP' WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Address'), '127.') = 1 THEN 'private_IP' WHEN JSON_EXTRACT(data, '$.UserData.Address') = '0.0.0.0' THEN 'private_IP' WHEN JSON_EXTRACT(data, '$.UserData.Address') LIKE '%::%' THEN 'unknown' WHEN JSON_EXTRACT(data, '$.UserData.Address') = '' THEN 'private_IP' ELSE 'external_IP' END AS status, 'TS LocalSession EVTX' AS data_source, 'Logins.01.4' AS query FROM sophos_windows_events WHERE source = 'Microsoft-Windows-TerminalServices-LocalSessionManager/Operational' AND eventid IN (21,22,25) AND (status = 'external_IP' OR status = 'unknown') UNION ALL SELECT strftime('%Y-%m-%dT%H:%M:%SZ',datetime) AS date_time, eventid, CASE eventid WHEN 1149 THEN eventid || ' - User authentication succeeded' ELSE NULL END AS description, JSON_EXTRACT(data, '$.UserData.Param1') AS username, JSON_EXTRACT(data, '$.UserData.Param2') AS domain, JSON_EXTRACT(data, '$.UserData.Param3') AS source_IP, NULL AS Session_ID, CASE WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Param3'), '192.168.') = 1 THEN 'private_IP' WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Param3'), '172.') = 1 AND CAST(SUBSTR(JSON_EXTRACT(data, '$.UserData.Param3'), 5, 2) AS INTEGER) BETWEEN 16 AND 31 THEN 'private_IP' WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Param3'), '10.')= 1 THEN 'private_IP' WHEN INSTR(JSON_EXTRACT(data, '$.UserData.Param3'), '127.')= 1 THEN 'private_IP' WHEN JSON_EXTRACT(data, '$.UserData.Param3') = '0.0.0.0' THEN 'private_IP' WHEN JSON_EXTRACT(data, '$.UserData.Param3') LIKE '%::%' THEN 'unknown' WHEN JSON_EXTRACT(data, '$.UserData.Param3') = '' THEN 'private_IP' ELSE 'external_IP' END AS status, 'TS RemoteConnection EVTX' AS data_source, 'Logins.01.4' AS query FROM sophos_windows_events WHERE source = 'Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational' AND eventid = 1149 AND (status = 'external_IP' OR status = 'unknown')
貼り付けたら、クエリを実行するマシンを選択します。このクエリは Windows に特化したもので、macOS や Linux のマシンに対して実行しても結果は出力されないため、まずは ([フィルター] > [オペレーティングシステム] から) これらの選択を解除してください。その他の設定は、各組織のニーズによって異なります。しかし、ネットワーク上のすべての Windows マシンに対して (万が一、誤ってインターネットに公開されている場合に備えてエンドポイントでも) クエリを実行するのは、強力な選択肢です。(残念なことに、ソフォスのインシデント対応調査員は、このような事例を頻繁に発見しています。)
[選択されたデバイスの更新] をクリックしてデバイスを確認し、右下の [クエリを実行] を選択して実行します。(未テストのクエリを実行するかどうか確認されるので、実行をクリックすると) クエリの実行が開始されます。結果が出力される速度は、クエリが実行されるデバイスの数やネットワーク接続に依存します。実行が終了すると、[Status] カラムがクエリの完了を知らせます (何か問題が発生した場合は、クエリの実行失敗を知らせます)。上にスクロールすると、クエリ結果というセクションがあり、結果が表示されます。何も表示されていなければ、外部 IP アドレスからの RDP ログインが見つからなかったことを意味します。しかし、何かが表示されている場合は、次のセクションをよくお読みください。
結果を理解する
クエリが結果を出力した場合、最初に注目すべきフィールドはエンドポイント名です。以下に示す例 (ビデオを作成するためにセットアップしたテストベッドからの抜粋) では、2 台のマシンで外部 RDP 接続があったことが報告されています。
図 2: テストベッドには 2 台のマシンがありますが、どちらも外部のマシンによって接続が試みられていました
結果を展開すると、接続が発生した日時、クエリによって返されたイベント ID (および、そのイベント ID の意味についての簡単な説明)、ログインしたアカウントのユーザー名、接続元の IP アドレスが表示されます。RFC 1918 以外のアドレスは、これらの接続がネットワークのプライベートアドレス空間由来のものではないことを証明しています。
この種の他のクエリと同様、誤検出を除外するにはさらなる調査が必要であることは注目に値します。しかし、「誤」検出、つまり管理者が一時的にサーバーの RDP を公開しただけの特殊な外部接続は、やはり調査する価値があります。本シリーズの前半の記事で述べたように、攻撃者は公開された RDP 接続に驚くほど速く飛びつきます。管理者が接続できたのであれば、多くの場合、攻撃者が開いているポートを見つける時間もあったと考えられます。用心するに越したことはありません。デバイスを隔離し、潜在的な侵害がないか調査することをお勧めします。
Remote Desktop Protocol:記事一覧
パート 1:イントロダクション ([本記事]、動画)
パート 2:公開されている RDP の危険性 (記事、動画)
パート 3:調査でのクエリ活用 (記事、動画)
パート 4:タイムゾーンバイアスの使い方 (記事、動画)
パート 5:外部 RDP クエリの実行 (記事、動画)
パート 6:4624_4625 ログインクエリの実行 (記事、動画)
GitHub のクエリリポジトリ: SophosRapidResponse/OSQuery
スクリプトのリポジトリ: sophoslabs/video-transcripts
Youtube のプレイリスト: Remote Desktop Protocol: The Series