一、先展示效果
官方demo站地址:http://**.**.**.**
可直接下载C:\windows\win.ini文件
直接下载管理用户的配置,内含账号和口令hash哦
目录文件直接列出来,点下载按钮可以直接下载的。由于会列出子目录中的内容,所以尽量不要列太高层的目录哈,不然会卡很久甚至卡死的。
二、挖掘过程
从上面的例子大家也已经看到了,存在问题的文件是viewsharenetdisk.php,该文件位于www目录下。
首先试了下,可以直接访问,我们再来一步一步看看需要什么参数,以及参数都有什么要求。
可以看到,$userid不能为空,且load_userinfo($userid)的结果不能为false,这就需要一个确定存在的用户,还好系统有个默认用户postmaster。就算这个用户被禁用了,想找到一个有效的用户还是比较容易的。
$domain为$userid的@后面部分或者为空,这样就确定了url中应该有userid=postmaster@**.**.**.**,后来经过测试发现$domain为空时load_domaininfo($domain)会获取主域名的值,所以可以简化一下userid=postermaster。
页面的结果有些变化了,接着往下看
文件名不为空的话,将空格替换为+,然后base64解码,看来文件名参数应该是base64格式的了
有两个判断,里面各种exit,这个地方过不去的话就没办法继续往下走了,一下子紧张起来,在这里花费不少时间。
先看第一判断,最后一句是$bAttach = true;能到这一步,第二个判断就不用进去了,第二个代码那么长,里面还各种password,我当然不想进去了。
于是凑条件,$chksum不能为空,还得等于md5($userid.'|'.$filename.'|'.$start),然后$nowtime - $start还不能大于$netdisk_share_expire,就是现在的时间减去文件开始共享的时间,不能大于文件共享的有效期,好复杂,还好这里的$start可以控制,那么尽量让$nowtime - $start无限小就好了,这样$userid、$filename、$start基本都确定了,md5值也可以计算出来了,这个判断就算绕过了,不过好麻烦啊,每改一次文件名都得重新计算下md5.
事实证明,这里的确是把事情弄复杂了,挖掘完漏洞回过头来看这里的时候,发现第二个判断里面$share = $ftp->GetShare();获取用户的共享信息,如果没有共享的话,$share['enddate']、$share['user']、$share['password']都会是空,所以下面的两个子判断就直接跳过去了。
postmaster是默认用户,应该不会有人去用这个用户共享什么内容吧,所以这里的两个判断实际上无需理会。
接着往下走,就到了处理操作的部分了。
$filename经过base64解密后,传到这里,并没有经过任何过滤,就赋值给了$ftpfile,而$ftpfile也没有经过任何过滤就拼接出了$localfile并传给了fopen函数,至此这个漏洞的真正成因弄清楚了。利用可以切换到上级目录的../,并结合文件的具体路径,经过base64编码后作为参数传入就可以下载任意指定文件了。
到这里本应该结束了,但是这样每查看一个文件都要进行编码好累啊,我又不会写脚本。想着应该不会这么费事的,下面还有个opt操作数,接着往下看吧。
先看else下面的部分,$ftp->GetAllShareFile();postmaster没有共享内容,所以这里获取不到任何东西。就剩下$ftphandle->get_folder_file($filename);这里了。
这个函数位于/inc/class.ftpfolder.php文件中,可以看到只要传进来的参数是目录名,一样可以处理的。
好了,分析结束,心情有点激动,废话有点多,大家见谅。