原创干货 | File Upload关于图片马的思考

  • A+
所属分类:安全文章
原创干货 | File Upload关于图片马的思考
点击关注了解更多精彩内容!!

 

 

原创干货 | File Upload关于图片马的思考
相关背景
原创干货 | File Upload关于图片马的思考
 
在一次Java代码审计中,发现某业务系统进行文件上传业务时,使用了如下的方式进行文件上传的后缀检查
原创干货 | File Upload关于图片马的思考

原创干货 | File Upload关于图片马的思考

其中FileTypeUtil是hutool(Hutool是一个小而全的Java工具类库)下的一个工具类,通过其FileTypeUtil.getType()方法获取到当前上传文件的后缀,然后进行后缀检查,若非图片类型则认为恶意上传操作。

原创干货 | File Upload关于图片马的思考
相关分析
原创干货 | File Upload关于图片马的思考

一般来说常见的后缀名检查都是直接获取当前上传文件名,然后字符串截取对应的后缀进行比对检查。这里直接通过一个File对象即可获取,那么到底Hutool的FileTypeUtil的getType方法底层实现是怎样的,有没有可能存在不完善的机制呢,这里下载了一个Hutool的jar进行查看:

原创干货 | File Upload关于图片马的思考

直接定位FileTypeUtil的getType方法:
可以看到重载了多个getType函数,分别可以传入的参数类型为String、InputStream和File:
原创干货 | File Upload关于图片马的思考
查看第一个函数:
原创干货 | File Upload关于图片马的思考
主要将fileStreamHexHead是与fileTypeMap里的内容进行比对,fileTypeMap的内容如下:
原创干货 | File Upload关于图片马的思考

也就是说,这个类是通过读取文件流中前N个byte值来判断文件类型,在类中我们通过Map形式将常用的文件类型做了映射,例如常用的图片、音频、视频、Office文档类型。既然是通过文件流中的前N个byte值来判断,考虑保留对应的字节内容后再加入Webshell的内容,然后在上传时成功获取到对应的byte值并且成功认为恶意的文件为图片,并且上传成功,即可绕过防御。

这里搭建一个简易的环境进行漏洞验证,简单的检测代码如下:
原创干货 | File Upload关于图片马的思考

同样的还是使用Hutool的FileTypeUtil的getType方法获取当前上传的文件后缀,然后进行合法性检测。

当前的效果如下:
原创干货 | File Upload关于图片马的思考
上传恶意的jsp文件的话是拒绝上传的:
原创干货 | File Upload关于图片马的思考
因为是通过读取文件流中前N个byte值来判断文件类型,所以这里我们尝试把一张图片的后缀改成jsp也是可以上传的:
原创干货 | File Upload关于图片马的思考
那么可否绕过对应的检测机制,上传我们恶意的jsp文件呢?

这里只需要在上传文件的字节流的头部,写入对应的hex值,即可绕过对应的安全检测了,这里以bmp的hex头为例,直接在burp我们的webshell中写入对应的bmp的hex头:

原创干货 | File Upload关于图片马的思考
再次重放我们的数据包,成功绕过安全检测上传webshell:
原创干货 | File Upload关于图片马的思考
尝试访问webshell,也是可以成功解析的:

原创干货 | File Upload关于图片马的思考

原创干货 | File Upload关于图片马的思考
拓展
原创干货 | File Upload关于图片马的思考

除了上述场景以外,还见过不检查文件后缀,直接通过生成文件的Image对象,判断Image对象是否为null、Image对象的属性(例如像素、图片的长宽)合法性进行判断,样例代码如下:
原创干货 | File Upload关于图片马的思考
有趣的是ImageIO.read方法的实现也是通过读取文件流中前N个byte值来进行判断的,那么可以同样可以考虑保留对应的字节内容后再加入Webshell的内容,然后在上传时成功获取到对应的元素属性,并且上传成功(这里是图片的长宽),即可绕过防御。
同样的这里也搭建环境进行尝试,正常情况上传jsp文件返回如下:
原创干货 | File Upload关于图片马的思考
以bmp文件为例,先找一个bmp图片查看它的文件内容:
图像的部分信息如下,按照刚刚的思路,我们要找到对应元素属性的位置(这里是图片的宽和高):
原创干货 | File Upload关于图片马的思考
首先是bmp头,既然要得到对应的元素属性,那么肯定要知道该文件是什么样的文件类型,所以bmp头也很重要:
原创干货 | File Upload关于图片马的思考
以下数据就是bmp文件头:
原创干货 | File Upload关于图片马的思考
以小端字节序来解读:
原创干货 | File Upload关于图片马的思考
再往下就是我们关键的元素信息了(图片宽、高),也就是位图信息头:
原创干货 | File Upload关于图片马的思考
到这里就得到我们绕过的关键信息了,同样的以小端字节序来解读:
原创干货 | File Upload关于图片马的思考
原创干货 | File Upload关于图片马的思考
到这里就可以进行绕过的图片码的制作了:
保留想要的关键信息,以特定的方式写Webshell:
原创干货 | File Upload关于图片马的思考
成功上传webshell:
原创干货 | File Upload关于图片马的思考
在后台也可以看到当前上传的jsp文件是可以获取到图片的“宽”和“高”的:

原创干货 | File Upload关于图片马的思考

原创干货 | File Upload关于图片马的思考
思考
原创干货 | File Upload关于图片马的思考
 

在文件上传时,有时候我们需要判断文件类型。可能在系统开发阶段已经考虑到了图片马的上传,于是我们需要在服务端通过读取文件的首部几个二进制位来判断常用的文件类型,但是并不是说这种方式就万无一失了,反而最简单的后缀名截断,检查在特定的场景更好用。所以在开发阶段还是应该多种方式结合,例如白名单、图片二次渲染等。

同时很多现有的api,在进行调用的时候也应该看看具体的底层实现,避免潜在的风险。

 

 

原创文章未经授权禁止转载,谢谢合作

·END·

云众可信
原创·干货·一起玩

微信号:yunzhongkexin

 

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: