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

[网鼎杯 2020 青龙组]AreUSerialz(个人记录写题笔记,含PHP反序列化的原理、漏洞成因以及利用技巧)

源代码

<?php include("flag.php"); highlight_file(__FILE__); class FileHandler { protected $op; protected $filename; protected $content; function __construct() { $op = "1"; $filename = "/tmp/tmpfile"; $content = "Hello World!"; $this->process(); } public function process() { if($this->op == "1") { $this->write(); } else if($this->op == "2") { $res = $this->read(); $this->output($res); } else { $this->output("Bad Hacker!"); } } private function write() { if(isset($this->filename) && isset($this->content)) { if(strlen((string)$this->content) > 100) { $this->output("Too long!"); die(); } $res = file_put_contents($this->filename, $this->content); if($res) $this->output("Successful!"); else $this->output("Failed!"); } else { $this->output("Failed!"); } } private function read() { $res = ""; if(isset($this->filename)) { $res = file_get_contents($this->filename); } return $res; } private function output($s) { echo "[Result]: <br>"; echo $s; } function __destruct() { if($this->op === "2") $this->op = "1"; $this->content = ""; $this->process(); } } function is_valid($s) { for($i = 0; $i < strlen($s); $i++) if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125)) return false; return true; } if(isset($_GET{'str'})) { $str = (string)$_GET['str']; if(is_valid($str)) { $obj = unserialize($str); } }

漏洞点分析

  1. 反序列化用户输入unserialize($_GET['str'])直接反序列化用户可控数据

  2. 危险方法调用read()方法中的file_get_contents()可以读取任意文件

  3. 属性可控:通过反序列化可以控制类的属性值

  4. 构造函数缺陷:构造函数中使用局部变量而非类属性

知识点梳理

1. PHP序列化与反序列化基础

序列化:将对象转换为字符串,便于存储或传输

$obj = new FileHandler(); $serialized = serialize($obj); // 输出:O:11:"FileHandler":3:{...}

反序列化:将字符串还原为对象

$obj = unserialize($serialized);

2. PHP魔术方法

​​​​​​​​​​​​​​
  • __construct():构造函数,对象创建时调用

  • __destruct():析构函数,对象销毁时调用

  • __wakeup():反序列化时调用

  • __sleep():序列化时调用

更多魔术方法可看:PHP之十六个魔术方法详解_php魔术方法-CSDN博客

在本题中,关键魔术方法的执行顺序:

​​​​​​​​​​​​​​
  1. unserialize()创建对象

  2. 执行__construct()(如果存在)

  3. 脚本结束,执行__destruct()

3. 可见性修饰符与序列化

PHP中属性的可见性影响序列化格式:

​​​​​​​​​​​​​​
  • public属性名

  • protected\x00*\x00属性名

  • private\x00类名\x00属性名

示例:

class Test { public $public = "public"; protected $protected = "protected"; private $private = "private"; } // 序列化输出包含不可见字符

4. PHP类型比较

  • 弱比较(==):类型转换后比较值(只比较值,不比较类型)

    2 == "2" // true 0 == "abc" // true "1e3" == 1000 // true
  • 严格比较(===):比较值和类型

    2 === "2" // false 0 === "abc" // false
重要区别总结
比较方式示例结果说明
弱比较 (==)2 == "2"true类型转换后值相等
严格比较 (===)2 === "2"false类型不同,值相等也没用
弱比较 (==)0 == "abc"true字符串"abc"转为整数是0
严格比较 (===)0 === "abc"false类型和值都不同
弱比较 (==)false == "0"true都转换为布尔值比较
严格比较 (===)false === "0"false类型不同

5. 文件读取技巧

​​​​​​​​​​​​​​
  • 直接读取:file_get_contents("flag.php")

  • PHP Wrapper读取源码:php://filter/convert.base64-encode/resource=flag.php

  • 目录遍历:./flag.php../flag.php

漏洞利用过程

第一步:分析利用链

目标:读取flag.php文件
利用链:unserialize() -> __construct() -> process() -> read() -> file_get_contents()

第二步:绕过限制

