ImageMagickの脆弱性を悪用してDockerコンテナに侵入した方法
2021年3月11日
0 分で読めます脆弱性のあるDockerイメージを使用すると、そのイメージを使うDockerコンテナがコマンドインジェクションの脆弱性を悪用され、深刻かつ差し迫ったリスクにさらされるとしたら、どうでしょうか。
この記事では、脆弱性のある公式のNode.js用Dockerベースイメージを使用するNode.jsベースのWebアプリケーションを悪用し、コンテナに侵入する手順を詳しく解説します。
脆弱性のあるNode.jsイメージを使ったコンテナへの侵入
この脆弱性を実証するため、古いNode.jsランタイムと、画像を指定サイズに変更するFastifyアプリケーションを使います。画像のリサイズ処理は、ImageMagickライブラリに処理を委ねます。このライブラリには便利なconvertコマンドラインツールが用意されています。
ImageMagickは、画像形式の変換、リサイズ、トリミングなど、Webアプリケーションで画像を処理する際によく使われる、プログラミング言語バインディングとコマンドラインツールのセットです。
しかし残念ながら、ImageMagickではこれまでに数多くのセキュリティ脆弱性が確認されており、その中のひとつが有名なImageTragickの脆弱性(CVE-2016-3714)です。この脆弱性は不適切な入力検証に分類されますが、リモートからのコマンドインジェクションにつながる可能性のある概念実証エクスプロイトが、2016年から実際に確認されています。
これは、セキュリティのベストプラクティスが守られていなかったり、Node.jsアプリケーションの依存関係に脆弱性があったりしたためではなく、DockerベースのNode.jsアプリケーションに含まれる可能性のあるサードパーティ製オープンソースコンポーネントを悪用して、コンテナに侵入した事例です。
Node.jsアプリケーション
まず、Node.jsアプリケーションをまとめたDockerイメージから見ていきましょう。説明を簡潔にするため、非常に軽量なDockerfileを使用します。
このDockerfileは、Dockerイメージの安全なビルドに関するガイドラインに準拠しておらず、説明を簡潔にするためだけに使用しています。セキュリティのベストプラクティスについては、DockerでNode.js Webアプリケーションをコンテナ化するための10のベストプラクティスのチートシートをご覧ください。
このFastify Webアプリケーションは、ファイルをアップロードする**/**uploadパスのルートを提供します。アップロードされた画像を使って/usr/bin/convertプロセスを実行し、指定サイズに変換した後、成功ページにリダイレクトします。
このコードでは、文字列の連結を許可しない、安全なNode.js APIを使ってプロセスを実行しています。
システムシェルを起動してプロセスを実行するのは良い方法でしょうか。そうとは言えません。少なくとも、正当な理由がなければ避けるべきです。キューからデータを受け取る、あるいはジョブスケジューラからタスクを受け取るNode.jsワーカープロセスであれば、この用途に適しているでしょう。
とはいえ、同様のユースケースがGoogle I/O 2017のイベントでライブデモされたのですから、私たちが批判するのもおかしな話です。

Dockerコンテナに侵入してみよう
まずSnykにプロジェクトをインポートしました。すると対応するマニフェストファイルが自動的に検出されます。この場合は、アプリケーションのpackage.jsonとDockerfileです。
最新のNode.js 6イメージ(node:6-stretch)であっても、コンテナイメージにはデフォルトで866件のセキュリティ脆弱性が存在することがわかります。幸い、Snykはアプリケーションのセキュリティを少なくとも2つの方法で改善できる、代替ベースイメージへのアップグレードを提案してくれます。
脆弱性の数を減らし、攻撃対象領域を縮小できます。
Node.jsランタイム自体に脆弱性がないベースイメージを選べます。これは、推奨されるベースイメージを利用することで得られる非常に重要なメリットですが、見落とされがちです。

コンテナイメージに含まれるバージョンのImageMagickにあるImageTragickの脆弱性を利用して、リモートコマンドインジェクション攻撃を仕掛けてみましょう。
このエクスプロイトでは、ImageMagickライブラリのdelegates機能による解析を回避するよう特別に細工した画像ファイルを使用します。ImageMagickのこの機能は、画像ファイル内の命令に関連付けられたシステムコマンドを実行します。想定された入力コンテキストから抜け出すことで、攻撃者はシステムコマンドを注入できます。
このGitリポジトリには概念実証エクスプロイトが含まれています。デフォルトでnetcatが含まれていないディストリビューション(Debian wheezyなど)で、netcatをダウンロードしてリバースシェルを実現するリモートコード実行のエクスプロイトです。
画像ファイルrce1.jpgに含まれる概念実証ペイロードは、次のようになっています。
この画像ファイルはユーザーが制御できるため、悪意のある攻撃者はペイロードを作成できます。この例では、UNIX系オペレーティングシステムでサポートされているコマンドを実行し、空のファイルtouch rce1を作成します。
コンテナイメージをビルドしたら、実行してみましょう。
シンプルなWebアプリケーションからファイルをアップロードできます。

rce1.jpgファイルを処理するためにResizeボタンを押すと、コマンドインジェクションが実行されます。
この攻撃を検証するため、実行中のDockerコンテナ内のアプリケーションに接続してみましょう。Node.jsアプリケーションのルートディレクトリにrce1.jpgという新しいファイルが作成されたことがわかります。

コンテナへの侵入を振り返る
さまざまなDockerイメージに数多くのセキュリティ脆弱性が見つかっていることに、それほど驚きはないでしょう。私たちも同じです。実際、オープンソースセキュリティの現状レポートで報告したように、Docker Hubの人気上位10件のDockerイメージにセキュリティ脆弱性が含まれていることを確認しています。

今回実証した攻撃は、あらゆるセキュアコーディングの規約を完全に回避し、Node.jsランタイムのセキュリティや、アプリケーションに含まれるオープンソースのNode.jsモジュールの依存関係にとどまらない脅威です。Dockerイメージを保護する必要性が、改めて浮き彫りになりました。Snykはまさにそのために生まれました。
Snykは優先度の高い脆弱性を明らかにし、切り替え可能な別のベースイメージという形で修正方法を提案します。

この攻撃を手順どおりに再現したい場合は、オープンソースリポジトリのREADMEにある手順をご覧ください。ImageTragickの脆弱性を利用したリモートリバースシェル攻撃の実行方法も説明しています。
次のステップ
Docker化したアプリケーションのプロジェクトリポジトリがオープンソースでもプライベートでも、Snykの無料プランを利用して、Dockerイメージの既知のセキュリティ脆弱性を検査・修正できます。この機会にNode.jsアプリケーションもスキャンして修正しましょう。
ここで紹介したDockerfileと、付属のオープンソースリポジトリに含まれるDockerfileは、セキュリティ対策が不十分なため推奨できません。代わりに、以下のブログ記事を参考に、Dockerのセキュリティ対策に取り組んでください。
開発者ファーストのコンテナセキュリティ
Snykは、コンテナイメージとKubernetesワークロードの脆弱性を検出し、自動的に修正します。



