序列化-PHP反序列化 & POP链构造

啥是反序列化?

  • 序列化:对象转换为数组或字符串等格式
  • 反序列化:将数组或字符串等格式转换成对象
  • serialize() //将一个对象转换成一个字符串
  • unserialize() //将字符串还原成一个对象

eg:

1
2
3
4
5
6
7
8
9
10
11
<?php
class test{
public $a;
public $b;
function __construct(){$this->a = "xiaoshizi";$this->b="laoshizi";}
function happy(){return $this->a;}
}
$a = new test();
echo serialize($a);
?>

序列化后:

1
2
O:4:"test":2:{s:1:"a";s:9:"xiaoshizi";s:1:"b";s:8:"laoshizi";}

反序列化-魔术方法

魔术方法:默认会调用的一些方法

1
2
3
4
5
6
7
8
9
10
11
12
13
触发:unserialize 函数的变量可控,文件中存在可利用的类,类中有魔术方法:
__construct(): //构造函数,当对象 new 的时候会自动调用
__destruct()://析构函数当对象被销毁时会被自 p(): //unserialize()时会被自动调用
__invoke(): //当尝试以调用函数的方法调用一个对象时,会被自动调用
__call(): //在对象上下文中调用不可访问的方法时触发====》 (在class中调用不存在的方法,会执行call())
__callStatci(): //在静态上下文中调用不可访问的方法时触发
__get(): //用于从不可访问的属性读取数据 ====》 ( 访问了方法中不存在的属性,会调用get()方法)
__set(): //用于将数据写入不可访问的属性 ====》 (将数据写入方法中不存在的属性)
__isset(): //在不可访问的属性上调用 isset()或 empty()触发
__unset(): //在不可访问的属性上使用 unset()时触发
__toString(): //把类当作字符串使用时触发
__sleep(): // 序列化serialize()函数会检查类中是否存在一个魔术方法__sleep() 如果存在,该方法会被优先调用
——wekeup(): //调用 反序列化 unserialize()函数时,如果存在wakeup()方法,会被调用

new()新对象后
先调用construct()——》在调用destruct()——》

class C{
public $cmd=’ipconfig’;
public function_destruct(){
system($this->cmd);
}
public function_construct(){
echo ‘start’.’
‘;
}
}

//函数引用,无对象创建触发魔术 方法自定义变脸
unserizlize($GET) //URL传入GET
//接收序列化后的字符串,反序列化成为对象,默认调用方法_destruct() –>_destruct() 执行

POP链构造

PHP反序列化原生类漏洞绕过,公有私有

方法&属性

对象变量属性:
public(公共的) 在本类内部、外部类、子类都可以访问
protect(受保护的) 只有本类或子类或父类可以访问
private(私有的) 只有在本类内部可以使用

序列化后显示:
protect属性序列化的时候格式是%00*%00成员名
private属性序列化的格式是%00类名%00成员名

class ddd{
public $name =”test1”;
private $age = “test2”;
protected $sex = “man”;
}

序列化以后:

O:3:"ddd":3:{s:4:"name";s:5:"test1";s:8:"dddage";s:5:"test2";s:6:"*sex";s:3:"man";}

反序列化利用大概分三类:

  • 魔术方法的调用逻辑,触发条件
  • 语言原生类的调用-如SoapClient
  • 语言自身的安全缺陷-CVE-2016-7124

1、分析逻辑,查找可以利用的魔术方法
2、没有方法可用,考虑借助原生类
发序列化可以和和xss、scrf结合使用

CTFshow、buuctf反序列化题目