FastAdminv1.0.0.20200506_beta前台GetShell复现
环境准备
https://gitee.com/karson/fastadmin/tree/v1.0.0.20200506_beta #源码地址
1 | #下载源码 |
环境准备完毕后显示自动生成了后台地址以及用户名密码。
最后,在phpstudy中配置fastadmin的网页根目录为public,并且官方要求PHP版本大于 7.1 且 小于7.3,Mysql大于等于5.5.0(需要支持innodb引擎)。
环境搭建OK:
记录我环境配置出现的问题:
1、在官方文档中Windows下PHPStudy安装fastadmin的教程中有一步是重写伪静态规则(.htaccess),按照教程的填写内容错误,修改为官方git中的内容才正确。
2、PHPStudy中创建网站,也就是上面最后一步增加网页域名根目录映射后,由于其中静态规则的设置,会重写public下的.htaccess,如果为空,则直接将源码中原来的.htaccess置空,这直接导致我的网站运行错误,同1,.htaccess修改为官方源码中的即可。
漏洞原理
原理看博客把,看完后下面会对POC有一定的解释。https://www.cnblogs.com/sevck/p/13723094.html
漏洞复现
1、个人资料处上传图片马
2、POC
这里我提供两个POC,原理是一样的,首先你要找到触发漏洞的controller点:_empty,这个函数默认在index这个application下的User.php中。这也是thinkphp访问url资源的方式:application/控制器名/函数,所以只要找到index/user/_empty就可以触发这个漏洞。
另外_empty函数漏洞的主要原因是用户传入了一个可控的路径参数被模板渲染函数所解析,fetch函数就是ThinkPHP中渲染模板的函数,它支持执行带有php标签的代码。
fetch函数的内部结构是首先通过了一个is_file()函数的判断,才真正去解析执行这个模板。在linux和windows下对于is_file函数的执行结果反应不同。比如在C:\\Users\\18265\\信息.txt
有这样一个文件,var_dump(is_file("C:\\abc\\..\\Users\\18265\\信息.txt"));
的结果会是true,Windows下不管你目录遍历了多少,只要最终找到目标文件的逻辑正确,就是true。而Linux下,目录遍历中只要有一个处写错误了,比如说不存在这个abc文件夹,会直接判断为false。
因此,再看看_empty漏洞点的内容,它使用fetch解析的模板文件路径是’user/‘+我们传入可控的参数的拼接结果,因为在当前工作目录public下不存在user这个文件夹,所以在linux中永远是false无法触发漏洞(除非你可以做到创建一个user文件夹在public下),window下逻辑绕过即可。
我们上传文件的文件夹upload就在public/uploads中,所以网上最多的POC是一种办法,直接user/../uploads/…又是一种办法。
1 | http://www.fa.com/index.php/index/user/_empty?name=/../../public/uploads/20201103/c23021b03d3b155f3f6d5d23af52a30e.gif #网上流传版本 |
3、坑点:此处图片马有可能因为图片本身的格式导致执行错误!
这里一开始我使用了我一直用的图片马,发现在触发漏洞时一直失败,踩了一上午的坑。最后想到在application/config.php中将app_debug的值赋值为true,来开启ThinkPHP的Debug模式。发现其实payload是正确的!报出的是一个ThrowableError的错误。
这里应该是执行错误后,把错误执行的代码内容存储到了fastadmin缓存文件夹中,来查看这个报错的php文件对应行数,发现乱码中出现了一些有实际意义但逻辑错误的符号字符等,这真的是一个小坑。所以我后来换了一个最简单的GIF头的图片马,成功复现漏洞。
漏洞修复
1 | public function _empty($name) |
增加一条正则过滤。
渗透测试时的一点小trick
对于渗透测试时遇到的一些常见CMS、框架,想利用其某些文件上传或者解析漏洞却发现前端没有上传点,那么我们可以自己重写DOM去上传,因为后端虽然没有在前端使用这个上传功能,但不一定删除了后端对应的上传接口。这一点也可以通过访问接口来测试。测试存在该接口,直接写个上传点即可。
1 | <form action="http://pay.yuntevip.com/index/ajax/upload" method="post" enctype="multipart/form-data"><input type="file" name="file" /><input type="submit" name="submit"></form> |