巨献娱乐代码审计 xxxdisk前台Getshell_HUC惠仲娱乐

巨献娱乐

0x0 xxxdisk

XXXDISK网盘系统[简称:XXXDISK],是国内最大的网络存储、云存储系统开发及服务提供商,长期专注于网络存储系统开发,是一套采用PHP和MySQL构建的网络硬盘(文件存储管理)系统,可替代传统的FTP文件管理。友好的界面,操作的便捷深受用户的欢迎。

她是一套可用于网络上文件办公、共享、传递、查看的多用户文件存储系统。广泛应用于互联网、公司、网吧、学校等地管理及使用文件,多方式的共享权限,全方位的后台管理,满足从个人到企业各方面应用的需求。
最新版的下载地址为:
http://bbs1.phpdisk.com/thread-5384-1-1.html

0x1 起步

之所以审计这套系统,是因为学校用的就是这个,在用历史漏洞拿下之后,学校给打上了补丁。但是,后来看着乌云上雨师傅、P牛等都审计出不少洞,想着如果我也审计出几个洞,是不是也能在几年之后变得那么强。于是就杠上了这套系统了。最后,在Windows平台的GBK版本上,挖掘到了一个无需登录的前台Getshell。

至于如何查看是啥版本,查看返回包的charset就行了。这里不多说,具体的瞅一眼代码就行。

0x2 Windows文件上传绕过

本系统默认情况下的所有限制后缀都是通过黑名单的,此前也缝缝补补过好几个任意文件上传漏洞,但是作者忽略了或者说根本不了解Windows下的NTFS ADS流的trick。来看看此程序上传部分的逻辑。

所有文件上传操作都被封装在upload_file函数中。

看看有哪些文件上传的地方:

总共有两处调用:第一处就是网站核心功能的文件上传,而第二处是给C/S客户端使用的,但是由于之前此处出现过很多次文件上传问题,已经被处理的没有办法使用了。
具体问题就是,默认此功能被修改成关闭了,原来雨牛挖掘的绕过签名,已经没办法使用了:

elseif(!$settings[open_phpdisk_client]){         $str = '总之就是没办法用了';         if(is_utf8()){             echo convert_str('utf-8','gbk',$str);         }else{             echo $str;         }         exit;

所以我们来看看第一处的文件上传, 位于modules/upload.inc.php

使用get_real_ext函数处理了后缀。

get_real_ext通过黑名单filter_extension对后缀进行修改添加.txt防止解析。
此处很明显可以绕过,如果我们控制文件名为1.php:$data的话就可以绕过此处限制了。
不过此处还存在两个需要解决的问题,一个就是文件真实名称是强随机生成的,以及需要找到无需登录的上传利用点。

0x3 权限绕过

此程序为网盘程序,所以自然而然的需要用户登录才能上传。但是,来看看程序逻辑mydisk.php

需要经过phpdisk_core::user_login();,才能包含upload模块,上传文件。
我们来看看这个类方法的逻辑。

居然认证没通过只是302,并没有exit,所以此处可以无授权访问上传功能。

0x4 未授权上传

组合起来利用,构造文件上传包:

可以看到成功上传了。

但是还需要解决获取真实文件名的问题。这里有三种思路:

  • 找到sql注入,注入出真实文件名
  • 删除index.htm,达成目录遍历
  • 使用Windows下的部分PHP函数的正则匹配(案例:DEDECMS寻找后台)

我太菜了,这里只找到了几个sql注入,后面两种都没有实现。

0x5 宽字节注入若干

此程序分为两个版本utf-8与gbk版,所以难免会有一些编码转换的地方,所以也难免发生不小心没有注意的地方。这里封装了一个编码转换的函数convert_str,大多数编码转换都是使用使用的这个函数,但是这里都做了多次转义。搜索一下iconv,会找到几处宽字节注入的。有一个是在UTF-8版本下的,但是位于客户端部分,需要开启了客户端才行。。。所以这里也限制了缺省条件下必须使用GBK版本。

这里利用的是位于ajax.php的一处宽字节注入:

由于这个系统有全局过滤,所以想找到注入还是比较困难的,这里存在一个$file = unserialize(base64_decode($data));$data是我们输入的,绕过了过滤。
将我们的输入base64解码后,反序列化成数组对象,最后传入sql语句。
$db->query_unbuffered(is_utf8() ? $sql : iconv('utf-8','gbk',$sql));
最后执行语句的时候存在一处编码转换,也是这里直接导致了注入。

并且是个比较好的利用点,这里是insert语句,存在回显,不用写脚本盲注。

0x6 最终利用

最后,我们将这几个串联起来,就成了一个无需登录的Getshell,整条漏洞利用链为:

  1. 上传文件

  1. 通过注入获取文件真实名称(其实也能直接注入获取管理员密码(md5),然后把黑名单修改一下)
    这里需要注意的是,为了获取回显,需要在insert中将文件属性in_share设置为1,这样就能未授权访问文件相关信息了。并且需要挑选足够合适的回显位。

    除了file_name以及file_description两个字段,其他字段长度都是不够存放回显的。这里我使用file_name作为注入点,一开始偷懒想直接使用mysql的强制类型转换(select ''+hex((select user))),把hex数据取出的,但是长度过长,精度丢失了...所以老老实实用file_description传出数据吧。
    payload:

注入成功

  1. 获取回显
    注入成功后,就需要想办法获取回显了,想要查看文件信息,需要获取文件ID。

    这里其实如果你有账号的话(默认有测试账号并且允许注册),可以自己上传一个文件获取file_id,然后减1就是上个文件的file_id了。不过这里我们是无账号的前提条件,所以可以通过爆破,也挺快的。通过最近上传获取到位置靠后的文件,然后爆破一下file_id就行了。

    最后找到了正确的文件id,访问即可在访问处获取真实文件名了。

  2. getshell

结语

最后这个程序已经停止更新维护了,所以发出来仅供学习参考。审计了几天,有点疲软,最后学校的那套系统不知道什么毛病,数据库一直报错,也没能利用成功2333。