php反序列化

参考:http://t.csdn.cn/dWy9l
https://www.cnblogs.com/fish-pompom/p/11126473.html

序列化

有时需要把一个对象在网络上传输,为了方便传输,可以把整个对象转化为二进制串,等到达另一端时,再还原为原来的对象,这个过程称之为串行化 (也叫序列化)。
json 数据使用,分隔开,数据内使用:分隔键和值
json 数据其实就是个数组,这样做的目的也是为了方便在前后端传输数据,后端接受到 json 数据,可以通过 json_decode () 得到原数据,这种将原本的数据通过某种手段进行 "压缩",并且按照一定的格式存储的过程就可以称之为序列化。
有两种情况必须把对象序列化:

  1. 把一个对象在网络中传输
  2. 把对象写入文件或数据库
  • public、protected、private
1
2
3
public:属性被序列化的时候属性值会变成 属性名
protected:属性被序列化的时候属性值会变成 \x00*\x00属性名
private:属性被序列化的时候属性值会变成 \x00类名\x00属性名

ps: \x00 表示空字符,但是还是占用一个字符位置(空格)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class People{
public $id;
protected $gender;
private $age;
public function __construct(){
$this->id = 'Hardworking666';
$this->gender = 'male';
$this->age = '18';
}
}
$a = new People();
echo serialize($a);
?>
1
O:6:"People":3:{s:2:"id";s:14:"Hardworking666";s:9:" * gender";s:4:"male";s:11:" People age";s:2:"18";}
  • 序列化格式
1
2
3
4
5
6
7
8
9
10
11
12
13
a - array 数组型
b - boolean 布尔型
d - double 浮点型
i - integer 整数型
o - common object 共同对象
r - objec reference 对象引用
s - non-escaped binary string 非转义的二进制字符串
S - escaped binary string 转义的二进制字符串
C - custom object 自定义对象
O - class 对象
N - null 空
R - pointer reference 指针引用
U - unicode string Unicode 编码的字符串

ps: 请记住,序列化他只序列化属性,不序列化方法

  1. 在反序列化的时候一定要保证在当前的作用域环境下有该类存在
  2. 反序列化攻击的时候也就是依托类属性进行攻击

反序列化

被序列化的字符串还原为对象,然后在接下来的代码中继续使用。

1
2
$u=unserialize("O:1:"S":1:{s:4:"test";s:7:"pikachu";}");
echo $u->test; //得到的结果为pikachu

反序列化漏洞

序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了 PHP 中的魔法函数,就会导致安全问题
具备反序列化漏洞的前提:

  1. 必须有 unserailize () 函数
  2. unserailize () 函数的参数必须可控(为了成功达到控制你输入的参数所实现的功能,可能需要绕过一些魔法函数

魔法函数

PHP 将所有以 __ (两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。

  • 常见魔法函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
__construct(),类的构造函数

__destruct(),类的析构函数

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

__callStatic(),用静态方式中调用一个不可访问方法时调用

__get(),获得一个类的成员变量时调用

__set(),设置一个类的成员变量时调用

__isset(),当对不可访问属性调用isset()或empty()时调用

__unset(),当对不可访问属性调用unset()时被调用。

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

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

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

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

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

__clone(),当对象复制完成时调用

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

__debugInfo(),打印所需调试信息
  • 重点关注
1
2
3
4
5
6
7
8
9
10
11
12
13
__construct:构造函数,当一个对象创建时调用

__destruct:析构函数,当一个对象被销毁时调用

__toString:当一个对象被当作一个字符串时使用

__sleep:在对象序列化的时候调用

__wakeup:对象重新醒来,即由二进制串重新组成一个对象的时候(在一个对象被反序列化时调用)

从序列化到反序列化这几个函数的执行过程是:

__construct() ->__sleep() -> __wakeup() -> __toString() -> __destruct()
  • __ toString () 这个魔术方法能触发的因素
1
2
3
4
5
6
7
8
1.  echo($obj)/print($obj)打印时会触发 
2. 反序列化对象与字符串连接时
3. 反序列化对象参与格式化字符串时
4. 反序列化对象与字符串进行==比较时(PHP进行==比较的时候会转换参数类型)
5. 反序列化对象参与格式化SQL语句,绑定参数时
6. 反序列化对象在经过php字符串处理函数,如strlen()、strops()、strcmp()、addslashes()等
7. 在in_array()方法中,第一个参数时反序列化对象,第二个参数的数组中有__toString()返回的字符串的时候__toString()会被调用
8. 反序列化的对象作为class_exists()的参数的时候

利用

  • 结合 xss
    O:1:“S”:1:{s:4:“test”;s:29:“”;}
  • 根据具体的魔法函数,获取想要的内容
    还是根据后面的 ctf 题实操吧
访问量 访客