Unserialize-ways

本文最后更新于:1 年前

PHP反序列化相关方法/解决方法问题

PHP反序列化

PHP常用魔术方法

__construct(),类的构造函数

__destruct(),类的析构函数

__call(),在对象中调用一个不可访问方法时调用

__callStatic(),在静态上下文中调用一个不可访问方法时调用

__get(),读取不可访问(protected或private)或不存在的属性的值时调用

__set(),在给不可访问(protected或private)或不存在的属性赋值时调用

__isset(),当对不可访问(protected或private)或不存在的属性调用isset()或empty()时调用

__unset(),当对不可访问(protected或private)或不存在的属性调用unset()时调用

__sleep(),执行serialize()时,先会调用这个函数

__wakeup(),执行unserialize()时,先会调用这个函数

__toString(),类被当成字符串时的回应方法

__invoke(),调用函数的方式调用一个对象时的回应方法

__set_state(),调用var_export()导出类时,此静态方法会被调用。

__clone(),当对象复制完成时调用(可用于修改属性的值)

__autoload(),尝试加载未定义的类

__debugInfo(),打印所需调试信息

public、protected与private在序列化时的区别

protected 声明的字段为保护字段,在所声明的类和该类的子类中可见,但在该类的对象实例中不可见。因此保护字段的字段名在序列化时,字段名前面会加上\0*\0的前缀。这里的 \0 表示 ASCII 码为 0 的字符(不可见字符),而不是 \0 组合。这也许解释了,为什么如果直接在网址上,传递\0*\0username会报错,因为实际上并不是\0,只是用它来代替ASCII值为0的字符。必须用python传值才可以。

private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字段名在序列化时,类名和字段名前面都会加上\0的前缀。字符串长度也包括所加前缀的长度。其中 \0 字符也是计算长度的。

public无标记,变量名不变,长度不变
protected在字段名前添加标记\00*\00,长度+3
private在类名和字段名前添加标记\00(classname)\00,长度+2+类名长度

[极客大挑战 2019]PHP

_wakeup绕过方法

unserialize()会检查是否存在一个 __wakeup()方法。如果存在,则会先调用 __wakeup()方法,预先准备对象需要的资源

序列化字符串中表示对象属性个数的值大于 真实的属性个数时会跳过__wakeup()的执行

[极客大挑战 2019]PHP

POP链的原理/利用

POP面向属性编程

指从现有运行环境中寻找一系列的代码或指令调用,然后根据需求构造出一组连续的调用链

一般简单的反序列化都是魔法函数中出现的一些利用的漏洞,因为自动去调用魔法方法而产生漏洞,但如果关键代码不在魔术方法中,而在一个类的一个普通方法中,则需要通过寻找相同的函数名将类的属性和敏感函数连接起来


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!