当前位置: 首页 > news >正文

PHP反序列化学习+解析+复现

文章目录

  • 1、PHP反序列化含义
  • 2、PHP反序列化解析
  • 3、PHP反序列化漏洞
    • 3.1首先确保本机含有php环境。
    • 3.2test.php脚本
    • 3.3启动php内置服务
    • 3.4访问
    • 3.5修改命令
  • 4、魔术方法

1、PHP反序列化含义

序列化:将复杂的数据结构(对象、数组)转化为字符串,方便存储和运输。

反序列化:将对应的字符串恢复成原来的数据。

序列化函数:serialize() 反序列化函数:unserialize()

2、PHP反序列化解析

先放一个最为简单基础的php反序列化代码,那么它的输出就是个序列化输出的格式。

<?php
class C {public $cmd = 'whoami'; // 测试命令为 whoamipublic function __destruct(){system($this->cmd); }// 对象销毁时自动执行系统命令
}
// 测试反序列化
if(isset($_GET['c'])){unserialize($_GET['c']);
} else {$b = new C();echo "Payload: ".serialize($b);
}
?>

ok那我们快来看下他payload的序列化格式
在这里插入图片描述

那么从图中可以看出序列化数据为O:1:“C”:1:{s:3:“cmd”;s:6:“whoami”;},当我们把属性值whoami改成别的命令的时候,命令就会被执行。

在这里插入图片描述

3、PHP反序列化漏洞

那我们现在知道了反序列化的漏洞所在,那么只需要更改命令并执行就可以了。

3.1首先确保本机含有php环境。

php -version

在这里插入图片描述
如果没有的话需要找到你防止php的地址,然后配置环境变量。

3.2test.php脚本

把这个脚本放在你的根目录下,以我为例子,就放在了这里。
在这里插入图片描述

3.3启动php内置服务

我把php端口设置成了6666,不要与别的端口冲突

php -S 0.0.0.0:6666  # 允许所有IP访问

在这里插入图片描述

3.4访问

然后用自己的浏览器访问,这里我用的是OWASP

http://localhost:8000/test.php #将localhost改成自己的ip

在这里插入图片描述
发现乱码了,是由于 Windows 命令行编码与PHP输出编码不匹配 导致的。在PHP脚本顶部添加编码声明即可。

<?php
header('Content-Type: text/html; charset=GB2312'); // 编码声明
class C {public $cmd = 'whoami'; // 测试命令为 whoamipublic function __destruct(){system($this->cmd); }// 对象销毁时自动执行系统命令
}// 测试反序列化
if(isset($_GET['c'])){unserialize($_GET['c']);
} else {$b = new C();echo "Payload: ".serialize($b);
}
?>

3.5修改命令

http://x.x.x.x:6666/test.php?c=O:1:"C":1:{s:3:"cmd";s:14:"ping 127.0.0.1";}

这个的意思很明显,记得改s:14空格也要算上字符,结果显示如下。

在这里插入图片描述
还可以搞点好玩的,比如修改成弹计算器的命令,全部运行成功了。

http://x.x.x.x:6666/test.php?c=O:1:"C":1:{s:3:"cmd";s:10:"start calc";}

4、魔术方法

_construct() 构造函数,当对象new的时候自动调用

class User {public function __construct($name) {echo "User [$name] initialized!";}
}
$user = new User("Alice"); // 输出:User [Alice] initialized!

-destruct() 析构函数,当对象销毁时自动调用(反序列化漏洞常用触发点)

class Database {public function __destruct() {echo "Closing database connection...";}
}
$db = new Database();
unset($db); // 输出:Closing database connection...

_toString() 把类当作字符串使用时触发(可被preg_match等字符串函数触发)

class Product {public function __toString() {return "This is a product object";}
}
echo new Product(); // 输出:This is a product object

_sleep() 当对象被serialize()序列化时自动调用·