​​​​​​​​​​​​​​
  1. 绕过is_valid()过滤:只允许ASCII 32-125的字符,我们的payload符合要求

  2. 绕过__destruct()修改:使用整数2而非字符串"2"

  3. 利用构造函数缺陷:构造函数使用局部变量,不影响反序列化设置的属性

第三步:构造payload

使用public属性和整数2

O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";s:0:"";}

第四步:执行效果

​​​​​​​​​​​​​​
  1. 反序列化设置$op=2,$filename="flag.php"

  2. 执行__construct(),但局部变量不影响属性值

  3. process()$this->op == "2"为 true(弱比较)

  4. 执行read(),读取flag.php

  5. 输出flag内容

  6. __destruct()$this->op === "2"为 false(严格比较),不修改$op​​​​​​​

扩展知识

1. PHP反序列化漏洞常见利用点

  • POP链构造:寻找从源点到危险函数执行的路径

  • Phar反序列化:通过Phar协议触发反序列化

  • 内置类利用:使用SimpleXMLElementSoapClient等内置类

2. 自动化工具

  • PHPGGC:PHP反序列化payload生成工具

  • CodeQL:静态代码分析工具,可用于发现反序列化漏洞

3. 相关CVE

  • CVE-2016-7124__wakeup()绕过漏洞

  • CVE-2019-11043:PHP-FPM漏洞

  • CVE-2020-7068get_headers()漏洞

总结

通过本题我们学习了:

  1. PHP反序列化基本流程:序列化格式、魔术方法执行顺序

  2. 类型比较的差异:弱比较与严格比较的安全影响

  3. 属性可见性的处理:public/protected/private在序列化中的表现

  4. 漏洞链构造:从用户输入到危险函数的完整路径

  5. 安全编码实践:如何避免和修复这类漏洞

反序列化漏洞是Web安全中常见且危害较大的漏洞类型,理解其原理和利用方式对于安全开发和渗透测试都至关重要。

参考:PHP之十六个魔术方法详解_php魔术方法-CSDN博客

http://www.jsqmd.com/news/84373/

相关文章:

  • PINN学习(三)—— 发现方程问题的解决
  • 当AI成为同事:HR的“战斗力”正在被重新定义
  • 【安卓aosp】编译报错 killed 如果处理
  • Comsol Multiphysics数值模拟
  • Windows11中使用VS2022编译运行libevent网络库
  • 不止于智能:GPT-5.1 发布,更温暖、更好聊的 ChatGPT 来啦!
  • 战网注册后显示无法登录
  • Creed —— 血液特效与敌人伤害
  • 生成式搜索优化服务商排行
  • PINBAI平板电脑维修实例
  • 大模型教我成为大模型算法工程师之day9:卷积神经网络 (CNN)
  • 优化巨型物流网络:某中心如何通过算法实现区域化转型
  • 13. django中间件
  • LangChain All In One
  • 论文解读|从“情感陪伴机器人”到“知识中介体”
  • AI大模型之Agent,RAG,LangChain(三)
  • 论文解读:多模态大模型情绪分析的承诺与现实
  • 重构 Flutter 状态管理:从 Provider 到 Riverpod 2.0 的无痛迁移与性能飞跃
  • 人工智能之数学基础:离散条件分布和连续条件概率密度
  • 精通 Flutter 网络请求:从基础 GET/POST 到拦截器 + 缓存 + 断点续传的全维度实践
  • 创客匠人峰会洞察:技术革命下知识变现的 “能力进化” 模型 —— 从 “专业者” 到 “知识超人” 的跃迁
  • 前端最新技术,零基础入门到精通,收藏这篇就够了
  • PPT——让两个视频在同一页幻灯片中同时自动播放
  • 前端失业有多严重?
  • 2026中专毕业想做出纳,考哪些证书企业比较认可?这些证让你轻松入职!
  • springboot设计与实现职称评审管理系统.zip(源码+论文+ppt答辩)
  • 如何用 VS Code + C# Dev Kit 创建类库项目并在主项目中引用它?
  • ABC331D Tile Pattern
  • js之事件系统
  • 第二章-依赖属性