This post is also available in: English (英語)
概要
筆者は2021年3月にこれまで確認されていなかったWindowsコンテナを標的とするマルウェアを初めて発見しました。ここ数年のクラウド導入数の急激な伸びを考えれば、この発見はとくに驚くにはあたらないでしょう。筆者はこのマルウェアをSiloscape(「サイロエスケープ」のように発音)と名付けました。その理由は、このマルウェアの主な目的がコンテナをエスケープ(脱出)することにあり、Windowsでのコンテナは主にサーバーサイロ (Server Silo) によって実装されているからです。
Siloscapeは高度に難読化されたマルウェアで、Windowsコンテナを介してKubernetesクラスタを標的にしています。その主な目的は設定ミスのあるKubernetesクラスタにバックドアを開き、悪意のあるコンテナを実行することです。
通常、個々のコンテナは単一のクラウドアプリケーションのみを実行しています。これに対しクラスタは複数のクラウドアプリケーションを実行している可能性があります。そのためクラスタ全体の侵害は個々のコンテナの侵害にくらべてはるかに深刻なものになります。たとえばユーザー名やパスワードなどの重要情報、組織の機密ファイルや内部ファイル、さらにはクラスタにホストされているデータベース全体を攻撃者に窃取されてしまうおそれがあります。このような攻撃が組織のファイルを人質に取ってランサムウェア攻撃に利用する可能性もあります。組織のクラウド化が進むにつれ開発環境やテスト環境にKubernetesクラスタを採用する企業も増えていますから、そうした環境が侵害されれば深刻なソフトウェアサプライチェーン攻撃につながってしまうおそれもあります。
SiloscapeはTorプロキシと.onionドメインを使用してコマンド&コントロール(C2)サーバーに匿名で接続します。筆者はこのサーバーへのアクセスになんとか成功しました。この結果「Siloscape」によるアクティブな被害者23名を確認しました。またこのC2サーバーは合計で313ユーザーをホストしていました。このことは「Siloscape」がさらに大規模なキャンペーンのごく一部であることを物語っています。筆者はまたこのキャンペーンが1年以上前から行われていることも確認しています。
本稿ではWindowsコンテナの脆弱性にまつわる背景、Siloscapeの技術的概要、Windowsコンテナセキュリティ確保のためのベストプラクティスについて解説します。
パロアルトネットワークスのお客様は、Prisma Cloudのランタイム保護機能によりこの脅威から保護されています。
Windows Server Container脆弱性の概要
筆者は2020年7月15日に「Windows Serverコンテナのブレイクアウト方法とその対策」という記事を公開しました。この記事では、コンテナエスケープ (コンテナブレイクアウト) のテクニックを紹介し、そうしたエスケープテクニックが攻撃者の手に渡った場合の潜在的な用途について考察しました。そこで筆者が注目した最も重要な用途は「Kubernetes内のWindowsコンテナノードからクラスタ内での拡散を狙ってコンテナエスケープする」というものでした。
Microsoftは当初、この問題を脆弱性とは考えていませんでした。その根拠は「Windows Serverコンテナはセキュリティ境界ではないからコンテナ内で実行されている各アプリケーションはそのホスト上で直接実行されているものとして扱われるべきである」というものでした。
この議論がかわされた数週間後、筆者はGoogleにこの問題を報告しました。Kubernetesにはこれらの問題に対する脆弱性があるためです。その後GoogleがMicrosoftに問い合わせをし、そこで何度かやりとりがかわされたのち、Microsoftは「Windowsコンテナからホストへのエスケープがコンテナ内で管理者権限なしに実行された場合それは実際に脆弱性であるものとみなす」と判断しました。
この後、筆者はSiloscapeを発見しました。SiloscapeはWindows Serverコンテナに積極的にエクスプロイトをしかけているマルウェアで、すでに利用された実績があります。Siloscapeは、Windowsコンテナ(Hyper-VではなくServer Containersを使用)を介してKubernetesを標的にする高度に難読化されたマルウェアです。その主な目的は設定ミスのあるKubernetesクラスタにバックドアを開き、たとえばクリプトジャックを行う悪意のあるコンテナを実行することです。ただし、その目的だけには限定されません。
このマルウェアはその振る舞いやテクニックにいくつか特徴があります。
- Webサーバーなど一般的なクラウドアプリケーションを初期アクセスの標的とします。そのさいは既知の脆弱性(ワンデイ脆弱性)のなかでもすでに既知のエクスプロイトが出回っているものを利用しているようです。
- Windowsのコンテナエスケープ技術を使ってコンテナを脱出し基盤ノード上でコードを実行します。
- 基盤ノードの認証情報を悪用してクラスタ内で拡散を試みます。
- TorネットワークでIRCプロトコルを使ってC2サーバーに接続します。
- 追加コマンドを待ち受けます。
このマルウェアはKubernetesクラスタのコンピューティングリソースを利用してクリプトジャックを行い、侵害クラスタ上で実行されている何百ものアプリケーションから機密データを漏出させる可能性があります。
このC2サーバーを調査した結果、このマルウェアは大規模ネットワークのほんの一部で、攻撃キャンペーンは1年以上前から行われていることがわかりました。さらに、本稿執筆時点でこのオンラインになっている特定攻撃キャンペーン部分にアクティブな被害者がいることも確認されました。
技術的概要
技術的詳細に入る前にSiloscapeの全体的な振る舞いとフローについてここでしっかり理解しておきたいと思います。
- 攻撃者が既知の脆弱性、脆弱なWebページや脆弱なデータベースなどを使い、Windowsコンテナ内でリモートコード実行(RCE)を行えるようにします。
- 攻撃者が必要なC2接続情報をコマンドライン引数として提供された(バイナリ内にハードコードされていない)Siloscape(CloudMalware.exe)を実行します。
- SiloscapeがCExecSvc.exeになりすまし、SeTcbPrivilegeの権限を取得します(この手法については筆者の過去の記事で詳しく説明しています)。
- Siloscapeがホストへのグローバルシンボリックリンクを作成し、コンテナ化されたXドライブを実質的にホストのCドライブにリンクします。
- Siloscapeがグローバルリンクを使ってホスト上のkubectl.exeバイナリを名前で検索し、Kubernetes設定ファイルを正規表現で検索します。
- Siloscapeが侵害ノードに新規Kubernetesデプロイメントの作成に十分な権限があるかどうかをチェックします。
- Siloscapeがアーカイブされたファイルからunzipバイナリを使ってTorクライアントをディスクに展開します。この2つのファイルはSiloscapeのメインバイナリにパックされています。
- SiloscapeがTorネットワークに接続します。
- 提供されたコマンドライン引数を使用してSiloscapeがC2サーバーのパスワードを復号します。
- Siloscapeがコマンドライン引数として指定された.onionドメイン(Torネットワークを通じてアクセス可能なドメイン)を使ってC2サーバーに接続します。
- SiloscapeがC2からのコマンドを待ってそれを実行します。
コンテナを標的にするマルウェアのほとんどがクリプトジャックに特化したものであるのに対し、Siloscapeはそれ自体では実際にクラスタに危害を加えるようなことはしません。そのかわり、検出されないことや追跡されないことに重点を置いてクラスタへのバックドアを開きます。
防御回避と難読化
Siloscapeは高度に難読化されています。バイナリ全体で読める文字列はほとんどありません。難読化ロジック自体はさほど複雑なものではありませんが、このバイナリを復元するのはかなり骨が折れます。
単純なAPIコールですら難読化されており、関数を単純に呼び出すかわりにわざわざ同じ関数のネイティブAPI(NTAPI) を使うことまでやっていました。
たとえばSiloscapeはCreateFileを呼び出す代わりにNtCreateFileを呼び出します。またNtCreateFileを直接呼び出さず、動的に呼び出します (つまり、ランタイムにntdll.dll内で関数名を検索してそのアドレスにジャンプします)。それだけでなく、関数名やモジュール名も難読化して実行時にのみ難読化を解除します。この結果、静的解析ツールでの検出やリバースエンジニアリングが非常に難しいマルウェアができあがっています。
SiloscapeはC2サーバーのパスワード復号に鍵をひと組使用します。この難読化の最大の特徴は、一方のキーをバイナリにハードコードし、もう一方のキーをコマンドライン引数として与えていることです。筆者はAutoFocusやVirusTotalなど複数のエンジンでハッシュを検索しましたが、何も見つけることができませんでした。このことから、Siloscapeは新しい攻撃のたびに固有のキーペアを使い、それぞれを一意なものとしてコンパイルされているのではないかと考えられます。ハードコードされたキーのおかげで各バイナリはほかのものと少しずつ違なるものになり、その結果ハッシュがどこにも見つからないのでしょう。このことはハッシュ単体ではSiloscapeを検出できないということも意味します。
このマルウェアの使うもう1つ興味深いテクニックがVisual Studio Resource Managerです。Visual Studio Resource ManagerはVisual Studio組み込みの機能で、簡単なAPIコールをいくつか実行するだけで基本的にはどんなファイルでも元のバイナリに添付することができ、その添付データへのポインタを取得することができます。Siloscapeはこの方法でTorアーカイブとTorアーカイブを開くunzipバイナリの両方をディスクに書き込んでいます。また安全にC2へ接続する目的でTorを使っています。
コンテナエスケープ
このSiloscapeのさらにもうひとつ興味深い点はコンテナエスケープの方法です。エスケープを可能にするシステムコールNtSetInformationSymbolicLinkを実行するにはまずSeTcbPrivilegeを得なくてはいけません。そのための方法はいくつかあって、たとえば筆者のテストでは、適切な権限を持つCExecSvc.exeにDLLを注入してCExecSvc.exeのコンテキストでNtSetInformationSymbolicLinkを実行していました。Siloscapeの場合、Thread Impersonationと呼ばれるテクニックを利用しています。この方法はオンラインにはあまりドキュメントがなく実例もほとんど見つかりませんが、このテクニックで最も重要な関数が文書化されていないシステムコールNtImpersonateThreadです。
SiloscapeはCExecSvc.exeのメインスレッドになりすますことでCExecSvc.exeの権限を模倣し、新たに作成されたシンボリックリンク上でNtSetInformationSymbolicLinkを呼び出してコンテナをエスケープします。具体的には、コンテナ化されたローカルのXドライブをホストのCドライブにリンクします。
クラスタの選択
Siloscapeはホストへのリンクを作成してから2つの特定ファイルを検索します。その1つ目がkubectl.exeで、2つ目が通常Kubernetesノードに存在する設定ファイルです。
Siloscapeはkubectl.exeを名前で検索し、設定ファイルを正規表現で検索します。検索関数は追加引数を取りますが、この引数は検索対象から除外するフォルダ名を格納したvectorへのポインタです。
上記のファイルを検索するためにFindFileを呼び出すと、Program Files、Program Files (x86)、Windows、Usersの各フォルダが除外されます。除外理由は検索を高速化するためと、前述のファイルがこれらのフォルダに存在する可能性が低いためです。ファイルが両方見つかるとそのパスがグローバル変数に保存されます。ファイルが見つからなければSiloscapeは終了して攻撃を停止します。
Siloscapeはkubectlコマンド実行に必要なものをすべて見つけると、つづけて侵害ノードが実際に攻撃者の悪意のあるアクティビティへの使用にたえうるパーミッションを持っているかどうかのチェックにうつります。このチェックは、kubectlコマンド%ls auth can-i create deployments --kubeconfig=%lsを実行して行います。そのさいは、書式内の文字列が先ほどグローバル変数として保存したパスに置き換えられます。
C2への接続と対応コマンド
必要なものをすべて入手し、侵害ノードで実際に新規デプロイメントを作成できることを確認すると、SiloscapeはTorアーカイブ(ZIP)とunzipバイナリをホストのCドライブに書き込みます。Torを展開したSiloscapeはtor.exeを新しいスレッドに起動し、Torスレッドの出力を確認しつつその終了を待ちます。
Torが起動すると、Siloscapeはコマンドライン引数として提供されたonionアドレスでTorを使ってC2(IRCサーバー)に接続します。
このサーバーはパスワードで保護されています。Siloscapeは最初のコマンドライン引数を使用して単純なバイトごとのXOR演算でパスワードを復号します。以下はこのC2サーバーのパスワード復号をわかりやすく表したものです。
1 2 3 4 |
char hardCodedXor[32] = "HARD_CODED_32_LONG_STRING"; char ircPass[32] = { 0 }; for (int i = 0; i < 32; i++) ircPass[i] = hardCodedXor[i] ^ argv[1][i]; |
IRCサーバーへの接続に成功すると、JOIN #WindowsKubernetesコマンドを発行してWindowsKubernetes IRCチャンネルに参加し、そのまま待機します。
Siloscapeはkubectlがサポートするコマンドと通常のWindowsのcmd用コマンドの2種類のコマンドを受け付けます。
Siloscapeはプライベートメッセージを待ち受けます。adminというユーザーからのプライベートメッセージを受け取ると、Siloscapeは次のロジックに従います。
- そのメッセージがKで始まる場合は以前%ls %s --kubeconfig=%lsコマンドの実行で見つけておいたパスを使ってクラスタへのkubectlコマンドを実行する。
- 1つ目のパラメータはkubectlパスのグローバル変数。
- 2つ目のパラメータはadminからのメッセージから最初の文字を除いたもの。
- 3つ目のパラメータは設定ファイルのパスのグローバル変数。
- メッセージがCで始まる場合は単に最初の文字を除いたコマンドを通常のWindowsのcmdコマンドとして実行する。
コマンド&コントロール
本マルウェアを逆アセンブルしたさい、とくにC2処理部を逆アセンブルしたさい、筆者はこのキャンペーンがまだ実行中なのかどうかを確認したいと考えました。
そこでまっさらな仮想マシンを用意してTorをダウンロードし、SOCKS5をサポートするIRCクライアントを探し始めました。SOCKS5はTorを介した接続で必要となるプロキシプロトコルです。IRCは非常に古いプロトコルで20年前に比べると今は人気がありません。くわえてIRCはSOCKS5登場のほぼ10年前には登場しています。筆者はSOCKS5とonionドメインへの接続の両方をサポートしているシンプルで軽量なIRCクライアント、HexChatを見つけました。
弊社のSilospaceサンプルが最初に実行されたさいのIRCユーザー名のコマンドライン引数はphp_35でした。そこで攻撃者から見て正当なものに見えることを期待してHexChatからC2サーバーへ接続するさいにこのユーザー名を使うことにしました。
接続してみるとこのサーバーがまだ稼働していることがわかりました。そこでSiloscapeのまねをして#WindowsKubernetesに参加しました。そこには23名のアクティブな被害者とadminというチャンネルオペレータがいました。
残念ながら2分ほどで気づかれてしまい、サーバーから締め出されてしまいました。その2分後には、少なくとも筆者が使っていたオリジナルのonionドメインでは、当該サーバーはすでにアクティブではなくなっていました。
今回学んだこと
今回の調査結果を確認してまず頭に浮かんだのは「このC2サーバーには#WindowsKubernetesチャンネルで実際に見たよりも多くのアクティブユーザーがいた」ということです。正確には合計313名のユーザーがいました。このことはSiloscapeマルウェアがより大きなキャンペーンのほんの一部でしかないことを物語っています。
残念ながらサーバーに接続するとチャンネルリストは空になっていました。これはサーバーがチャンネルを公開しないように設定されたことを意味します。このためチャンネル名からは詳しい情報を得ることができませんでした。
もうひとつ重要なポイントは被害者名の表記方法です。筆者らに与えられた名前はphp_35でしたが、筆者らのSiloscapeのサンプルが最初に実行されたとき、それは実際、脆弱なphpインスタンスを介して実行されていました。そのほかの名前も攻撃者がコード実行を達成した方法を明確に示しています(たとえば「sqlinj」は「SQLインジェクション」を意味しているのでしょう)。
@admin sqlinj_64 sqlinj_51 php_34 weblogic_12 sqlinj_138 weblogic_19 php_66 sqlinj_87 sqlinj_8 sqlinj_33 sqlinj_114 activemq_5 sqlinj_44 tomcat_9 sqlinj_52 sqlinj_107 redis_10 php_76 sqlinj_28 activemq_25 sqlinj_35 php_8 weblogic_31 php_35
C2から得られた最後の情報はサーバーの作成日です。これは2020年1月12日となっていました。これは必ずしもその日にSiloscapeが作られたということは意味しませんのでその点は留意してください。どちらかといえばその頃からキャンペーンが始まっていた可能性があります。
結論
リソースハイジャックやサービス妨害(DoS)を主な目的とする多くのクラウドマルウェアとは異なり、Siloscapeには限定された特定の目的がありません。そのかわり、あらゆる種類の悪意ある活動へのバックドアを開きます。
前回の記事でも述べたように、ユーザーは「Windowsコンテナをセキュリティ機能と考えて利用しないこと」を推奨するMicrosoftのガイダンスに従うべきです。Microsoftではコンテナ化をセキュリティ境界として利用するのであれば、厳密にHyper-Vコンテナだけを使うことを推奨しています。Windows Serverコンテナで実行されるプロセスはすべて、ホスト(この場合はKubernetesノード)のadminと同じ権限を持っているものと仮定しておく必要があるのです。Windows Serverコンテナでセキュリティを確保する必要のあるアプリケーションを実行しているなら、これらのアプリケーションはHyper-Vコンテナに移行することをお勧めします。
さらに管理者はKubernetesクラスタが安全に構成されていることも確認する必要があります。とくにセキュリティで保護されたKubernetesクラスタであれば、ノード権限で新規デプロイメントを作成できないことからこの特定マルウェアに対してはそれほど脆弱ではありません。この場合Siloscapeの実行は停止します。
Siloscapeはコンテナセキュリティの重要性を教えてくれるものといえます。コンテナエスケープができなければこのマルウェアはさほど大きなダメージを与えることができません。こうした脅威から組織を守るには、設定ミスのない安全なクラウド環境を維持することが重要です。
Prisma Cloudは既存の機能でSiloscapeマルウェアを検出・緩和することができます。
Prisma Cloudのランタイム保護機能はマシンの振る舞いを学習し、プロセスのためのルールセットを作成します。学習が完了すると新たに実行される予期せぬプロセスに対するアクションをユーザーが選択できるようになります。選択できるアクションは、警告、防止、または実行の完全なブロックです。
IoC
説明 | SHA256値 |
筆者らのSiloscape亜種 | 5B7A23676EE1953247A0364AC431B193E32C952CF17B205D36F800C270753FCB |
Siloscapeがディスクに書き込むunzipバイナリのunzip.exe | 81046F943D26501561612A629D8BE95AF254BC161011BA8A62D25C34C16D6D2A |
Silsocapeがディスクに書き込むtorアーカイブtor.zip | 010859BA20684AEABA986928A28E1AF219BAEBBF51B273FF47CB382987373DB7 |
追加資料
Unit 42、Windowsコンテナを標的とした初のマルウェアを発見
ウェビナー開催: Unit 42リサーチャーがSiloscapeの詳細をライブで解説します。