无题
php序列化和反序列化
php访问修饰符:
可访问性 | public | protected | private |
---|---|---|---|
类自身 | √ | √ | √ |
类外部 | √ | × | × |
子类 | √ | √ | × |
注释:在PHP类中不写访问修饰符默认的访问权限为public
什么是序列化?
序列化是指将数据结构或对象转换为一串字节流的过程。使其可以在存储、传输或缓存时进行持久化。
什么是反序列化?
反序列化是指将序列化后的数据进行解码和还原,恢复为原始的数据结构或对象的过程。反序列化是序列化的逆过程。
在 PHP 中,使用 serialize() 函数可以将数据结构或对象进行序列化,得到一个表示序列化后数据的字符串。通过 unserialize() 函数可以将这个字符串进行反序列化,将其还原为原始的数据。
php对象的序列化:
O:长度:“类名”:变量数:{变量类型:变量名长度:“变量名字”;变量的值;}
例如:
1 | O:6:"people":2:{s:4:"name";s:4:"lili";s:3:"age";i:18;} |
注意:对象的方法不会显示在序列化中
PHP数组反序列化
PHP关联数组的序列化和反序列化
var_dump和print_r的区别:
var_dump输出的更为详细,有属性数量,类型等等,而print_r更为简单
PHP魔术方法
定义:PHP的魔术方法(Magic Methods)是一组特殊的方法,以双下划线(__)开头和结束命名的。它们在对象的生命周期中被自动调用,用于执行特定的操作。这些魔术方法可以让开发者更好地控制和定制对象的行为。
16个常用的函数方法
1 | __construct(), 类的构造函数,创建对象时进行初始化操作 |
函数 | __construct() | __destruct() | __call() | __callStatic() | __get() | __set() | __isset() | __unset() |
---|---|---|---|---|---|---|---|---|
调用时机 | 创建对象时 | 被销毁时 | 调用无法调用的方法时 | 调用无法调用的静态方法时 | 访问无法查看的属性时 | 设置无法设置的属性时 | 检查无法检查的属性时 | unset() 函数尝试删除不可删除属性时自动触发 |
传递参数 | 自定义 | 不可设置 | 方法名,参数数组 | 方法名,数组 | 属性名 | 属性名,属性值 | 属性名 | 被销毁属性名称 |
返回值 | 无要求 | 无 | 自定义 | 自定义 | 自定义 | 无 | 布尔值 | 无 |
pop链构造与技巧
pop链介绍
pop链就是利用了PHP中对象的自动调用魔术方法特性,将多个类和方法串联起来,形成一个链式调用。当PHP反序列化时,会自动调用这些方法,触发代码执行。
pop链构造技巧
1.简单浏览:找出可能的漏洞点。多去注意一写容易触发漏洞的函数:eval、include等
2.根据漏洞点反推:看逻辑是否可行(参数是否可写入、魔术方法是否能触发、条件是否可达成等)
一般先找注入点,判断注入需要的参数,然后找到包含执行注入的函数(一般就是魔术方法),再找执行此函数的条件a,判断条件a是否可以满足,然后再找执行条件a需要满足的条件b,依次找下去直到不需要再找需要满足的条件即可。
3.最后构造poc验证。构造的时候根据上一步找到条件最好从后往前构造,并且要找正确触发魔术方法的究竟是谁($this指的是谁)
例题:
简单的pop例题:
1 | <?php |
首先找到敏感函数–>eval(),这里并没有对test参数做过滤处理,直接可以通过test的值来获取flag,确定好了漏洞点
接着要执行eval就需要调用hello()函数,这里只有test类中的魔法函数__destruct()调用了hello()函数,反序列化是调用destruct()函数的条件,我们可以发现如果不对test类中的index参数做任何处理,调用destruct函数后并不会调用execute类里的hello()函数,而是直接调用index类中的hello函数,也就是对execute()类的调用进行了过滤,这里我们需要不让index()被调用,所以可以直接将test类中的index参数指向excute类,从而可以覆盖index()类的调用,进而调用execute()类,从而实现了漏洞点的利用
在这里没考虑construct()魔法函数的原因是,反序列化并不会调用construct()函数
根据思路反推pop
1 | <?php |
[MRCTF2020]Ezpop
1 | class Modifier { |
首先,找到漏洞点:Modifier类的include()函数,这里可以利用文件包含
然后,一步一步推导:当进行反序列化时首先触发的是wakeup魔法函数
wakeup函数中使用了正则表达式,把source属性看成字符串,对其进行过滤,然而我们恰恰可以利用这点,将source赋值为一个对象,进而触发了to_string函数,由于show类中有to_string魔法函数,该函数返回str对象里面的source属性,在这我们可以将str指向没有source属性的对象,从而触发get魔法函数,在test类中恰好有get魔法函数,该get函数中将属性p作为function()函数的返回值,接着进一步利用,将p赋值为对象,可以触发invoke函数,在Modifier类中有invoke魔法函数,且该魔法函数将var属性的值赋值给apend函数,进而对var值进行文件包含
接下来直接构造pop
1 | class Modifier { |