てきとうなメモ

本の感想とか技術メモとか

ImageMagickの脆弱性(ImageTragick)

piyokangoさんが詳しいが自分も少し調べたので。

d.hatena.ne.jp
ImageTragick

どんな脆弱性

外部からの入力により、意図せずに、ファイルを読みこんだり、ファイルを移動したり、削除したり、特定のURLにアクセスしたり、任意のコードを実行可能な脆弱性

どういうアプリが攻撃される?

画像をアップロードしてImageMagickを使って変換するみたいなサービスが狙われるかな。

どういう仕組みで攻撃しているのか

ImageMagickはいろんな種類のファイルを処理できるが、そのためにcoderとdelegateという機能がある。coderはライブラリとして各種ファイルを変換する機能、delegateは適切なcoderがなかった時に、外部コマンドを用いて変換する機能である。

CVE-2016-3714(コード実行の脆弱性)については、delegateの機能で外部コマンドを呼び出す時にsystem関数を利用していたが、shellの特殊文字のエスケープを実施していなかったことが主な原因。

例えば、

convert https://www.imagemagick.org/image/wizard.png wizard.png

を実行すると、imagemagickのサイトからwizard.pngをダウンロードしてwizard.pngというファイルに保存している。

内部的には次のような処理を行っている。
ImageMagickはconvertの変換元(第一引数)をHTTPSという種類のファイルとみなす。HTTPSのcoderは存在しないので、delegateを探す。delegateはdelegates.xmlに記述されており、CentOS6では以下のものが該当する

<delegate decode="https" command="&quot;curl&quot; -s -k -o &quot;%o&quot; &quot;https:%M&quot;"/>

ImageMagickはcommandの部分のコマンドを実行する。%Mには入力ファイル名が渡される。しかし%Mを置換する際にshellの特殊文字のエスケープを実施していないので、

convert 'https://www.imagemagick.org/image/wizard.png"|ls "-la' wizard.png

を実行すると

"curl" -s -k -o "wizard.png" "https://www.imagemagick.org/image/wizard.png"|ls "-la"

が実行され、lsも実行されることになる。

これだけだと、普通のアプリだと外部の入力をそのままconvertの引数にしないから大丈夫じゃないかと思える。が、この処理を画像ファイルの中に隠すことができる。

ImageMagickにはSVGとMVG(ImageMagick独自のテキストベースの画像フォーマット)のcoderがあり、それらのフォーマットは外部のURLやファイルを参照できる。例えば以下のMVGファイルは外部URLhttps://example.com/image.jpgを含む。

push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg)'
pop graphic-context

この外部URL参照に対してもcoder/delegateが実行される。今回の場合はHTTPSフォーマットだとみなされ、HTTPSdelegate commandが実行され、任意のプロセスを起動できる。

さらに、ImageMagickはそのファイルがどのフォーマットのファイルかについて

  1. マジックバイト
  2. format:filename形式のprefix
  3. 拡張子(filename.suffix)

の優先順位でチェックする。SVGやMVGはマジックバイトがチェックされるので、拡張子pngなどを指定していたとしても、中身がSVG/MVGならばSVG/MVGと解釈されてしまう。

そのため、MVGファイルをアップロードする→convertでファイルを処理しようとするとMVGのcoderが実行される→URLを参照している部分でコードを実行可能ということになる。

その他の脆弱性についてだが、shellコマンドのエスケープの問題はないものの、これらもMVG内に外部のファイルやURLを参照することにより、ファイル/URLの読み書きを行ってしまうことが原因となっている。

修正版は?

最新版(7.0.1-1)をインストールすると防げるようである。

実際に動かしてみると一部しか防げない(×は防げていない)のでpolicy.xmlで防ぐ必要がある。

CVE 内容 防げる?
CVE-2016-3714 delegateによるRCE脆弱性
CVE-2016-3718 SSRF(URLに対するGET) ×
CVE-2016-3715 ephemeralプロトコルによるファイルの削除 ×
CVE-2016-3716 mslプロトコルによるファイルの移動 *1
CVE-2016-3717 labelプロトコルによるファイルの読み込み ×

回避策は?

脆弱性公式サイトによると以下のどちらかで防げる。

  1. マジックバイトをチェックする
  2. policy.xmlに以下を指定
<policymap>
  <policy domain="coder" rights="none" pattern="EPHEMERAL" />
  <policy domain="coder" rights="none" pattern="URL" />
  <policy domain="coder" rights="none" pattern="HTTPS" />
  <policy domain="coder" rights="none" pattern="MVG" />
  <policy domain="coder" rights="none" pattern="MSL" />
  <policy domain="coder" rights="none" pattern="TEXT" />
  <policy domain="coder" rights="none" pattern="SHOW" />
  <policy domain="coder" rights="none" pattern="WIN" />
  <policy domain="coder" rights="none" pattern="PLT" />
</policymap>

coderとかdelegateの周りの処理の流れがよくわからん

私もよくわかっていないが、以下のような感じかな

  1. 仕組みのところに書いた優先度でフォーマットを決める
    • マジックバイトのチェックはMagicCore/magic.cのMagicMapの値を読むとなんとなくわかる
    • magic.xmlにもカスタマイズしたものを指定可能だけども
  2. フォーマットに対応するcoderを探し、存在すればcoderを実行する
    • どのフォーマットがどのcoderに該当するかはMagicCore/coder.cのCoderMapを読むとなんとなくわかる
  3. coderが存在しなければdelegateを実行する
    • デフォルトのdelegateはconfig/delegates.xml.inに書かれてある

RedHatの回避策は微妙?

ImageMagick Filtering Vulnerability - CVE-2016-3714のResolveのMitigationのことだよね。うん、これは微妙だ。RHEL 5では使えないし、明示的にHTTPとFTPを禁止している理由が判らない。私がコードを眺めた限りでは、HTTPとFTPはURLが提供しているようだ。やれやれ。

policy.xmlが使えない古いImageMagickでImageTragickを回避する (2) - Qiita

私がコードを読んだ感じだとcoderのpolicyチェックはcoder名に対して行うのではなく、フォーマットに対して行うのでそんなに悪くない気がするかな。MagicCore/constitute.cのReadImage関数の部分

  if (IsRightsAuthorized(domain,rights,read_info->magick) == MagickFalse)
    {    
      errno=EPERM;
      (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
        "NotAuthorized","`%s'",read_info->filename);
      read_info=DestroyImageInfo(read_info);
      return((Image *) NULL);
    }

read_info->magickにはcoder名ではなくフォーマット名が入る。

実際にMVG内にHTTPのURLを書いた場合はHTTPのcoderをnoneにしないと防げなかった。

ただ、そもそもMVGをnoneにした時点で防げる話ではあるのだけども。

修正内容はどんなもの?

いまいち理解しきれていないが今回の脆弱性に関して7.0.1-1までに以下の修正が入ったっぽい。

その後の修正

今回の脆弱性関係でまだいくつか修正しているっぽい。

*1:なぜ防げているのかよくわからない