ImageMagick(CVE-2016-3714)执行过程,漏洞分析以及修复方案-安全盒子

什么是ImageMagick

ImageMagick是一个免费的创建、编辑、合成图片的软件。它可以读取、转换、写入多种格式的图片。图片切割、颜色替换、各种效果的应用,图片的旋转、组合,文本,直线,多边形,椭圆,曲线,附加到图片伸展旋转。

在本周二,ImageMagick披露出了一个严重的0day漏洞,此漏洞允许攻击者通过上传恶意构造的图像文件,在目标服务器执行任意代码。Slack安全工程师Ryan Hube发现了这一0day漏洞。相关报道

漏洞分析

这次披露的是ImageMagick的一个命令执行漏洞。首先定位到最终漏洞代码执行的地方,老外给出的poc是在一个文件内填充以下字符命名为

1
.mvg

格式

push graphic-context

viewbox 0 0 640 480

fill’url(https://example.com/image.jpg“ls “-la)’

pop graphic-context

ImageMagick(CVE-2016-3714)执行过程,漏洞分析以及修复方案-安全盒子

POC执行效果如上图所示,可以执行mvg中注入的命令

我以POC为一个切入点,分析POC的执行过程。

ImageMagick(CVE-2016-3714)执行过程,漏洞分析以及修复方案-安全盒子

首先从入口函数CovertMain()开始,在第81行MagickCommandGenesis()的第二个参数传入了ConvertImageCommand这个变量,这个变量是一个函数指针,指向了ConvertImageCommand()的函数首地址。所以MagickCommandGenesis()实现了函数的动态调用(非常好的写法)。

文件:wand/delegate.c:417行

ImageMagick(CVE-2016-3714)执行过程,漏洞分析以及修复方案-安全盒子

的函数ExternalDelegateCommand()中调用了system()函数,执行了我们注入的命令。

整个执行流程是

ConvertMain() -> MagickCommandGenesis()-> ConvertImageCommand()

-> ReadImages() -> ReadImage() ->ReadMVGImage() -> DrawImage() ->ReadImage()

-> InvokeDelegate() -> system()

这一段

主要做了读取判断文件名类型,根据文件类型调用相应的decoder,而调用decoder的方式使用的是delegate模式。

在coders/mvg.c:67行中

有一个IsMVG()函数

if (LocaleNCompare((const char *)magick,"push graphic-context",20) == 0)

return(MagickTrue);

这一段读取了文件前20个字符,判断是否是一个MVG格式的图片,

1
viewbox 0 0 640 480

主要由

1
2
3
4
5
文件:coders/mvg.c
[crayon-58ac0e38c842e092192780/]
这一段代码处理。

处理

fill

1
字段就是出问题的地方, 当mvg文件有

fill

1
字段代表需要填充外部的图片进当前的图片,

pattern_info->filename

1
就是从

fill`中解析出来的填充文件的字符串

ImageMagick(CVE-2016-3714)执行过程,漏洞分析以及修复方案-安全盒子

1
magick/delegate.c

中的InvokeDelegate()进行了调用了ExternalDelegateCommand()执行外部命令。

题外话:可以看出来这个功能使用了delegate代理模式(对方法的封装)

在调用前实际上是对当前种类的请求方法,相应的权限进行了判断

if(IsRightsAuthorized(domain,rights,read_info->magick) == MagickFalse)

{

errno=EPERM;

(void) ThrowMagickException(exception,GetMagickModule(),PolicyError,

"NotAuthorized","

1
2
3
4
5
6
7
8
9
10
11
%s'",read_info->filename);

read_info=DestroyImageInfo(read_info);

return((Image *) NULL);

}

并不是像网上说的这个程序一点安全都没有做

并且在

delegate.c

1
2
3
4
5
6
7
8
9
10
11
中也有对权限的检测。

if (IsRightsAuthorized(DelegatePolicyDomain,rights,encode)== MagickFalse)

{

errno=EPERM;

(void) ThrowMagickException(exception,GetMagickModule(),PolicyError,

"NotAuthorized","

%s'",encode);

return(MagickFalse);

}

并且在

1
delegate.c

中定义了合法字符的白名单,问题有一部分出在白名单这。

static char

whitelist[] =

"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"

".@&;<>()|////'/":%=~

1
2
3
4
5
6
7
8
9
10
11
";

...

for (p+=strspn(p,whitelist); p != q;p+=strspn(p,whitelist))

*p='_';

return(sanitize_command);

我们可以看到不在白名单中的字符全部会被替换成_,但是官方却把

|

1

;

1
2
3
4
5
放在了白名单中,导致了可以执行多个命令…
<h2>修复方式</h2>
所以,经过以上的流程分析,可以有两种修复方法:

1.设置

Policy

1
2
3
文件

policy.xml
1
 

<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>

1
 
1
2
3
ps:来自imagetragick.com

2.如果不需要一些不常用的delegate里面的功能只保留https这个功能的话,去掉whitelist[]里面的管道符号

|

1
,还有

;

1
2
3
号等特殊符号,https这个delegate就可以正常使用了

复现之前的exploit可以看到去掉白名单里面的

;

1

|`之后,命令执行已经不成功了:)

ImageMagick(CVE-2016-3714)执行过程,漏洞分析以及修复方案-安全盒子

相应的,想要发掘对应的delegate可以有什么样的利用,可以看以下具体的委托

ImageMagick(CVE-2016-3714)执行过程,漏洞分析以及修复方案-安全盒子

Reference

http://blog.csdn.net/liujiyong7/article/details/44833475

*本文作者:Luverose,本文属FreeBuf黑客与极客(FreeBuf.COM)原创奖励计划,未经许可禁止转载