Citrix NetScaler ADCおよびGatewayアプライアンスへの悪用攻撃に備える

はじめに

2026年9月下旬、Mandiant ConsultingとGoogle Threat Intelligence Group(GTIG)は、Citrix NetScaler ADCおよびNetScaler Gatewayアプライアンスに影響を及ぼすゼロデイ脆弱性(CVE-2026-88772)が、実環境で悪用されていることを確認しました。少なくとも9月上旬から続くこの攻撃キャンペーンでは、北米と欧州の政府機関、金融サービス、教育、法務・プロフェッショナルサービスの各分野の組織が被害を受けたとみられる証拠を観測しています。ベンダーの発表によると、攻撃者は2つ目のゼロデイ脆弱性(CVE-2026-88771)も積極的に悪用しています。 

CVE-2026-88772を悪用すると、認証を回避し、NetScalerパケット処理エンジン(NSPPE)を異常終了させて、ルート権限による初期アクセスを確立できます。攻撃者が侵入後に使うツール群を分析したところ、新たに発見されたカスタムPHP Webシェルが見つかりました。その一つであるWHIPSHOTは、Base64エンコードしたコマンド&コントロール(C&C)のペイロードを、標準的なHTTPヘッダーの中に偽装して送り込めます。ツール群には、新種のPython製トンネラーSLAPSHOTも含まれます。SLAPSHOTは通信を内部ネットワークへ中継し、偵察や認証情報の窃取に利用できます。少なくとも1件の侵入では、攻撃者がこのプロキシ経由で通信し、内部偵察と認証情報の窃取を手作業で進めていました。

Citrixは、新たに修正された脆弱性に関するガイダンスをお客様向けに公表し、アップデートを推奨しています。詳細はこちらをご覧ください。防御担当者はCitrixのドキュメントを確認し、これらの脆弱性へのパッチ適用を優先してください。本ブログでは、Mandiantによる封じ込めと復旧のガイダンスも示します。

キャンペーンの概要

初期アクセス

NSPPEは、認証前の暗号ハンドシェイクの初期段階で、受信したDTLSレコード構造を解析します。Google Threat Intelligence Groupはエクスプロイトコードを入手していませんが、最前線のテレメトリーを分析した結果、次のことが示唆されています。特別に細工した、あるいは断片化したレコードヘッダーを送信すると、パケットエンジン内でヒープメモリの境界が破壊されます。その結果、制御フローが乗っ取られ、基盤となるFreeBSD上で、ルート権限の任意のシェルコードが実行されます。

攻撃に成功すると、次の2種類のログが残りました。

0-PPE-0 : default SSLLOG SSL_HANDSHAKE_FAILURE 0 : SPCBId - ClientIP - ClientPort - VserverServiceIP - VserverServicePort 443 - ClientVersion DTLSv1.0 - CipherSuite "TLS1-AES-256-CBC-SHA" - Session New - Reason "Handshake failure-Internal Error"

図1:Syslogに記録されたSSLハンドシェイク失敗

