一、漏洞简介
2020年1月10日,ThinkPHP团队发布一个补丁更新,修复了一处由不安全的SessionId导致的任意文件操作漏洞。该漏洞允许攻击者在目标环境启用session的条件下创建任意文件以及删除任意文件,在特定情况下还可以getshell。
攻击者可利用此漏洞构造恶意的数据报文,向服务器写入任意内容的文件,从而能够达到远程代码执行.
二、影响范围
ThinkPHP6.0.0
ThinkPHP6.0.1
三、环境搭建
使用ThinkPHP6.0.0版本搭建,利用中间件phpstudy运行搭建的网站,
四、漏洞复现
利用条件:
在目标环境为Windows且开启session的情况下,容易遭受任意文件删除攻击。
在目标环境开启session且写入的session可控的情况下,容易遭受任意文件写入攻击。
修改/app/controller/Index.php 文件
增加下面这段代码:
修改 /app/middleware.php 文件如下
使用burp构造数据报文如下:
默认在目标/ runtime/session文件夹下生成如下文件
写入的文件内容
拼接URL地址:
替换payload获取webshell
获取webshell
五、漏洞分析
根据官方github的commit推测,可能是在存储session时导致的文件写入。然后,跟踪:vendor/topthink/framework/src/think/session/Store.php
public function save(): void
这里调用了一个write函数,跟进一下:vendor/topthink/framework/src/think/session/driver/File.php
调用writeFile函数,跟入:
写入文件的操作。
继续看一下文件名是否可控,该文件名来自于最开始的getId()得到的$sessionId的值。看一下函数内容:
在 session 初始化时,程序会将 PHPSESSID 对应的值赋值给 \think\session\Store:id 。这里如果 PHPSESSID 对应值长度等于32,则无任何过滤直接赋值,看一下调用setId的地方:vendor/topthink/framework/src/think/middleware/SessionInit.php:46。
然后在程序构造响应数据返回给用户时,会先将 session 写入文件,而这个文件的文件名则由之前的 PHPSESSID 拼接而成。由于没有任何的过滤,这也就造成了任意文件创建、覆盖。在session 数据可控的情况下,可以达到 getshell 的目的
六、漏洞修复
目前官网已经更新了thinkphp6.0.2版本,修复了该漏洞,建议尽快升级最新版本。