0x00 前言
前几天FastAdmin爆出存在低权限用户有条件RCE的漏洞,比较奇怪的是好像一直没有什么人复现。昨晚小盘师傅复现了该漏洞后给我投稿,这里感谢小盘师傅的支持。那么看一下这个漏洞到底是怎么回事叭。
0x01 漏洞原理
当开启了分片上传功能时,fastadmin 会根据传入的 chunkid ,结合硬编码后缀来命名和保存文件,攻击者可预测文件上传路径;此后攻击者提交 "分片合并" 请求时,fastadmin 将会根据传入的 chunkid ,去除了上一步操作中文件名的硬编码后保存新文件,导致任意文件上传。
0x02 前期准备
0x03 漏洞分析
该漏洞位于 application/api/controller/Common.php 下的 upload() 方法中。
主要的流程分为上传分片和合并文件两个步骤。我们先来看上传分片。
1)上传分片
根据下文的代码得知,我们需要POST传入以下参数才能调用到上传分片文件处(第25行):
跟进 chunk() 方法,发现:
其中,上面的代码 $chunkid 和 $chunkindex 是我们可控的,上传路径也是确定的。所以我们可以预测我们上传文件路径。
发送上传请求
ps:这里 chunkid 传入的是 xx.php ,这个 .php 在后面有奇效
生成文件:
2)合并文件
上传分片文件完毕后,我们来看看和分片文件相关的方法 merge() ,调用点:application/api/controller/Common.php 下的 upload() 方法(第16行):
根据上面的代码可知,我们需要传入以下POST参数:
跟进 merge() 方法,该方法代码简写如下:
上面代码 $chunkid 、 $chunkcount 是我们可控的。其中 $chunkid 和 $chunkcount 共同控制 被读取的分片文件名,$chunkid 还单独控制着 "整合文件" 的文件名
0x04 总结
在上传分片时,我们最终分片文件名为 xx.php-0.part 。而在合并分片函数 merge() 中,假设我们传入了 chunkid=xx.php & chunkcount=1 ,则 merge() 函数会读取 xx.php-0.part 的内容,并保存为 xx.php 。这样,我们便可在 runtime/chunks 下创建一个 .php 文件了。
发送请求:
虽然报错了,但是 php文件还是成功生成了
访问之,成功RCE:
0x05 修复建议
虽然该漏洞是普通用户即可通过上传造成RCE,但是其依赖于分片上传的配置项,该配置项默认不是开启的所以受影响的范围还是有限的。可以通过检查分片上传的配置项来判断自己是否受影响,如果开启分片上传则先将其关闭然后等待官方发布补丁进行更新。
关闭分片上传:
设置 application/extra/upload.php 下的chunking 项为 false