前言这里对自己简单测试过的phpok6.0的后台文件上传的功能点做个小结, 总的来说就是不安全的unzip操作, 相关漏洞均已提交至CNVD.
文件上传漏洞文件上传, 顾名思义就是上传文件的功能行为, 之所以会被发展为危害严重的漏洞, 是因为程序没有对提交的数据进行检验或者过滤不严, 导致可以直接恶意文件或者提交修改过的数据绕过扩展名的检验. 文件上传漏洞是漏洞中最为简单猖獗的利用形式, 一般只要能上传获取地址, 可执行文件被解析就可以获取系统WebShell.
文件上传漏洞的常见上传点有:
- 上传头像
- 上传相册
- 上传插件
- 上传附件
- 添加文章图片
- 前台留言资料上传
- 编辑器文件上传
- ......
随着防护手段的不断增加, 直接上传恶意PHP文件来进行getshell的概率越来愈小, 但是不安全的unzip导致的getshell问题依旧还是存在于许多的CMS当中.
漏洞点插件中心导出一个已安装的插件, 接着修改一下文件的名字以及添加恶意代码, 再本地上传插件, 访问上传后的恶意文件即可getshell.
抓包看看请求的内容: /phpok6/admin.php?c=upload&f=zip&PHPSESSION=9ff1mj7tdjnnru3uahmdfg6nh5&id=WU_FILE_0&name=shell.zip&type=application/x-zip-compressed&lastModifiedDate=Tue+Mar+15+2022+12:20:22+GMT+0800+(中国标准时间)&size=10022
在phpok框架中c是控制器, f是方法, 且相关代码都在framework文件夹下面. 因此跟进framework/admin/upload_control.php中的zip_f方法.
public function zip_f(){ $rs = $this->lib('upload')->zipfile('upfile'); if($rs['status'] != 'ok'){ $this->json($rs['error']); } $this->json($rs['filename'],true);}
可以看到zip_f方法会调用到framework/libs/upload.php中的zipfile方法, 可以看到这里只是做了filemax的检测和文件类型的检测, 接着调用_upload方法, 由于zip属于可上传文件的后缀名并且不会对压缩包中的内容做一个恶意检测, 因此可以正常上传并且解压, 恶意的PHP文件成功保存下来.
public function zipfile($input,$folder=''){ if(!$input){ return array('status'=>'error','content'=>P_Lang('未指定表单名称')); } //如果未指定存储文件夹,则使用 if(!$folder){ $folder = $this->dir_cache; } $this->cateid = 0; $this->set_dir($folder); $this->set_type('zip'); $this->cate = array('id'=>0,'filemax'=>104857600,'root'=>$folder,'folder'=>'/','filetypes'=>'zip'); if(isset($_FILES[$input])){ $rs = $this->_upload($input); }else{ $rs = $this->_save($input); } if($rs['status'] != 'ok'){ return $rs; } $rs['cate'] = $this->cate; return $rs;}
程序升级按照同样的思路, 在framework/admin文件夹中存在一个update_control文件, 其中也有zip_f方法.
在后台存在一个程序升级的功能, 其中有一个压缩包升级, 抓包查看调用的控制器和方法, 正好对应update_control文件中的zip_f方法.
按照插件中心的压缩包文件上传getshell的方法, 程序升级中的压缩包升级功能成功getshell.
模块管理依旧还是抓住zip上传的点, 找到后台的模块管理功能, 先导出一个已有模块, 发现压缩包中只有xml文件, 尝试在压缩包中加入php文件, 接着导入模块, 这里会显示导入模块失败, 请检查解压缩是否成功, 但是此时在_cache文件夹中会有解压后的文件夹, 且文件夹和文件名字不会变, 因此当目标网站_cache文件夹具有访问权限并且后台并未清空缓存时, 可以利用该点进行getshell.
抓包跟一下url, 分别为:
/phpok6/admin.php?c=upload&f=zip&PHPSESSION=cb43j0h4epcfr589foaphmk2p5&id=WU_FILE_0&name=wdnmd.zip&type=application/x-zip-compressed&lastModifiedDate=Tue+Mar+15+2022+15:23:16+GMT+0800+(中国标准时间)&size=1244 HTTP/1.1/phpok6/admin.php?c=module&f=import&zipfile=_cache/0eb054f91b4f2a92.zip&_=1647333917744
跟进framework/admin/module_control.php中的import_r方法, 可以看到虽然后面会抛出error, 但是会先解压_cache目录下的压缩包再进行判断, 因此在_cache中会保留解压后的文件内容, 故可以利用_cache中解压后的文件进行getshell.
public function import_f() { $zipfile = $this->get('zipfile'); if(!$zipfile){ $this->lib('form')->cssjs(array('form_type'=>'upload')); $this->addjs('js/webuploader/admin.upload.js'); $this->view('module_import'); } if(strpos($zipfile,'..') !== false){ $this->error(P_Lang('不支持带..上级路径')); } if(!file_exists($this->dir_root.$zipfile)){ $this->error(P_Lang('ZIP文件不存在')); } $this->lib('phpzip')->unzip($this->dir_root.$zipfile,$this->dir_cache); if(!file_exists($this->dir_cache.'module.xml')){ $this->error(P_Lang('导入模块失败,请检查解压缩是否成功')); }}
总结这里只是做了一个简单的演示, 其实相关的漏洞点还是很多的, 但是此类漏洞的利用概率很小, 毕竟前提是要拿到管理员权限登录进后台. 但是从另一方面强调了后台安全的重要性, 往往很多的建站系统只是前台做的很安全, 但是后台却一塌糊涂, 往往利用其它方式拿到管理员权限后, 配合上传压缩包来getshell是一个不错的选择.
注:如有侵权请联系删除