ImageMagickの脆弱性(ImageTragick)
piyokangoさんが詳しいが自分も少し調べたので。
どういうアプリが攻撃される?
画像をアップロードして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=""curl" -s -k -o "%o" "https:%M""/>
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フォーマットだとみなされ、HTTPSのdelegate commandが実行され、任意のプロセスを起動できる。
さらに、ImageMagickはそのファイルがどのフォーマットのファイルかについて
- マジックバイト
- format:filename形式のprefix
- 拡張子(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プロトコルによるファイルの読み込み | × |
回避策は?
脆弱性公式サイトによると以下のどちらかで防げる。
- マジックバイトをチェックする
- 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の周りの処理の流れがよくわからん
私もよくわかっていないが、以下のような感じかな
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までに以下の修正が入ったっぽい。
その後の修正
今回の脆弱性関係でまだいくつか修正しているっぽい。
- Update to the latest autoconf / automake · ImageMagick/ImageMagick@e87116a · GitHub
- Use %F instead of %M for zero-configuration delegates · ImageMagick/ImageMagick@dcdd212 · GitHub
- Remove support for internal ephemeral coder. · ImageMagick/ImageMagick@b831d90 · GitHub
- ephemeral coder自体がなくなった。
- Less secure coders require explicit reference (e.g. mvg:my-graph.mvg) · ImageMagick/ImageMagick@a58ba05 · GitHub
- マジックバイトでMVGかどうかを判断しなくなった。つまり、明示的にmvgファイルだと拡張子やprefixで指定しないとmvgとして処理されなくなる。
*1:なぜ防げているのかよくわからない