qat0: Process <PID> NSPPE-<##> exit with orphan rings 5:500
pitboss[<##>]: pitboss <DATETIME> NOT restarting NSPPE-<##> (<PID>)

図2:FreeBSDカーネルとアプライアンスの監視デーモン(pitboss)が記録したNSPPEプロセスの終了(/var/log/messages)

足がかりの確立と永続化

攻撃が成功すると、最初のWebシェルのペイロードが、対象のhttpd.confファイルを書き換えて自らをインストールします。この設定変更により、スクリプトではない特定のファイルタイプがPHPスクリプトとして実行されるようになります。これが、WHIPSHOT(PHP Webシェル)やSLAPSHOT(Pythonプロキシ/トンネラー)など、追加のカスタムマルウェアを展開する下地になります。 

Webサーバーの永続化手法A:パッケージハンドラーへの偽装(.deb)

あるケースでは、最初のインストーラーが/etc/httpd.confを書き換え、Webサーバーが.debファイルをPHPスクリプトとして処理するように設定していました。

php_flag engine on
  <FilesMatch "\.deb$">
    Header set Cache-Control "no-cache"
  </FilesMatch>
AddHandler application/x-httpd-php .deb

図3:パッケージハンドラーへの偽装による永続化

この設定変更によって、攻撃者は/netscaler/gui/vpn/scripts/linuxに、拡張子を偽装したWebシェルを配置できるようになりました。

Webサーバーの永続化手法B:アイコンのエイリアス化と署名ファイルハンドラー(.sig)

別の侵入では、攻撃者がより巧妙な設定フックを仕込み、Webシェルの実行を画像リクエストに見せかけていました。

php_flag engine on#
AliasMatch ^/vpn/media/(.+).ico$ /var/netscaler/gui/vpn/scripts/linux/$1.sig
AddHandler application/x-httpd-php .sig

図4:アイコンのエイリアス化と署名ファイルハンドラーによる永続化

この設定ディレクティブは、次の3つの処理を行います。

  1. mod_phpエンジンを有効にする。

  2. .sigファイルを実行可能なPHPスクリプトとして登録する。

  3. /vpn/media/配下で.icoで終わるHTTPリクエストを、/var/netscaler/gui/vpn/scripts/linux/内にある、同じベース名の.sigファイルへ直接マッピングする。

たとえば、クライアントが/vpn/media/e6ee7c85.icoにアクセスすると、配置されたPHP Webシェルe6ee7c85.sigが応答します。少なくとも1件では、Webサーバーのアクセスログに、HTTP 404を返しているにもかかわらず、処理時間が長く、応答サイズが数キロバイトに及ぶGETリクエストが記録されていました。その後の数日間には、攻撃者が存在しない.sigファイルへアクセスを試み、httperror-vpnログに「ファイルなし」のエラーが記録されました。これは、ファイルがそこにないことを示唆しています。攻撃者が、複数の侵害先環境で同様のWebシェルを管理している可能性があります。

ルート権限の永続化

CVE-2026-88772の最初の悪用はルート権限で実行されますが、その後にWebサーバー(httpd)が処理するリクエストは、権限のないWebサービスのコンテキストで動作します。攻撃者は、Webシェルをルート権限で永続的に実行させるため、軽量なインストーラーWebシェルを使って、/bin/sh実行ファイルにsetuid(Set User ID)ビットを設定しました。:

chmod u+s /bin/sh

図5:ユーザーIDを設定するコマンド

/bin/shのパーミッションを変更することで、攻撃者は、Webサーバーが以降のWebリクエストを昇格した権限で実行するようにしました。インストーラーは、/etc/httpd.confの変更とSUIDシェルの変更を反映させるため、NetScalerアプライアンス全体の再起動(/netscaler/nsshutdown -R)を実行しました。 

Webシェルの別の亜種では、攻撃者がWebサービスを直接再起動するコマンドを実行し、あわせて/bin/sh実行ファイルにルートのsetuid(Set User ID)権限を割り当てていました。

system('/bin/httpd -k restart -f /etc/httpd.conf && chmod u+s /bin/sh');

図6:Webサービスを再起動するコマンド

マルウェア分析

攻撃者は、複数のPHP Webシェルとトンネラーマルウェアを展開し、被害組織のネットワークへ通信を中継していました。これにより、内部偵察、横展開、認証情報の収集を進めていました。

インストーラーとスタンドアロンのWebシェル

Mandiantは、.debや.sigの拡張子を持つファイルに配置された、軽量なPHP Webシェルを複数回収しました。これらのWebシェルは、コマンドの直接実行と、アプライアンスへの自動的な永続化を可能にします。直接観測した侵入では、Webシェルのファイル名は被害先ごとに異なっていました。「nginstaller」の変形に数字を付けたファイル名を使う、軽量Webシェルの例を複数確認しています。 

  • ある例は、コマンドラインインターフェース(CLI)から実行すると、/etc/httpd.confを変更し、/bin/shにsetuid root権限を付与(chmod u+s /bin/sh)します。さらに、/etc/crontabから/vpn/scripts/linuxへの参照を消去し、/netscaler/nsshutdown -Rでアプライアンスを再起動します。HTTP経由では、HTTP_NSC_LDAPヘッダーからBase64エンコードされたコマンドを取り出し、shell_exec()で実行して、Base64エンコードした出力を返します。

  • 別の亜種は、偽装したHTTP404 Not Foundレスポンスコードを返します。設定変更を反映させるためApacheデーモンを再起動(/bin/httpd -k restart -f /etc/httpd.conf)し、受信したペイロードをeval()で実行します。検知を逃れるため、正規表現(#^.*/vpn/scripts/linux.*\n#m)を使って、システムの`/etc/crontab`から自身のインストールパスを系統的に消去します。このWebシェルは、HTTPのHTTP_NSC_LDAPヘッダーで受け取ったBase64エンコード済みペイロードを、`eval()`でそのままPHPとして実行します。

  • e6ee7c85.sig:こちらの亜種もHTTP 404 Not Foundレスポンスを強制します。ただし、Base64エンコード済みペイロードはHTTP_NSC_CLIENTTYPEリクエストヘッダーから取り出し、同様にeval()で実行します。

WHIPSHOT

WHIPSHOTは、Debianパッケージに偽装して/netscaler/ns_gui/vpn/scripts/linux/に配置されるPHP Webシェルです。SLAPSHOTプロキシデーモンのためのHTTPトランスポートブリッジとして機能します。

主な機能と挙動は次のとおりです。

  • HTTPチャンク転送:受信したHTTPリクエストヘッダーから、連番のパラメーターブロック(HTTP_X_UX_0からHTTP_X_UX_95、またはHTTP_X_UX)を調べます。これらのヘッダー値を連結し、得られたストリームをBase64デコードして、ループバック経由でSLAPSHOTプロキシに転送します。

  • プロセス管理と起動:接続を確立する前に、WHIPSHOTは/tmp/.uxdportと/tmp/.uxdlockの有無を確認します。プロキシが動作していなければ、SLAPSHOTを含む埋め込み済みのBase64ペイロードを取り出し、次のコマンドでバックグラウンド起動します。

nohup <python> -c 'import base64;exec(base64.b64decode("<payload>"))' /tmp/.uxdport /tmp/.uxdlock > /dev/null 2>&1 </dev/null &

図7:SLAPSHOTをバックグラウンドで実行するコマンド

  • ループバックIPC:SLAPSHOTが動作すると、WHIPSHOTは/tmp/.uxdportに記録された動的TCPポートを読み取り、127.0.0.1:<port>へソケット接続を確立して、クライアントのリクエストを中継します。

  • 検知回避:WHIPSHOTは標準のエラー報告(error_reporting(0))を抑止し、HTTPの404 Not Foundレスポンスヘッダーを設定したうえで、トンネリングしたTCPレスポンスをHTTPボディに載せて返します。

SLAPSHOT

SLAPSHOTは、Pythonで書かれたTCPトンネリングツールです。内部ネットワークへのブリッジとして機能し、WHIPSHOTからコマンドを受け取って、任意のTCPストリームを内部ホストに転送します。

主な機能と挙動は次のとおりです。

  • 動的ポートのバインドとロック:起動すると、SLAPSHOTは127.0.0.1のエフェメラルポートにバインドし、使用中のポート番号を/tmp/.uxdportなどの指定ファイルに書き込みます。さらにfcntl.flockを使い、/tmp/.uxdlockなどのロックファイルに排他ロックをかけます。これにより、同時に動作するインスタンスは1つだけになります。

  • 独自のワイヤープロトコル:プロキシとの通信には独自のバイナリプロトコルを使います。各メッセージは、4バイトのビッグエンディアン長プレフィックスとJSONペイロードで構成されます。対応するコマンドアクションは次のとおりです。

  • open:対象のホストとポートへ、外向きのTCPソケットを確立します。

  • push:開いているセッションへデータを書き込みます。

  • pull:開いているセッションのソケットをポーリングし、データを読み取ります。

  • exch:開いているセッションのソケットとの間で、C&Cデータを送受信します。

  • close:指定したネットワークセッションを終了します。

  • ping:基本的なヘルスチェックを行います。

  • アイドルタイムアウト:デーモンは接続の動作を監視し、15分間通信がないセッションソケットを自動的に閉じます。10分間(UXD_IDLE_EXIT変数で変更可能)アクティブなセッションもコマンドも受信しなければ、SLAPSHOTはポートファイルとロックファイルを削除してプロセスを終了します。これにより、メモリ使用量と検知されるリスクを抑えます。

  • 影響と今後の見通し

    今回のキャンペーンは、攻撃者が被害ネットワークへの初期アクセスを得るために、エッジデバイスを狙い続けていることを改めて示しています。GTIGは、さまざまな攻撃者にわたってこの傾向を追跡してきました。特に、これらの脆弱性は2025年のエンタープライズ関連ゼロデイの約半数を占めました。アプリケーションデリバリーコントローラー、VPNゲートウェイ、ファイアウォールなどのアプライアンスは、インターネットに公開され、エンドポイント検知・対応(EDR)ツールの監視も及びません。しかも、ネットワークの奥深くへ侵入するために使える認証情報を保存・処理していることが多く、攻撃者にとって魅力的な標的であり続けています。この手口の有効性は実証済みであり、攻撃者は今後もエッジデバイスの脆弱性を悪用し続けるとみられます。 

    ハンティング、封じ込め、復旧のガイダンス

    組織はまず、既存のログと設定ファイルを分析し、侵害の兆候がないかを確認してください。

    ハンティング戦略 

    Citrix NetScaler ADCアプライアンス

    1. Webサーバー設定の確認:すべてのNetScaler ADCアプライアンスで/etc/httpd.confを調べ、不正なMIMEタイプ、スクリプトハンドラーのディレクティブ、Webパスのエイリアス設定がないかを確認します。AddHandlerやAddTypeで、PHP以外のファイル拡張子(.deb、.sig、.html、.rpm、.tgzなど)をPHPスクリプトとして実行するよう登録している場合は、侵害の兆候です。公開Webパス(/vpn/media/、/vpn/theme/、/vpn/images/)をアプライアンスのスクリプトディレクトリへ振り向けるAliasMatchも同様です。

    grep -En -i "application/x-httpd-php|php_flag|AliasMatch" /etc/httpd.conf
    

    図8:Webパスのエイリアス設定

    2. アプライアンスのステージング用ディレクトリとクライアントプラグイン用ディレクトリの監査:ネイティブのクライアントプラグインのパス(/var/netscaler/gui/vpn/scripts/linux/、/var/netscaler/gui/vpns/scripts/vista/、/var/netscaler/gui/vpns/scripts/mac/)とWebアセットのパス(/netscaler/ns_gui/vpn/media/、/var/vpn/theme/)の内容を監査します。これらのディレクトリにある正規のクライアント配布物は、コンパイル済みのバイナリかアーカイブです。ASCIIテキストと判定されるファイルや、PHPスクリプトのマーカーを含むファイルは異常です。デフォルトのインストールでは、これらのディレクトリには正規のコンパイル済みクライアントバイナリと静的Webアセットしかありません。スクリプト以外の拡張子に偽装したプレーンテキストのスクリプトや、PHPコードを含むファイルがないかを調べてください。

    file /var/netscaler/gui/vpn/scripts/linux/* /var/netscaler/gui/vpns/scripts/vista/* /var/netscaler/gui/vpns/scripts/mac/* /netscaler/ns_gui/vpn/media/* 2>/dev/null | grep -E "ASCII text|PHP script"
    grep -rlE "<\?php|eval\(|base64_decode\(|shell_exec\(" /var/netscaler/gui/ /netscaler/ns_gui/ /var/vpn/ /netscaler/portal/ 2>/dev/null
    

    図9:クライアントプラグインのパスに、スクリプト以外の拡張子に偽装したスクリプトや、PHPコードを含むファイルがないかを調べる

    3. Webサーバーのアクセスログとエラーログの確認:/var/log/httperror*で、偽装された拡張子や標準外の拡張子に関する構文エラー、パースエラー、実行エラーを確認します。これらのエラーは、アクセスログが消去されていても残ります。/var/log/httpaccess.logでは、静的メディア、アイコン、スクリプトのパスを狙ったリクエストのうち、偽装されたHTTP 404ステータスを返しているものや、想定外に大きなレスポンスペイロードを返しているものを監査します。また、/vpn/scripts/や/vpn/media/の前後で、アクセスログに時系列の急な欠落や途中で切れた行がないかを調べてください。攻撃者が正規表現ベースのログ消去ツールを実行した痕跡の可能性があります。

    grep -E -i "\.(deb|sig|rpm|tgz|sh|so|dat|ico|png|html)" /var/log/httperror*

    図10:標準外のファイル拡張子と実行エラーを検索する

    grep -E "/vpn/media/|/vpn/scripts/|/vpn/theme/" /var/log/httpaccess.log* | awk '$9 ~ /200|404/ && $10 > 5000'

    図11:想定外に大きなレスポンスペイロードを検索する

    4. 一時的なIPCアーティファクトの確認:アプライアンスの/tmp/ディレクトリを調べ、SLAPSHOTが作成したロックファイルとポートポインターファイルがないかを確認します。/tmp/.uxdportまたは/tmp/.uxdlockが存在する場合は、SLAPSHOTプロキシデーモンが現在動作中か、最近動作していたことを示します。対応担当者は、.uxdportに記録されているポートを控え、sockstat -4 -lで待ち受けているプロセスを調べてください。

    ls -la /tmp/.uxdport* /tmp/.uxdlock

    図12:SLAPSHOTが作成したファイルを検索する

    5. シェルとバイナリのパーミッションの確認:/bin/shを調べ、不正なSUID権限が設定されていないかを確認します。パーミッションが所有者rootの-rwsr-xr-xになっていれば、永続的なsetuid権限昇格のためにバイナリが改変されています。

    ls -l /bin/sh

    図13:不正なSUID権限を確認する

    6. プロセス実行とシェル履歴の調査:稼働中のシステムプロセスを調べ、/tmp/.uxdportを参照する、またはnohupで動作している、異常なPythonインタープリターがバックグラウンドでコマンドを実行していないかを確認します。/var/log/sh.logでは、変更ウィンドウ外に実行された管理コマンドを確認します。強制再起動(/netscaler/nsshutdown -R)や、Apacheの手動再起動(httpd -k restart)が対象です。

    ps aux | grep -E "python.*(\.uxd|uxdport|uxdlock|base64)"

    図14:システムプロセスに異常なPythonインタープリターがないか調べる

    封じ込めと復旧の戦略 

    最新のセキュリティアップデートをまだ適用していない組織は、ただちに自社の露出状況とリスクを評価してください。NetScaler Gatewayを広くインターネットから隔離したり、IPアドレスを厳格に許可リスト化したりすると、Citrix Virtual Apps and Desktops(旧XenAppおよびXenDesktop)でリモートワーカーを支えている組織では、大きな業務の混乱を招きかねません。このためMandiantは、パッチ適用を最優先としつつ、組織のリスクプロファイルに応じて適切な封じ込めと代替コントロールを組み合わせる、段階的で的を絞ったアプローチを推奨します。

    即時の緩和策

    組織は、自社のリスク許容度、侵害の証拠、運用上の要件に基づいて、次の選択肢を検討してください。

    選択肢1:最新のCitrixビルドを適用する(Mandiant推奨)

    対象の脆弱性を修正した最新のCitrixビルドを適用してください。現在の運用トラックに応じて、次の修正済みリリース(またはそれ以降)へアップグレードします。

    • NetScaler 14.1トラック:バージョン14.1-73.37以降のリリースにアップグレードします。

    • NetScaler 13.1トラック:バージョン13.1-64.23以降の13.1リリースにアップグレードします。

    注:14.1-FIPSおよび13.1-FIPS/NDcPPの環境向けにも、専用のパッチ適用済みビルドが提供されています。

    Citrixカスタマーダウンロードポータルで該当ビルドが見つからない組織は、Citrixに重大度1のサポートケースを起票し、必要な修正を含む最新ビルドを確認して入手してください。

    選択肢2:侵害された、または侵害が疑われるアプライアンスを隔離する

    侵害が確認された、または疑われる場合は、影響を受けたNetScalerアプライアンスをネットワークから隔離してください。この選択肢は、特にアプライアンスがリモートアクセスなどの重要なサービスを提供している場合、業務に大きな支障をきたすおそれがあります。

    上述のハンティング戦略で侵害の痕跡(IoC)が見つかった場合、Mandiantは次の封じ込め措置の実施を推奨します。

    • ノードを隔離する。侵害が確認された、または疑われるアプライアンスを、ただちにネットワークから切り離します。

    • HA同期を停止する。高可用性(HA)ペアで運用しているNetScalerでは、両ノードを個別に評価します。両ノードの検証が済むまで、構成同期を無効にします。侵害されたノードが、改変されたhttpd.confファイルなどの不正な変更をスタンバイノードに複製するのを防ぐためです。

    • 外向き通信を制限する。確認された攻撃者のインフラをブロックし、アプライアンスからのインターネット向け送信接続を制限します。特に、任意のTCP/UDPの外向き通信を禁止し、明確な必要がない限りTCP/25経由の外向きSMTPをブロックしてください。

    •  ハイパーバイザーのネットワーク分離を確認する。NetScalerを仮想化環境でVPXアプライアンスとして運用している場合は、vSphereのvSwitchとポートグループの設定を確認します。NetScaler VPXが適切にセグメント化されているかを確かめ、ESXiのvmk0やvCenterなどのハイパーバイザー管理インターフェースや、機密性の高い他のインフラ階層と、レイヤー2ネットワークを共有していないことを確認してください。追加の推奨事項については、vSphere向けのMandiantハードニングガイダンスを参照してください。

    選択肢3:的を絞った代替コントロールを適用する

    すぐにパッチを適用できない場合は、影響を受けるアプライアンスを更新できるまで、的を絞ったコントロールを実施して、露出している攻撃対象領域を減らしてください。以下のDTLSとUDP/443に関するコントロールは、CVE-2026-88772に固有のものです。CVE-2026-88771の緩和策としては当てにしないでください。両方の脆弱性に対処するには、修正済みのNetScalerビルドのインストールが引き続き必要です。

    パートA:ネットワーク制限

    • 運用上可能であれば、DTLSを無効にする。パッチ適用が遅れる場合は、インターネットに公開しているNetScaler Gatewayの仮想サーバーで、不要なDTLSを無効にします。今回のキャンペーンでは、エクスプロイトのペイロードがData gram Transport Layer Security(DTLS)を使い、UDP/443で送り込まれます。

    • 上流でインバウンドのUDP/443を制限する。DTLSが明確に必要でない限り、影響を受けるアプライアンス宛てのインバウンドUDP/443をブロックします。このコントロールは、上流の境界ファイアウォールかエッジルーターに実装してください。NetScaler上のローカルACLだけに頼ると、トラフィックが破棄される前に、脆弱なパケット処理エンジン(nsppe)へ到達してしまいます。

    • 可能であれば、上流でIPアドレスの許可リストを実装する。NetScalerをロードバランシング専用で使っている組織や、接続元の外部IPアドレスが予測可能なAccess Gatewayを運用している組織は、不正な通信をアプライアンスに届く前に破棄する、上流のネットワークACLを検討してください。

    大規模なリモートワーカーを支える公開VPNでは、動的な家庭用IPアドレスが管理・運用の大きな負担になるため、この方法は現実的でない場合があります。 

    • フォレンジック分析のために仮想アプライアンスの状態を保全する。NetScalerをVMware vSphereなどのハイパーバイザー上の仮想アプライアンス(NetScaler VPXを含む)として運用している場合は、可能な限り、再起動する前にメモリ状態を含む完全なVMスナップショットを取得してください。

    パートB:認証情報のローテーションとセッションの終了

    組織は、侵害されたアプライアンスに保存されていた認証情報が漏えいした可能性があるという前提で対応してください。認証情報のローテーションとセッションの終了は、アプライアンスと接続先のシステム全体で連携して進める必要があります。

    • アクティブなセッションを失効させる。既存の管理者、Gateway、VPNのセッションを無効化し、侵害された可能性のあるセッショントークンを排除します。アプライアンスをCitrix Virtual Apps and Desktopsのゲートウェイとして使っている組織は、必要に応じて、アクティブなICA/HDXセッションの終了も含めてください。追加のガイダンスについては、Citrix CTX584227を参照してください。

    • アプライアンスのシークレットをローテーションする。NetScalerの管理者認証情報、ローカルのアプライアンスアカウント、Secure Shell(SSH)キー、TLS証明書、関連する秘密鍵をローテーションします。

    • 連携先の認証情報をローテーションする。LDAPバインドアカウントとサービスアカウント、RADIUS共有シークレット、TACACS認証情報、SNMPコミュニティ文字列、NITRO/アプリケーションプログラミングインターフェース(API)の認証情報をローテーションします。

    • 下流のCitrixインフラを監査する。NetScalerが直接通信するシステムを確認します。特に、Citrix StoreFrontサーバー、Citrix Delivery Controller(DDC)、社内のCitrix Virtual Apps and Desktopsホストが対象です。Windowsイベントログを調べ、異常な対話型ログオン、想定外のリモートデスクトッププロトコル(RDP)の動作、認証情報ダンプの兆候、その他の横展開の証拠がないかを確認してください。

    侵害されたアプライアンスに保存されているTLS証明書と関連する秘密鍵についても、失効とローテーションを検討してください。

    注:認証情報のローテーションは、アプライアンスへのパッチ適用が完了した後に実施してください。

    パートC:コントロールプレーンの制限

    NetScalerのコントロールプレーンと管理プレーンには、追加の制限を適用してください。

    • インターネットに公開するサービスは、必要なポートとプロトコルだけに限定する。

    • NetScalerアプライアンスには、デフォルト拒否のアウトバウンドファイアウォールルールを実装する。

    • 外向き通信は、明示的に承認された宛先とサービスだけに許可する。対象は、DNS、NTP、必要なOCSP/CRLサービス、承認済みのバックエンドアプリケーション、承認済みの管理・セキュリティインフラなど。

    • 文書化された業務上の必要性がない限り、TCP/25経由の外向きSMTPを明示的にブロックする。

    • NSIPと管理インターフェースをインターネットに公開しない。

    • SSH、HTTPS管理、NITRO/APIへのアクセスは、専用の管理ネットワーク、承認済みの踏み台ホスト、明示的に承認された接続元IPレンジに限定する。

    パートD:ログ収集と検知エンジニアリング

    検知は、対応戦略の重要な要素です。Mandiantは、2つの領域から検知に取り組むことを推奨します。1つは必要なテレメトリーを確実に取得すること、もう1つはネットワーク、アプライアンス、ファイルシステム、ID(認証)の各アクティビティを相関させる検知を実装することです。

    ログ収集と可視性

    以下の検知の多くは、NetScalerがデフォルトでは転送しないログに依存します。検知ロジックを実装する前に、SIEMが次のテレメトリーを受信していることを確認してください。

    • syslogアクション経由のNetScaler監査ログ(ns.log)。SSL関連のイベントを含みます。

    • アプライアンスのFreeBSDシステムログ(/var/log/messages)。NSPPEの終了/クラッシュとpitbossのメッセージが記録されますが、標準のns.log転送には含まれません。

    • Webサーバーログ(/var/log/httpaccess.logと/var/log/httperror*)、NetScaler Webロギング、またはAppFlowテレメトリー。TLSはアプライアンス上で終端されるため、上流のネットワーク機器では通常、HTTPのリクエストパスやヘッダーを検査できません。

    • NetScalerのNSIPおよびSNIPアドレスが発信元となるトラフィックの、ファイアウォールログまたはネットワークフローログ。

    • Secret Serverなどの特権アクセス管理(PAM)の監査ログ。

    検知エンジニアリング

    プロトコルとトラフィックの分析

    • エクスプロイトパターンに合致するDTLS失敗をアラート化する。ClientVersionがDTLSv1.0で、理由がHandshake failure-Internal ErrorのSSL_HANDSHAKE_FAILUREイベントを探します。今回の活動で確認された攻撃成功時には、このイベントが発生しました。個々の発生を確認し、同じアプライアンスから発生したクラスターを優先してください。

    • DTLS失敗とエンジンの終了/クラッシュを相関させる。同じアプライアンスで、DTLSハンドシェイク失敗の数分以内にNSPPEの終了/クラッシュが続く場合は、悪用を示す強いシグナルです。優先度を高くして調査してください。

    • 想定外のインバウンドUDP/443を確認する。DTLSが無効、または想定されていないアプライアンスに注目します。各Gatewayとの間で通常DTLS接続を確立する接続元をベースライン化してください。攻撃に必要なトラフィックはごくわずかな場合があり、量に基づく異常検知だけでは、この活動を特定できない可能性があります。

    アプライアンスのプロセスとメモリの安定性

    • NSPPEの終了/クラッシュを監視する。NSPPEプロセスの終了、またはシグナルによる強制終了を示すカーネルメッセージには、重大度の高いアラートを生成します。/var/core/配下に新しいNSPPEコアファイルが作成されていないかも監視してください。

    • pitbossがNSPPEを再起動しなかった場合にアラートを出す。pitboss NOT restarting NSPPEを含むpitbossのメッセージを監視します。これらのメッセージとNSPPEのカーネル終了/クラッシュイベントは、両方の条件が揃うのを待たず、それぞれ独立してアラート化してください。

    • 可用性イベントと相関させる。インターネットに公開しているGatewayで、同じ時間帯に予期しないHAフェイルオーバーやアプライアンスの再起動が起きた場合は、悪用の可能性を裏付ける証拠として扱ってください。

    ファイルシステムと設定の完全性

    • 重要なVPNスクリプトのパスを監視する。次のようなVPN関連ディレクトリで、nsgclient.sigなどの.sigファイルの作成、変更、配置を検知します。

    • /var/netscaler/gui/vpn/scripts/linux/

    • /netscaler/ns_gui/vpn/scripts/linux/

    • /var/netscaler/gui/vpns/scripts/vista/

    • /var/netscaler/gui/vpns/scripts/mac/

    • /netscaler/ns_gui/vpn/media/

    • /var/vpn/theme/

  • 不正なWebサーバー設定の変更を検知する。/etc/httpd.conf、/nsconfig/httpd.conf、/flash/nsconfig/httpd.confへの不正な変更を監視します。特に、次の点でアラートを出してください。

    • AddHandler application/x-httpd-php .[ext]ディレクティブの追加または変更。

    • php_flag engine onの設定、またはPHPの実行を有効にするその他の変更。攻撃者の活動には、.php以外の拡張子を使うPHPベースのWebシェルが含まれており、具体的な拡張子は環境によって異なる可能性があります。/vpn/media/、/vpn/theme/、/vpn/images/などのWebアセットパスを、スクリプトディレクトリや実行可能ファイルにマッピングするAlias、AliasMatch、RewriteRuleのディレクティブ。

  • 実行時の状態を定期的に確認する。次の項目を監視します。

  • /bin/shにSUIDビットが設定されていないか

  • /tmp/.uxdportまたは/tmp/.uxdlockが存在しないか

  • nohup経由で起動された、またはBase64エンコード済みペイロードを含むPythonプロセスがないか

  • /nsconfig/配下の永続的な設定ファイルや起動ファイルに、予期しない変更がないか

  • 外向き通信とやり取りの監視

    • 静的パスやクライアントスクリプトのパスに対する、不審なWebシェルのやり取りを検知する。正規のクライアントは/vpn/media/のリソースに日常的にアクセスするため、リクエストされたパスだけでなく、挙動に注目してください。指標になりうるものは次のとおりです。

    • /vpn/media/*.icoまたは/vpn/scripts/のパスに対する404レスポンスのうち、数KBのレスポンスボディを返すもの、または処理時間が異常に長いもの。

    • /vpn/scripts/配下の.sigファイルやその他の標準外ファイルに関する、HTTPエラーログの「File does not exist」エントリ。アクセスログが改変または消去されていても、これらのイベントは残っている場合があります。

    • /vpn/scripts/や/vpn/media/へのリクエストの前後における、httpaccess.logの欠落、不正な形式のエントリ、途中で切れた行。

  • アプライアンスからの異常な外向き通信を特定する。NetScalerアプライアンスから直接発信される送信接続を監視し、宛先が組織の承認済みの外向き許可リストにない場合はアラートを出します。優先すべきは、認証情報の保管庫やPAMシステムに関わる活動、想定外のポートによるドメインコントローラーへの接続、短時間での多数の内部システムへの接続、TCP/25経由の外向きSMTPです。

  • 侵害指標(IOC)

    ネットワークとトランスポートの指標

    種類

    説明

    指標

    インバウンドのネットワークトラフィック

    ゼロデイエクスプロイトの送り込みに使われた配信プロトコル 

    UDP :443 (DTLSv1.0)

    HTTPリクエストヘッダー

    nsginstaller.debが使うインバウンドのコマンド実行ヘッダー

    HTTP_NSC_LDAP

    HTTPリクエストヘッダー

    nsgclient.sigが使うインバウンドのコマンド実行ヘッダー

    HTTP_NSC_CLIENTTYPE

    HTTPリクエストヘッダー

    WHIPSHOTが使うチャンク化Base64トランスポートヘッダー

    HTTP_X_UX / HTTP_X_UX_[0-9]+

    URIパス

    AliasMatch経由で.sig Webシェルに振り向けられる、アイコンのリクエストに偽装したURI

    /vpn/media/nsgclient.ico / /vpn/media/*.ico

    URIパス

    NetScaler Gateway上で、悪意あるPHP Webシェルを配置するパス

    /vpn/scripts/linux/nsginstaller*.deb/vpn/scripts/linux/nsgclient*.deb/vpn/scripts/linux/*.php

    IPv4アドレス

    スキャンおよびステージング用インフラ 

    143.198.7.94

    IPv4アドレス

    NetScalerの悪用と、基本的なWebシェルバックドアのインストール

    157.254.167.12

    本ブログで説明した活動のハンティングと特定を、より広いコミュニティが行いやすくするため、登録ユーザー向けのGTIコレクションに侵害指標(IOC)を掲載しています。

    ファイルの指標

    ファイルパス

    /tmp/.uxdport

    SLAPSHOTのアクティブポートのアーティファクト

    ファイルパス

    /tmp/.uxdlock

    SLAPSHOTのプロセスロックのアーティファクト

    検知

    YARAルール

    rule G_APT_Backdoorwebshell_WHIPSHOT_1
    {
        meta:
            description = "Detects WHIPSHOT PHP webshell tunneling frontend deployed on Citrix NetScaler ADC appliances"
            author = "GTIG"
            family = "WHIPSHOT"
        strings:
            // Chunked transport headers
            $sh1 = "HTTP_X_UX" ascii
            $sh2 = "HTTP_X_UX_" ascii
            // IPC lock and port pointers to local proxy daemon
            $si1 = "/.uxdport" ascii
            $si2 = "/.uxdlock" ascii
            $si3 = "/tmp/.uxdport /tmp/.uxdlock" ascii
            // Socket forwarding logic
            $sf1 = "fsockopen" ascii
            $sf2 = "127.0.0.1" ascii
        condition:
            filesize < 50KB and (
                ($sh1 or $sh2) and ($si1 or $si2 or $si3) and ($sf1 or $sf2)
            )
    }
    
    rule G_APT_Tunneler_SLAPSHOT_1
    {
        meta:
            description = "Detects SLAPSHOT Python proxy daemon and tunneling tool deployed alongside WHIPSHOT on compromised NetScaler appliances"
            author = "GTIG"
            family = "SLAPSHOT"
       strings:
            // Lock and port files
            $ss1 = "/tmp/.uxdport" ascii fullword
            $ss2 = "/tmp/.uxdlock" ascii fullword
            $ss3 = "UXD_IDLE_EXIT" ascii fullword
            $ss4 = "127.0.0.1" ascii
            // Wire protocol command verbs
            $sc1 = "\"open\"" ascii fullword
            $sc2 = "\"conn\"" ascii fullword
            $sc3 = "\"push\"" ascii fullword
            $sc4 = "\"pull\"" ascii fullword
            $sc5 = "\"exch\"" ascii fullword
            $sc6 = "\"close\"" ascii fullword
            $sc7 = "\"ping\"" ascii fullword
            // Protocol parameter names
            $sp1 = "\"sid\"" ascii fullword
            $sp2 = "\"host\"" ascii fullword
            $sp3 = "\"port\"" ascii fullword
            $sp4 = "\"data\"" ascii fullword
        condition:
            filesize < 30KB and (
                ($ss1 and $ss2 and $ss3) or
                ($ss4 and ($ss1 or $ss2) and 3 of ($sc*) and 2 of ($sp*)) or
                ($ss3 and 3 of ($sc*) and 2 of ($sp*))
            )
    }
    
    rule G_Hunting_Config_NetScaler_PHP_1
    {
        meta:
            description = "Detects unauthorized Apache configuration directives registering non-standard extensions as PHP scripts, or aliasing web paths to appliance script directories on Citrix NetScaler ADC"
            author = "GTIG"
        strings:
            // NetScaler appliance configuration context markers
            $ns1 = "/netscaler" ascii nocase
            $ns2 = "/var/netscaler" ascii nocase
            $ns3 = "/vpn/" ascii nocase
            $ns4 = "ns_gui" ascii nocase
            $ns5 = "<VirtualHost *:81>" ascii nocase
            $ns6 = "Listen 81" ascii nocase
            // Generic type or handler registration mapping non-standard file extensions to PHP
            $t1 = /Add(Handler|Type)\s+['"]?application\/x-httpd-php['"]?\s+\.([^p\s\r\n][a-zA-Z0-9_-]*|p[^h\s\r\n][a-zA-Z0-9_-]*|ph[^p\s\r\n][a-zA-Z0-9_-]*|php[^s\s\r\n][a-zA-Z0-9_-]*|phps[a-zA-Z0-9_-]+)/ ascii nocase
            // Diversion of web asset paths (media, theme, help, logon, images) to script staging directories
            $a1 = "AliasMatch" ascii nocase
            $a2 = /\^?\/vpn(s)?\/(media|theme|themes|images|help|logon|support)\// ascii nocase
            $a3 = /\/var\/netscaler\/gui\/vpn(s)?\/scripts\// ascii nocase
            $a4 = /\/vpn(s)?\/scripts\// ascii nocase
            // PHP execution flags
            $p1 = "php_flag engine on" ascii nocase
            // Exclusions for web pages, markup, and source code
            $not_html1 = "<html" ascii nocase
            $not_html2 = "<!DOCTYPE" ascii nocase
            $not_html3 = "<?xml" ascii nocase
            $not_code1 = "package " ascii
            $not_code2 = "#include " ascii
        condition:
            filesize < 100KB and not (
                $not_html1 or $not_html2 or $not_html3 or $not_code1 or $not_code2
            ) and (1 of ($ns*)) and (
                // Any directive registering a non-PHP extension as PHP
                $t1 or
                // Any AliasMatch diverting web paths to script directories
                ($a1 and ($a2 or $a3 or $a4)) or
                // Generic combination of php_flag engine on with script directory aliasing
                ($p1 and $a1 and ($a3 or $a4))
            )
    }
    
    rule G_Hunting_Backdoorwebshell_NetScaler_C2Headers_1
    {
        meta:
            description = "Detects standalone PHP webshells deployed on NetScaler appliances extracting commands from custom or native SetEnvIf HTTP headers"
            author = "GTIG"
       strings:
            // NetScaler C2 header patterns (both HTTP_NSC_* and raw NSC_*, covering all native SetEnvIf variables)
            $h1 = /(HTTP_)?NSC_[a-zA-Z0-9_]+/ ascii
            $h2 = /(HTTP_)?NSC_(USER|NONCE|LDAP|CLIENTTYPE|FT_HIDE)/ ascii nocase
            // Specific named NetScaler SetEnvIf headers
            $hs1 = "HTTP_NSC_LDAP" ascii fullword nocase
            $hs2 = "HTTP_NSC_CLIENTTYPE" ascii fullword nocase
            $hs3 = "HTTP_NSC_USER" ascii fullword nocase
            $hs4 = "HTTP_NSC_NONCE" ascii fullword nocase
            $hs5 = "HTTP_NSC_FT_HIDE" ascii fullword nocase
            $hs6 = "NSC_USER" ascii fullword nocase
            $hs7 = "NSC_NONCE" ascii fullword nocase
            $hs8 = "NSC_LDAP" ascii fullword nocase
            $hs9 = "NSC_CLIENTTYPE" ascii fullword nocase
            $hs10 = "NSC_FT_HIDE" ascii fullword nocase
            // Dynamic execution sinks
            $e1 = "eval(base64_decode(" ascii
            $e2 = "shell_exec(base64_decode(" ascii
            $e3 = "system(base64_decode(" ascii
            $e4 = "passthru(base64_decode(" ascii
            $e5 = "eval(" ascii
            $e6 = "base64_decode(" ascii
            $e7 = "shell_exec(" ascii
            $e8 = "passthru(" ascii
            $e9 = "system(" ascii
            $e10 = "exec(" ascii
            $e11 = "popen(" ascii
            $e12 = "proc_open(" ascii
            $e13 = "assert(" ascii
            // Concealment and response markers
            $c1 = "http_response_code(404)" ascii
            $c2 = "REQUEST_METHOD" ascii
            $c3 = "<FATO>" ascii
            $c4 = "</FATO>" ascii
        condition:
            filesize < 50KB and (
                // Any NSC header accessed alongside dynamic execution
                ((1 of ($h*) or 1 of ($hs*)) and ($e1 or $e2 or $e3 or $e4 or ($e6 and ($e5 or $e7 or $e8 or $e9 or $e10 or $e11 or $e12 or $e13)))) or
                // Any NSC header paired with concealment markers
                ((1 of ($h*) or 1 of ($hs*)) and ($c3 or $c4 or ($c1 and $c2))) or
                // Standalone FATO marker webshell
                (($c3 and $c4) and ($e1 or $e2 or ($e5 and $e6) or ($e6 and $e7)))
            )
    }
    
    rule G_Hunting_Script_NetScaler_Persistence_1
    {
        meta:
            description = "Detects appliance staging, installer, and anti-forensic maintenance scripts deployed during NetScaler compromise"
            author = "GTIG"
        strings:
            // Appliance restart / shutdown commands
            $cmd1 = "/netscaler/nsshutdown" ascii
            $cmd2 = "nsshutdown -R" ascii
            // SUID root backdoor creation
            $cmd3 = "chmod u+s /bin/sh" ascii
            // Web server reload / restart
            $cmd4 = "/bin/httpd -k restart" ascii
            $cmd5 = "httpd -k restart -f /etc/httpd.conf" ascii
            // Forensic access log scrubbing regex pattern (across any staging path)
            $scrub1 = /#\^\.\*\/vpn(s)?\/(scripts|media|theme|themes|help|logon)/ ascii
            // Apache configuration modification strings
            $cfg1 = "AddHandler application/x-httpd-php" ascii
            $cfg2 = "AddType application/x-httpd-php" ascii
            $cfg3 = "php_flag engine on" ascii
            $cfg4 = "AliasMatch" ascii
            $cfg5 = "SetEnvIf" ascii
        condition:
            filesize < 50KB and (
                // Log scrubber + privilege escalation or web server restart
                ($scrub1 and ($cmd3 or $cmd4 or $cmd5)) or
                // SUID root backdoor creation + appliance command or config modification
                ($cmd3 and ($cmd1 or $cmd2 or $cmd4 or $cmd5 or $cfg1 or $cfg2 or $cfg3 or $cfg4 or $cfg5)) or
                // Configuration tampering + appliance command
                (($cfg1 or $cfg2 or $cfg4) and ($cmd1 or $cmd2 or $cmd4 or $cmd5)) or
                // Generic 2 of the specific appliance maintenance commands
                (2 of ($cmd*))
            )
    }
    

    Google Security Operations 

    Google Security Operationsは、お客様を確実に保護するため、Mandiant Intel Emerging Threatsルールパック内のルールを継続的に開発・更新しています。本稿で詳述した脅威活動に対する新しいルールは現在、積極的にテストを進めています。検知カバレッジが整い次第、Google SecOps全体に追加・展開する予定です。

    謝辞

    本分析は、Bella Valdescruz、Bhavesh Dhake、Chris Linklater、Christopher Romano、Geoff Carstairs、Greg Blaum、Josh Thackston、Kimberly Goody、Lianis Oliva、Matthew Quick、Michael Edie、Omar ElAhdan、Peter Ukhanov、Sagun Chetry、Stuart Carrera、Tyler McLellanの協力なしには実現できませんでした。

    掲載カテゴリ

    翻訳元: https://cloud.google.com/blog/topics/threat-intelligence/defending-against-active-exploitation-of-citrix-netscaler-adc-and-gateway-appliances/

    本記事は cloud.google.com の記事を翻訳・要約したものです。