0x00 前言

gou楼兰师傅发来个站说是过不了gd库,问我有啥办法没有,给了他之前海贼师傅说的jpg_payload脚本,但是绕不过,问他拿了站点,写了个jpg_payload批量的fuzz脚本,fuzz了大半天,但都是没有成功的。

目标基础信息:

thinkphp3.2.3

php 5.4.45

使用gd库添加文字水印

0x01 转机

晚上吃饱喝足,闲来无事重新分析目标给出的报错信息,当上传了不是jpg文件的信息时候,返回如下内容。

可以知道目标使用了tp自带的图片处理类Think\image->open方法。

下个thinkphp 3.2.3源码,对比分析。

Think\image->open调用了驱动类的open方法,这里是Gd库。

跟到Gd类的open方法,可以看到这里用了getImageSize()方法来获取图像信息。

目标报错的“非法图像文件”也就是因为Gd类getImageSize()方法没有绕过导致的。

P神之前有一篇文章说到imagemagick绕过getImageSize()的方法,利用xbmp格式图像。

(参考文章:imagemagick邂逅getimagesize的那点事儿

很简单,加上这两句话再试一下,payload如下:

#define xlogo_width 200
#define xlogo_height 200
<?php phpinfo();?>

很可惜没有直接过,

目标这一次报错为”没有指定图像资源”,结合报错点为size()方法

需要this->img为空的时候才会报这个错,也就是没有初始化到。追溯看$img什么时候初始化。

可以看到$img是在open方法由imagecreatefromxxx方法或者图片为gif的时候由imagecreatefromstring方法赋值的。

这里我们传入的格式是xbm,也就是会调用imagecreatefromxbm方法来创建图片,但这里没创建成功。

0x02 突破

猜想是因为xbm格式问题,google查找xbm文件的标准格式。在维基百科上,看到xbm的标准格式如下:

当即就是复制这串东西,插入php代码,如下payload。

#define test_width 16
#define test_height 7
<?php echo 'it works';?>
static char test_bits[] = {
0x13, 0x00, 0x15, 0x00, 0x93, 0xcd, 0x55, 0xa5, 0x93, 0xc5, 0x00, 0x80,
0x00, 0x60 };

打一发,一发入魂,直接绕过。

成功getshell

简单粗暴之极,那么到底是怎么绕过的呢?

0x03 分析

后面拿到后端源码,发现源码大概长这样:

分析这段代码,通过base64编码获取到文件内容,从base64里面拿到的后缀,而后拼接后缀名写入文件,文件名是当前时间,注意后面的if判断,在写入之后添加水印,添加成功将覆盖掉原来的文件,最后返回文件存储的路径。

这段代码抛开Gd的问题,其实可以直接爆破文件名,因为文件其实已经写入了,后面报错不影响,只是没法返回路径罢了。

那么这里是怎么过的Gd的呢?

看到代码,这里先是open(),接着text()添加水印,最后save()保存图像。

open()里面需要绕过的点有getImageSize(),最后是createimagefromxxx,这两个都可以直接用xbm格式绕过。

至于text()加水印,这里怎么绕过的我没分析,啥图形处理太难了,放弃。确定一点就是在经过text()方法处理之后,xbm图片是没有变化的。

看到最后的save()方法,save方法里面调用了

imagexbm方法保存图像

分析imagexbm源码,看到gd库源码gdImageXbmCtx方法:

https://github.com/libgd/libgd/blob/gd-2.1.0/src/gd_xbm.c#L162

这段代码C写的,大概意思就是只允许特定的字符写出。

通过gdCtxPrintf方法来将内容输出到out,所以我们只需要关注这个方法里面可以输出什么就行了,通读之后可以知道内容被限制只能为标准格式,如下:

其中可以控的就是文件名了,代码会将name插入进去,name是文件名。

但是往上看一下:

做了限制,导致文件名只允许大小写字母和0-9数字,其他字符都会被转换为_

也就可以解释原本内容为

保存文件名为2.jpg

保存之后的内容是怎么来的

又经过深入分析,发现php版本不同,save方法表现也不一样。以phpstudy的几个版本为例

php版本

写入文件是否成功

5.3.29

成功

5.4.45

不成功

5.5.38

不成功

5.6.27

成功

7.0.12

成功

而且save()写入文件成功与否都不会报错。

至此,其实已经搞明白了,目标站能过的原因,就是因为php 5.4.45版本save保存不成功,但是又不报错,导致原本的内容不被覆盖,程序继续往下走,最后返回之前写入的文件路径。

倘若这里的版本换成其他的了,比如5.6或者7.0那么原文件就会被覆盖,php代码自然也写不进去。

至于为什么xbm格式可以允许php代码,imagecreatefromxbm能够创建成功呢?可以看

https://github.com/libgd/libgd/blob/gd-2.1.0/src/gd_xbm.c#L22

Gd源码gdImageCreateFromXbm 方法是怎么解析的。(代码就不截了)

我的C很烂,读了很久,大概应该是只检测标准的格式有没有,有就可以创建图像了,不管其他字符。

0x04 延伸

这只是一个特定的例子。比较常见的应该是通过$_FILES上传文件,添加水印的。如下场景:

直接open上传的临时文件,在添加了水印之后,最后save的时候才保存文件到可访问目录。

这种情况利用xbm格式就需要绕过imagexbm方法了,这个目前来看是不可能的,代码写死了,确实没办法引入php代码。

0x05 总结

算是完整记录了一下遇到的问题

总结起来就是利用xbm格式绕过getimagesize(),通过imagecreatfromxbm(),通过text()添加水印,最终在特定版本情况下,save()方法不报错,没有覆盖掉原来写入的shell,实现了伪绕过

关于gd库绕过的相关问题、场景之后可以继续分析研究,挺有意思的

记一次bypass某场景GD库及拓展分析的更多相关文章

  1. 在已经编译安装好php7场景下,install gd库 with free-type (解决Call to undefined function imagettftext())

    在已经编译安装好php7场景下,install gd库 with free-type (解决Call to undefined function   imagettftext()) install g ...

  2. php课程 8-29 gd库能够画哪些东西

    php课程 8-29 gd库能够画哪些东西 一.总结 一句话总结:文字,点,线,圆,弧线,矩形,各种形状都是可以的,和html5中的canva能画的东西很像,使用也很像,参数怎么记呢,参数完全不用记, ...

  3. 一起学习PHP中GD库的使用(二)

    在日常的开发过程中,GD 库最常用的功能就是帮我们对图片进行一些处理,当然,除了处理已有的图片之外,它也可以直接来画图,就像我们最常见的图片验证码.今天的内容主要就是和画图有关,所以最后我们也会做一个 ...

  4. PHP的GD库

    GD库 PHP通过GD库,可以对JPG.PNG.GIF.SWF等图片进行处理.GD库常用在图片加水印,验证码生成等方面. 绘制线条 要对图形进行操作,首先要新建一个画布,通过imagecreatetr ...

  5. gd库

    1.开启GD库扩展 去掉注释: extension=php_gd2.dll extension_dir='ext目录所在位置' 2.检测GD库是否开启 phpinfo(); //检测扩展是够开启 ex ...

  6. 已安装php 编译安装 gd库拓展模块

    参考资料:http://wenku.baidu.com/link?url=EgXFShYxeJOZSYNQ_7RCBC-6X8OcRRCqVm4qCv49uBk57d6vLBoUpfYdQ-KqJRs ...

  7. Mac php使用gd库出错 Call to undefined function imagettftext()

    第一次在Mac下使用ThinkPHP,用到验证码功能时报如题的错误: Call to undefined function Think\imagettftext() 然后检查自己的GD库,发现安装上了 ...

  8. GD库处理图像

    在PHP5中,动态图象的处理要比以前容易得多.PHP5在php.ini文件中包含了GD扩展包,只需去掉GD扩展包的相应注释就可以正常使用了.PHP5包含的GD库正是升级的GD2库,其中包含支持真彩图像 ...

  9. 烂泥:centos单独编译安装gd库

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 这几天一直在弄一个商城系统,该系统的源码及数据库都已经上传并创建完毕.但是在安装该系统时,却提示缺少gd库.如下: 使用php探针查看,发现php确实没 ...

随机推荐

  1. 基于Broadcast 状态的Flink Etl Demo

    接上文: [翻译]The Broadcast State Pattern(广播状态) 最近尝试了一下Flink 的 Broadcase 功能,在Etl,流表关联场景非常适用:一个流数据量大,一个流数据 ...

  2. AI佳作解读系列(六) - 生成对抗网络(GAN)综述精华

    注:本文来自机器之心的PaperWeekly系列:万字综述之生成对抗网络(GAN),如有侵权,请联系删除,谢谢! 前阵子学习 GAN 的过程发现现在的 GAN 综述文章大都是 2016 年 Ian G ...

  3. 比较oracle表字段是否一致

    SELECT M.OWNER ,M.TABLE_NAME ,M.COLUMN_ID ,M.COLUMN_NAME ,M.DATA_TYPE ,M.DATA_LENGTH ,N.OWNER ,N.TAB ...

  4. 用easymock来mock数据

    昨天学习微信小程序了解了一个模拟数据的工具EasyMock,一早到公司就使用试试. 1.创建项目: 创建好如下所示: 2.创建接口: 点击右下角+号按钮即可. 操作栏依次是:预览,编辑,链接,更多操作 ...

  5. webpack 安装vue(两种代码模式compiler 和runtime)

    使用webpack安装vue,import之后,运营项目报错,如下: [Vue warn]: You are using the runtime-only build of Vue where the ...

  6. 【GStreamer开发】GStreamer播放教程08——视频解码的硬件加速

    目标 视频的硬件解码近来发展非常快速,尤其是在低功耗的设备上.本教程会讲述一些硬件加速的背景知识并解释一下GStreamer是怎么做的. 悄悄告诉你,如果设置正确地话,我们什么也不用做,GStream ...

  7. centos 用户组操作

    adduser testuser //新建testuser 用户 passwd testuser //给testuser 用户设置密码 useradd -g testgroup testuser // ...

  8. Quartz.Net—基本操作

    Quratz基本架构 Scheduler基本操作 /// <summary> /// 调度器信息 /// </summary> /// <returns></ ...

  9. Zuul【工作原理】

    zuul的核心逻辑都是由一系列filter过滤器链实现的,但是filter的类型不同,执行的时机也不同,效果自然也不一样,主要特点如下: filter的类型:filter的类型,决定了它在整个filt ...

  10. 批量删除c文件和h文件中的注释

    不知道大家有没有批量删除c文件和h文件中注释的需要,说起来搞笑,偶然翻出来早先写的一份,首先楼猪不是闲的蛋疼写这东西,工作需要,哪里要砖就要搬.冷门的东西大家需要的时候也不一定好找,分享给大家,省的自 ...