Skip to main content

ImageMagickの脆弱性を悪用してDockerコンテナに侵入した方法

著者
Blog Header Hacking 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を使用します。

FROM node:6.1.0-wheezy 

RUN mkdir /usr/src/goof
COPY . /usr/src/goof
WORKDIR /usr/src/goof

RUN npm update
RUN npm install
CMD ["npm", "start"]

このDockerfileは、Dockerイメージの安全なビルドに関するガイドラインに準拠しておらず、説明を簡潔にするためだけに使用しています。セキュリティのベストプラクティスについては、DockerでNode.js Webアプリケーションをコンテナ化するための10のベストプラクティスのチートシートをご覧ください。

このFastify Webアプリケーションは、ファイルをアップロードする**/**uploadパスのルートを提供します。アップロードされた画像を使って/usr/bin/convertプロセスを実行し、指定サイズに変換した後、成功ページにリダイレクトします。

fastify.post("/upload", (req, res) => {
  req.multipart(uploadFileHandler, err => {
    if (err) {
      fastify.log.error(err);
    }

    fastify.log.info("upload completed");
    fastify.log.info("commencing image resizing");

    child_process.execFile(
      "/usr/bin/convert",
      [FILE_OUTPUT, "-resize", "280x150", FILE_RESULT],
      () => {
        res.redirect("/result.html");
      }
    );
  });
});

このコードでは、文字列の連結を許可しない、安全なNode.js APIを使ってプロセスを実行しています。

システムシェルを起動してプロセスを実行するのは良い方法でしょうか。そうとは言えません。少なくとも、正当な理由がなければ避けるべきです。キューからデータを受け取る、あるいはジョブスケジューラからタスクを受け取るNode.jsワーカープロセスであれば、この用途に適しているでしょう。

とはいえ、同様のユースケースがGoogle I/O 2017のイベントでライブデモされたのですから、私たちが批判するのもおかしな話です。

FirebaseとGoogle Cloudのコードが画像をダウンロード、サイズ変更、アップロードする様子を示す動画プレーヤー。

Dockerコンテナに侵入してみよう

まずSnykにプロジェクトをインポートしました。すると対応するマニフェストファイルが自動的に検出されます。この場合は、アプリケーションのpackage.jsonとDockerfileです。

最新のNode.js 6イメージ(node:6-stretch)であっても、コンテナイメージにはデフォルトで866件のセキュリティ脆弱性が存在することがわかります。幸い、Snykはアプリケーションのセキュリティを少なくとも2つの方法で改善できる、代替ベースイメージへのアップグレードを提案してくれます。

  1. 脆弱性の数を減らし、攻撃対象領域を縮小できます。

  2. Node.jsランタイム自体に脆弱性がないベースイメージを選べます。これは、推奨されるベースイメージを利用することで得られる非常に重要なメリットですが、見落とされがちです。

Dockerfileの詳細と、ベースイメージのアップグレードに関する推奨事項、脆弱性、深刻度評価を一覧にしたSnykプロジェクトの概要。

コンテナイメージに含まれるバージョンのImageMagickにあるImageTragickの脆弱性を利用して、リモートコマンドインジェクション攻撃を仕掛けてみましょう。

このエクスプロイトでは、ImageMagickライブラリのdelegates機能による解析を回避するよう特別に細工した画像ファイルを使用します。ImageMagickのこの機能は、画像ファイル内の命令に関連付けられたシステムコマンドを実行します。想定された入力コンテキストから抜け出すことで、攻撃者はシステムコマンドを注入できます。

このGitリポジトリには概念実証エクスプロイトが含まれています。デフォルトでnetcatが含まれていないディストリビューション(Debian wheezyなど)で、netcatをダウンロードしてリバースシェルを実現するリモートコード実行のエクスプロイトです。

画像ファイルrce1.jpgに含まれる概念実証ペイロードは、次のようになっています。

push graphic-context
viewbox 0 0 640 480
fill 'url(https://127.0.0.0/oops.jpg"|touch "rce1)'
pop graphic-context

この画像ファイルはユーザーが制御できるため、悪意のある攻撃者はペイロードを作成できます。この例では、UNIX系オペレーティングシステムでサポートされているコマンドを実行し、空のファイルtouch rce1を作成します。

コンテナイメージをビルドしたら、実行してみましょう。

docker run --rm --name rce rce

シンプルなWebアプリケーションからファイルをアップロードできます。

「こんにちは」と表示されたシンプルなWebページ。画像のアップロード欄と、写真を280×150ピクセルに変換する「サイズ変更」ボタンがあります。

rce1.jpgファイルを処理するためにResizeボタンを押すと、コマンドインジェクションが実行されます。

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

Dockerコンテナのコマンドと、package.json、Dockerfile、exploitファイル、強調表示されたファイルなど、Node.jsプロジェクトのディレクトリ一覧が表示されたターミナル。

コンテナへの侵入を振り返る

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

「公式コンテナイメージの脆弱性」と題された棒グラフ。Node、PostgreSQL、Nginx、その他のイメージについて、2018年と2019年の件数を比較。

今回実証した攻撃は、あらゆるセキュアコーディングの規約を完全に回避し、Node.jsランタイムのセキュリティや、アプリケーションに含まれるオープンソースのNode.jsモジュールの依存関係にとどまらない脅威です。Dockerイメージを保護する必要性が、改めて浮き彫りになりました。Snykはまさにそのために生まれました。

Snykは優先度の高い脆弱性を明らかにし、切り替え可能な別のベースイメージという形で修正方法を提案します。

Node.jsのベースイメージのアップグレードを推奨する表。脆弱性の件数と、重大度(高・中・低)を示しています。

この攻撃を手順どおりに再現したい場合は、オープンソースリポジトリのREADMEにある手順をご覧ください。ImageTragickの脆弱性を利用したリモートリバースシェル攻撃の実行方法も説明しています。

次のステップ

Docker化したアプリケーションのプロジェクトリポジトリがオープンソースでもプライベートでも、Snykの無料プランを利用して、Dockerイメージの既知のセキュリティ脆弱性を検査・修正できます。この機会にNode.jsアプリケーションもスキャンして修正しましょう。

ここで紹介したDockerfileと、付属のオープンソースリポジトリに含まれるDockerfileは、セキュリティ対策が不十分なため推奨できません。代わりに、以下のブログ記事を参考に、Dockerのセキュリティ対策に取り組んでください。

開発者ファーストのコンテナセキュリティ

Snykは、コンテナイメージとKubernetesワークロードの脆弱性を検出し、自動的に修正します。

続きを読む

feature customer snowflake
Article

開発初期からセキュリティを確保:Snowflake Cortex Code向けSnyk Studioインテグレーションを発表

Snyk StudioがSnowflake Cortex Codeと連携し、開発中にAI生成コード、依存関係、コンテナの脆弱性をスキャンします。

blog feature pypi spoof
Article

オープンソースのメンテナーに、Snyk AI Security Platformをすべて無料で提供

オープンソースのメンテナーは、実際の脆弱性レポートに追われ、優先順位付けや修正、修正版のリリースを迅速に進めるための支援を必要としています。SnykのSecure Developer Programでは、条件を満たすプロジェクトにSnyk AI Security Platformを無料で提供します。

feature insights announcement
Blog

Node-gypサプライチェーン侵害:binding.gypに潜む自己増殖型npmワーム

新たなnpmワームがbinding.gypを悪用し、インストール時にnode-gypを起動。ライフサイクルスクリプトを使わずに悪意あるパッケージからコードを実行します。認証情報を窃取し、GitHub上に潜伏し、メンテナー間で自己増殖します。