前段时间写的文章,在微博上说7月底结束分享一下,总算可以发了。感谢 @voidfyoo 提出的这个问题。
今天遇到一个代码,大致如下:
$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这样的图片格式。
这时候我们怎么绕过这个限制呢?
0×01 Imagemagick命令执行不完全回顾
Imagemagick历史上曾出现过的很多命令执行漏洞,我在vulhub里做过以下三个:
1.CVE-2016-3714
2.CVE-2018-16509
3.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,"\004%!",3)==0)
return(MagickTrue);
return(MagickFalse);
}
// coders/mvg.c
static MagickBooleanType IsMVG(const unsigned char *magick,const size_t length)
{
if (length 20)
return(MagickFalse);
if (LocaleNCompare((const char *) magick,"push graphic-context",20)==0)
return(MagickTrue);
return(MagickFalse);
}
这两个函数就是判断文件是否是postscript和mvg格式。很显然,他这里是通过文件头来判断,也就是说,如果想让Imagemagick用ps的处理 *** 来处理图片,这个图片的前几个字节必须是%!或\004%!。
这也很好理解,文件头的意义就是标示这个文件是什么类型的文件。
所以,如果我们想利用Imagemagick的命令执行漏洞,必须要给他传入一个合法的mvg或ps文件,或者至少文件头要满足要求。
0×02 深入getimagesize
通过翻阅PHP文档,可知getimagesize支持的图片类型有:GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM,WBMP:
那么这时候就犯难了,ps和mvg并不在其中。如果我们传入一个ps文件,getimagesize处理时就会失败并返回false,那么就不会执行到Imagick那里。这种 *** 也是当初ImageTragick漏洞出现时,很多文章推荐的缓解措施。
似乎很安全,不过我们应该深入研究一下getimagesize究竟是如何处理图片的。
下载php源码,ext/standard/image.c这个文件是关键,看到如下函数:
static void php_getimagesize_from_stream(php_stream *stream, zval *info, INTERNAL_FUNCTION_PARAMETERS)
{
int itype=0;
struct gfxinfo *result=NULL;
if (!stream) {
RETURN_FALSE;
}
itype=php_getimagetype(stream, NULL);
switch( itype) {
case IMAGE_FILETYPE_GIF:
result=php_handle_gif(stream);
break;
case IMAGE_FILETYPE_JPEG:
//...
case ...
可见,这里逻辑是首先用php_getimagetype(stream, NULL)来获取图片格式,然后进入一个switch语句,根据格式来分配具体的处理 *** 。
看看PHP是如何获取图片格式的:
PHPAPI int php_getimagetype(php_stream * stream, char *filetype)
{
char tmp[12];
int twelve_bytes_read;
if ( !filetype) filetype=tmp;
if((php_stream_read(stream, filetype, 3)) !=3) {
php_error_docref(NULL, E_NOTICE, "Read error!");
return IMAGE_FILETYPE_UNKNOWN;
失信行为“箩筐化”之忧 信用惩戒泛化乱象调查 本报记者王珏玢、潘晔 继去年“献血加信用分”引起热议后,今年疫情防控期间,信用管理话题再刷一波存在感。 记者梳理“信用中国”网站发现,多地出台规定...
一、电脑黑客接单流程 1、微信接单黑客黑客术语的基础主要是找出一些常用的黑客术语,比如注入什么意思,以及一些常用的工具,如NCSC等等。电脑教程软件下载上午79天的高峰时间是对客户习惯的分析。微信电脑...
怎么用手机控制别人的摄像头呢? 以iPhone11,IOS13系统为例,在手机上查看家中监控画面的方法大致分为四个步骤,具体的操作步骤如下所示:首先打开手机,然后点击打开浏览器。根据监控系统的品牌,下...
如何悄悄接受丈夫手机微信(同歩手机微信不被发觉),当今,腾迅游戏支撑点微号灯和QQ号果断登陆。用微号灯登陆手机游戏后,手机游戏管理体系会积极将一样在打...
王者荣耀五五守护星收集活动终于在今天(4月29日)开启了,上周各位玩家无法弄到这个道具是因为还没有开放,而收集五五守护星是为了兑换活动专属皮肤-盾山圆桌骑士,现在就给大家详细分享下五五守护星收集方法...
相信现在有很多的朋友们对于根雕家具的特点是什么都想要了解吧,那么今天小编就来给大家针对根雕家具的特点是什么进行一个介绍吧,希望小编介绍的内容能够为大家起到帮助哦 根雕家具十分的难,可是也恰恰因为我们在...