概念
序列化和反序列化
序列化
- 将对象型转换成字符串的过程。
反序列化
- 将字符串还原成对象型的过程。
反序列化漏洞(了解)
- 便于传输和存储
接下来上代码进行测试,先搞个类,
<?php
header("content-type:text/html;charset=utf8");
// 序列化 反序列化
// 创建一个类
class Person{
// 属性
var $name ;
var $age ;
// 方法
function hello(){
echo "你好";
}
// 构造方法
function __construct($n,$a){
$this->name = $n;
$this->age = $a;
}
}
// 实例化一个对象
$p1 = new Person("zhangsan",18);
var_dump($p1);
echo "<br>";
// 将 对象 序列化成 字符串
$res = serialize($p1);
echo $res; // O:6:"Person":2:{s:4:"name";s:8:"zhangsan";s:3:"age";i:18;}
echo "<br>";
// 把字符串 反序列化为 对象
$p11 = unserialize($res);
var_dump($p11);
echo "<br>-------------------<br>";
// 自定义字符串,进行反序列化
$str1 = 'O:6:"Person":2:{s:4:"name";s:8:"zhangsan";s:3:"age";i:18;}';
$p2 = unserialize($str1);
var_dump($p2);
echo "<br>-------------------<br>";
$str3 = 'O:6:"Person":2:{s:4:"name";s:4:"lisi";s:3:"age";i:18;}';
$p3 = unserialize($str3);
var_dump($p3);
echo "<br>-------------------<br>";
$str4 = 'O:6:"Person":3:{s:4:"name";s:4:"lisi";s:3:"age";i:18;s:4:"abcd";s:4:"1234";}';
$p4 = unserialize($str4);
var_dump($p4);
?>
解析:
O:6:"Person":1:{s:4:"name";s:6:"张三";}
// O:object
// 6:类名的长度
// "Person" :类名
// 1:属性的个数
// s:string类型
<?php
class S{
// 属性
var $test = "<script>alert(1);</script>";
}
echo(serialize(new S()));
?>
测试后反序列化成功,那么可想到这个界面是否跟XSS有关,试着往里插一下弹框("<script>alert(1);</script>")的数据看看,嫌麻烦用工具可以去菜鸟工具的在线php的序列化输出一下弹框("<script>alert(1);</script>")的字符串格式是怎样的,如下图右,已输出。手敲也行,得数,麻烦
这是反序列化结合XSS的风险
这样不就OK了,弹框出现,说明
试试别的
常见魔法函数
一般两个下划线开头的函数都是魔术方法,所谓魔术无非就是会自动调用而已。
1.__construct()当一个对象创建时被调用(构造函数)<不需要返回值>
2.__destruct()当一个对象销毁时被调用(析构函数)<不需要返回值>
3.__toString()当一个对象被当作一个字符串使用被调用<需要有返回值return>
4.__sleep()在对象在被序列化之前被调用<需要有返回值return,返回需要序列化的变量数组>
5.__wakeup()在反序列化之后立刻被调用<不需要返回值>
<?php
header("Content-type:text/html;charset=utf8");
// 定义一个类
class Persion{
var $name;
var $age;
// __construct构造函数,实例化对象的时候自动调用
function __construct($n,$a){
$this->name = $n;
$this->age = $a;
echo "<br>__construct函数执行了<br>";
}
// __destruct,对象被销毁时自动调用
function __destruct(){
echo "<br>__destruct函数执行了,对象销毁了<br>";
}
// __toString,当对象被当做字符串处理时自动调用
function __toString(){
echo "<br>__toString函数执行了~<br>";
return "__toString返回了~";
}
// __sleep(),对象在序列化之前被调用
function __sleep(){
echo "<br>__sleep函数执行了~<br>";
return array("name","age"); // 哪个属性可以被序列化
}
// __wakeup(),在反序列化之后调用
function __wakeup(){
echo "<br>__wakeup函数执行了~<br>";
}
}
// 实例化一个对象
$p1 = new Persion("zhangsan",18);
var_dump($p1);
echo $p1; // 将对象当做字符串处理
// 序列化
$data = serialize($p1);
echo $data;
// 反序列化
$obj = unserialize($data);
?>
反序列化漏洞
class S{
var $test = "pikachu";
function __construct(){
echo $this->test;
}
}
自己构造字节流:
- 类名不能变,属性名不能变,值可以变化(由用户控制)
O:1:"S":1:{s:4:"test";s:8:"zhangsan";}
构造恶意的字节流
O:1:"S":1:{s:4:"test";s:26:"<script>alert(1);</script>";}
反序列化小案例
PHP 在线工具 | 菜鸟工具 (jyshare.com)
shell_exec($this->name); 不同的写法有不同的风险,这样的写法有RCE远程代码执行的风险,这次这个是反序列化结合RCE
<?php
header("content-type:text/html;charset=utf8");
class Person{
var $name;
var $age;
// 构造函数,在new一个对象时会自动调用
function __construct($n,$a){
$this->name = $n;
$this->age = $a;
}
// wakeup()在反序列化之后立刻被调用
function __wakeup(){
shell_exec($this->name);
}
}
$data = $_GET['a'];
$p2 = unserialize($data);
?>