## PHP序列化漏洞相关知识
本文仅记录我自己的学习过程
题目:
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=
给出的是一个代码块页面,而且还是不完整的,在这里我们可以得到两部分内容:1.一个xctf的类;2.要返回一个code参数,还有题目提示的反序列化函数unserialize().既然是反序列化,那么code传入很有可能xctf类的序列化字符串,因此我们补齐代码试一试(PHP在线编程)
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
}
$a=new xctf();
$s=serialize($a);
print($s);
?>
输出的是这样一串字符串:O:4:“xctf”:1:{s:4:“flag”;s:3:“111”;}
构造payload:code===O:4:“xctf”:1:{s:4:“flag”;s:3:“111”;}==发送,返回如下页面
这和上面__wakeup()函数的输出内容一样,调用了该函数,如果知道PHP魔术方法的同学就应该认识这个__wakeup函数(在反序列化时如果存在首先调用执行),就是绕过__wakeup()函数说不定就能够得到flag
百度绕过__wakeup()函数
__wakeup()漏洞就是与整个属性个数值有关。当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行
由此重新构造payload:code===O:4:“xctf”:2:{s:4:“flag”;s:3:“111”;}==发送
知识点:序列化,反序列化,序列号字符串的格式,魔术方法(__wakeup())的绕过
描述:
serialize ( mixed $value ) : string
serialize() 返回字符串,此字符串包含了表示 value 的字节流,可以存储于任何地方。这有利于存储或传递 PHP 的值,同时不丢失其类型和结构。想要将已序列化的字符串变回 PHP 的值,可使用 unserialize()。
说明:
unserialize ( string $str ) : mixed
参数: 序列化后的字符串。
作用:unserialize() 对单一的已序列化的变量进行操作,将其转换回 PHP 的值。若被解序列化的变量是一个对象,在成功地重新构造对象之后,PHP 会自动地试图去调用 __wakeup() 成员函数(如果存在的话)。
具体参照:PHP序列化_serialize_格式详解
对象(object)通常被序列化为:
O::" ": :{ … }
其中表示对象的类名 的字符串长度。 表示对象中的属性(字段)个数。
要注意的是:
1.私有字段的字段名在序列化时,字段名前面会加上 \0
2.静态字段在序列化时不受影响,即无法被序列化
class test {
public $a='1111';
static $b='1111';
private $c=123;
}
$a=new test();
$s=serialize($a);
print($s);
?>
输出:
O:4:"test":2:{s:1:"a";s:4:"1111";s:7:" test c";i:123;}
这个例子刚刚好能够说明上述的注意要点
以上面的结果了解一下字段的含义
O:对象的序列化
4:序列化对象的类名的长度
"test":序列化对象的类名
2:两个可见加的字段()
s:1:"a";s:4:"1111";:字段a的名称和值以及长度,数据类型
s:7:" test c";i:123;:同上,不过由于c是私有的变量,会加上类名
魔术方法:PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 等方法在 PHP 中被称为"魔术方法"(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。
和序列化反序列化有关的函数:
serialize() 函数
serialize() 会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。__sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。
__wakeup()函数:
unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
百度上有这样一句话:
__wakeup()漏洞就是与整个属性个数值有关。当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行
在早些年这样是一个漏洞曾经被爆出来过
参考链接:
PHP官方文档:https://www.php.net/manual/zh/
PHP序列化_serialize_格式详解:https://blog.csdn.net/Iamduoluo/article/details/8491746?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
[反序列化篇]反序列化漏洞之PHP反序列化全家桶(理论认知):https://blog.csdn.net/qq_43668710/article/details/105502267
其他大佬的wp:https://blog.csdn.net/wyj_1216/article/details/95320000
*如有不足之处,请告知,转载请表明出处