远程图像上传导致的RCE
在目标Web应用中,有两种方法可以将图像添加到媒体库中,一种是使用本地文件上传,另一种是通过存储图片的网站进行远程文件上传。
我首先想到的是,通过远程文件上传功能可能存在SSRF漏洞。但是我还是首先测试了本地文件上传是否有问题。
经过几次对本地文件上传的测试,我发现,应用只允许上传图像文件(.jpg,.png,.gif和.svg),其中.svg
格式的文件可能导致XSS。
接着我开始研究从存储图片网站远程上传文件的功能,尝试添加一个图像分析其中的请求。我发现在POST数据包中有3个form-data
数据,分别涉及发送到服务器的name,url和photoId。
我试图改变联通到我的服务器的Url,但得到内部服务器响应错误,我的服务器没有接收到任何传入连接。然后我试图删除PhotoId
,并再次发起请求,但还是得到了内部服务器错误响应,不过这次我的服务器看到了传入的连接。由于我指定的Url并不是一个有效的图像文件,所以这确实会导致内部服务器错误。
随后我尝试提供一个有效的jpg图像文件的url,也成功上传到媒体库。然后再次上传相同的图像文件,并将“name”这一项form-data数据分别修改为image.html
和image.php
,令人惊讶的是它们都成功上传了。
经过一段时间的研究,我意识到并不能把php脚本注入到图像的exif元数据中,因为目标应用会使用PHP-GD
库重新创建远程获取的图像文件,而在重新创建后,exif元数据都将被删除。
随后我也发现有几篇文章告诉我们有在图像处理后不会被删除代码的方法。
https://github.com/fakhrizulkifli/Defeating-PHP-GD-imagecreatefromjpeg
https://github.com/fakhrizulkifli/Defeating-PHP-GD-imagecreatefromgif
https://secgeek.net/bookfresh-vulnerability/
根据上述文章,我们仍然可以将php脚本注入到图像中,但是只能使用有限的字符。
此外还有dlegs创建的payload注入器。
https://github.com/dlegs/php-jpeg-injector
在第一次测试时,我尝试使用dlegs工具将payload注入到.jpg
图像中。你需要首先使用php-gd重新创建.jpg
图像,然后使用gd-jpeg.py
注入payload。
$ php gd.php image.jpg image-gd.jpg
然后将payload注入image-gd.jpg
$ python gd-jpeg.py image-gd.jpg ‘<?php phpinfo()?>’ image-gd-poc.jpg
为了确保注入的payload1能工作,请尝试使用php-gd重新创建image-gd-poc.jpg
。
$ php gd.php image-gd-poc.jpg image-gd-poc-1.jpg
然后比较图像image-gd-poc.jpg
和image-gd-poc-1.jpg
。
我在这使用了vbindiff
。
$ vbindiff image-gd-poc.jpg image-gd-poc-1.jpg
dlegs编写的注射器确实可以将payload注入到一个.jpg
图像文件中,而且不会被二次渲染破坏。然而,在我的目标应用中,它转换的图像质量有变化,所以payload还是会被删除。
第一次尝试.jpg图像失败,所以接下来我尝试使用@ABOUL3LA
的paylaod与.gif图像文件。在他的文章中,提供了已注入payload的poc.gif图像(<?phpinfo()?>)。
最后,我上传了poc.gif(将form-data的“name”重命名为test.php),以下是结果。
如果你想使用@ABOUL3LA的POC.gif,目标应用的php.ini
必须有short_open_tag=On
,否则php脚本将无法执行(其中涉及<?php ?>标签)。
在把这个报告给漏洞悬赏项目后,几分钟内就得到了分类反馈,几小时内就做出了快速修补。
漏洞测试虽然已经结束,但我想进一步研究php-gd
库,想确认我们到底可以向图像注入多少字节。在对不同的.jpg和.gif图像进行多次测试之后,我发现,.jpg图像可以注入最多13个字节的payload,而.gif图像可以注入更多的字节。
而可以被注入的GIF图像是具有空字节块的GIF图像。我发现Netscape循环应用程序扩展(Netscape Looping Application Extension)的GIF图像存在这种空字节块。
Netscape Looping Application Extension
是最流行的应用扩展块,它会告诉浏览器或其他GIF查看器去循环整个动画(http://www.vurdalakov.net/misc/gif/netscape-looping-application-extension)。
以下是一个示例GIF图像:
https://media2.giphy.com/media/6NjZoOdEbXs1W/source.gif
如果我们用php-gd重新创建这种特殊的GIF图像,空字节块并不会被删除。以下是原始gif和gd处理后的gif之间的二进制比较。
现在,让我们尝试将php的shellcode注入到空字节块,再用PHP-GD进行处理,二进制对比如下:
你可以发现,被注入的payload保持不变,此时你就可以上传gif图像到你的目标应用中。
相关该工具和脚本如下:
https://gist.github.com/asdqwe3124/e63eba35dc8e6976af97f1a9348b277b
感谢你的阅读。
本文由白帽汇整理并翻译,不代表白帽汇任何观点和立场
来源:https://medium.com/@asdqwedev/remote-image-upload-leads-to-rce-inject-malicious-code-to-php-gd-image-90e1e8b2aada
最新评论