前段时间写的文章,在微博上说HW结束分享一下,总算可以发了。感谢 @voidfyoo 提出的这个问题。
今天遇到一个代码,大致如下:
<?php $filename = $_FILES['image']['tmp_name']; $size = getimagesize($filename); if ($size && $size[0] > 100 && $size[1] > 100) { $img = new Imagick($_FILES['image']['tmp_name']); $img->cropThumbnailImage(100, 100); $img->writeImage('newimage.gif'); }
用户上传的文件如果大于100px,则用Imagick处理成100×100的缩略图,再存储在硬盘上。
通过这个代码,我们很容易想到用Imagemagick的漏洞进行测试,但这里前面对图片大小用getimagesize进行了限制,之前爆出来的那些POC均无法通过校验,因为getimagesize并不支持类似PostScript、MVG这样的图片格式。
这时候我们怎么绕过这个限制呢?
0x01 Imagemagick命令执行不完全回顾
Imagemagick历史上曾出现过的很多命令执行漏洞,我在vulhub里做过以下三个:
- CVE-2016-3714
- CVE-2018-16509
- CVE-2019-6116
第一个是Imagemagick在处理mvg格式图片时导致的命令注入,后两个都是在处理PostScript文件时因为使用了GhostScript,而GhostScript中存在的命令注入。
Imagemagick是一个大而全的图片处理库,他能处理日常生活中见到的绝大多数图片格式,比如jpg、gif、png等,当然也包括日常生活中很少见到的图片格式,比如前面说的mvg和ps。
这三个漏洞的具体原理网上很多文章也分析过,我这里就不再分析了,但我们思考一下:一个文件交给Imagemagick处理,他是怎么知道这是哪种格式的图片,并如何处理呢?
显然需要一个方法来区分文件类型,而单纯用文件名后缀来判断是不合理的(文件后缀并不是构成文件名的必要元素),常规的做法就是通过文件头来判断。
随便翻一下Imagemagick的代码,我就发现大多数文件格式的处理中,通常有一个函数,用来判断这个文件是否是对应的格式。
比如:
// coders/ps.c static MagickBooleanType IsPS(const unsigned char *magick,const size_t length) { if (length < 4) return(MagickFalse); if (memcmp(magick,"%!",2) == 0) return(MagickTrue); if (memcmp(magick,"