class Config {public $user = 'admin';private $password = '123456';public function __sleep() {return ['user']; // 仅序列化user属性}
}
echo serialize(new Config()); // 输出:O:6:"Config":1:{s:4:"user";s:5:"admin";}

-wakeup() 当对象被unserialize()反序列化时触发(反序列化入口点)

class Logger {public function __wakeup() {echo "Object deserialized!";}
}
$data = 'O:6:"Logger":0:{}';
unserialize($data); // 输出:Object deserialized!

_call() 当调用不存在的方法时触发(可用于实现动态方法)

class Dynamic {public function __call($name, $args) {echo "Calling undefined method: $name";}
}
$obj = new Dynamic();
$obj->fakeMethod(); // 输出:Calling undefined method: fakeMethod

_callStatic() 当调用不存在的静态方法时触发·

class StaticDemo {public static function __callStatic($name, $arguments) {echo "调用了不存在的静态方法: $name\n";print_r($arguments);}
}StaticDemo::undefinedMethod('param1', 123); 
// 输出:调用了不存在的静态方法: undefinedMethod
// Array([0] => param1 [1] => 123)

_get() 当读取不可访问属性时触发(如private属性)

class User {private $data = ['name' => '张三','age' => 25];public function __get($name) {if (array_key_exists($name, $this->data)) {return $this->data[$name];}return "属性{$name}不存在";}
}$user = new User();
echo $user->name; // 输出:张三
echo $user->email; // 输出:属性email不存在

_set() 当给不可访问属性赋值时触发·

class Account {private $balance = 0;public function __set($name, $value) {if ($name === 'balance') {throw new Exception("禁止直接修改余额");}$this->$name = $value;}
}$account = new Account();
$account->balance = 1000; // 抛出异常
$account->name = "测试"; // 正常设置

_isset() 当对不可访问属性调用isset()时触发·

class Config {private $settings = ['debug' => true];public function __isset($name) {echo "检查属性是否存在: $name\n";return isset($this->settings[$name]);}
}$config = new Config();
var_dump(isset($config->debug)); // 输出:true

_unset() 当对不可访问属性调用unset()时触发·

class Session {private $data = [];public function __unset($name) {echo "尝试删除属性: $name\n";unset($this->data[$name]);}
}$session = new Session();
unset($session->token); // 触发__unset

_invoke() 当尝试以函数方式调用对象时触发(如$obj())

class Calculator {public function __invoke($a, $b) {return $a + $b;}
}$calc = new Calculator();
echo $calc(3, 5); // 输出:8
http://www.dtcms.com/a/308375.html

相关文章:

  • 提升Windows操作效率:三款实用辅助工具功能解析​
  • 代码随想录Day35:动态规划(背包问题 二维 一维、分割等和子集)
  • Spring Boot整合MyBatis-Plus全攻略
  • 如何监控项目的每个阶段,提高执行效率
  • SchemaCrawler:一款免费开源的数据库文档工具
  • 斐波那契数
  • AI学习笔记三十三:基于Opencv的单目标跟踪
  • OpenCSG月度更新2025.7
  • leecode18 四数之和
  • 个股期权合约期内遇到标的停牌,如何处置?
  • DoRA详解:从LoRA到权重分解的进化
  • Redis线程模型讨论
  • 修改VSCode远程SSH的PATH
  • JVM字节码文件结构剖析
  • JVM学习日记(十二)Day12
  • 解释 MySQL 中的 EXPLAIN 命令的作用和使用场景
  • 格雷希尔G25F系列电气端口快速封堵接头,解决电池包、电机控制器等壳体的气密性测试难题,提升效率与可靠性,助力新能源汽车生产。
  • ARM--中断
  • 三坐标测量仪攻克深孔检测!破解新能源汽车阀体阀孔测量难题
  • 雷霆战机游戏代码
  • ABS系统专用磁阻式汽车轮速传感器
  • 建设公司如何优化梳理部门职责,提高运作效率?
  • 中烟创新自研【烟草行政许可文书制作系统】纳入“北京市人工智能赋能行业发展典型案例集”
  • 电子电气架构 --- 车载48V系统
  • 如何导入json文件到数据库
  • 生信技能76 - 根据SNP列表提取SNP位点上下游的参考基因组fasta
  • RocksDB关键设计详解
  • MySQL 45讲 16-17
  • 【Linux网络编程】网络层协议 - IP
  • 大模型微调工具LLaMA-Factory的安装流程