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

060-WEB攻防-PHP反序列化POP链构造魔术方法流程漏洞触发条件属性修改

060-WEB攻防-PHP反序列化&POP链构造&魔术方法流程&漏洞触发条件&属性修改

知识点:
1、PHP-反序列化-应用&识别&函数
2、PHP-反序列化-魔术方法&触发规则
3、PHP-反序列化-联合漏洞&POP链构造

在实战情况下,是不需要知道这些具体分析的,都是利用工具去扫一些框架爆出的反序列话漏洞直接利用即可。
学这些具体分析就是为了以后往漏洞挖掘方向发展或者打CTF比赛及面试会被问

1、PHP-DEMO1-序列化和反序列化

为什么会产生序列化?

为了解决开发中数据传输和数据解析的一个情况(类似于要发送一个椅子快递,不可能整个椅子打包发送,这是非常不方便的,所以就要对椅子进行序列化处理,让椅子分成很多部分在一起打包发送,到目的后重新组装,也就是反序列化处理)

什么是反序列化操作? - 类型转换

  • PHP & JavaEE & Python(见图)

63b7809a3530f569c350be7fc77ccc4e

580444fb1a4681b61529ce7d97299718

序列化:对象转换为数组或字符串等格式

序列化(Serialization)
把“复杂的数据结构(如数组、对象)”转换成一个字符串,方便你:

  • 存进文件
  • 放进数据库
  • 在网络上传输(如 Cookie、Session、API)

不能直接把“数组”或“对象”这样的复杂数据,塞进一个只支持字符串的地方(比如 Cookie)。

为什么不能直接把数组或对象塞进只支持字符串的地方?

  1. 本质问题:类型不兼容

PHP 的数组、对象是内存中的复杂结构,比如:

  • 数组有键名、键值、可能还嵌套其他数组
  • 对象有属性、方法、类名等元信息

而像 Cookie、数据库字段、URL 参数,这些地方只能存储字符串类型(即文本)。

所以你不能直接把这样的“结构”放进去,比如:

setcookie("user", ['name' => 'Tom']); // ❌ 错误!数组不能直接当 cookie 值

image-20250527193851523

反序列化(Unserialization)
是序列化的逆操作——把字符串还原成原来的数据结构

image-20250527194236223

serialize() //将对象转换成一个字符串
unserialize() //将字符串还原成一个对象

2、PHP-DEMO2-魔术方法触发规则

常见的php魔术方法

b89050ab42fb6cfcb31c7288a7e815cc

__construct():

  • //当对象new的时候会自动调用
  • 当new Test实例化对象 触发魔术方法_construct() 输出__construct()初始化
  • unset() 是 PHP 的一个语言结构,用于销毁变量,也就是说,它会让一个变量“消失”。

image-20250527195651058

__destruct()

  • //当对象被销毁时会被自动调用
  • __destruct() 是对象销毁时自动触发的魔术方法。你没有主动销毁对象 $test,但当脚本结束时 PHP 自动回收内存,系统帮你调用了 __destruct(),所以会输出那一行。

image-20250527195933702

__sleep()

  • : //serialize()序列化执行时被自动调用

image-20250527200833741

image-20250527200951800

__wakeup()

  • //unserialize()反序列化时会被自动调用

  • 这个和__sleep()截然相反

image-20250527201342084

image-20250527201407419

__invoke()

  • : //把对象当作函数调用时触发

image-20250527201626664

__toString()

  • : //把对象当作字符串使用时触发

原因详解:为什么 __toString() 会被自动调用?

  • \1. echo / 字符串上下文要求是字符串类型
  • 在 PHP 中,echo 是一个语言结构,它只能输出字符串。所以当你:echo $a
  • 其中 $a 是一个对象,PHP 必须把它转换成字符串,否则就会报错。

image-20250527201721403

__call():

  • //调用某个方法,若方法存在,则调用;若不存在,则会去调用__call函数。

image-20250527202336593

image-20250527202430152

__get()

  • 读取一个对象的属性时,若属性存在,则直接返回属性值;若不存在,则会调用__get函数

image-20250527202656204

image-20250527202952109

__ set()

  • 魔术方法 设置一个对象的属性时, 若属性存在,则直接赋值;若不存在,则会调用__set函数。

  • __set():设置对象不存在的属性或无法访问(私有)的属性时调用

  • __set($name, $value)* 用来为私有成员属性设置的值* 第一个参数为你要为设置值的属性名,第二个参数是要给属性设置的值,没有返回值。
    

image-20250527203600241

image-20250527203703407

__isset()

  • __检测对象的某个属性是否存在时执行此函数。当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用
  • name没被调用的原因是因为name是私有属性
image-20250527204233957

image-20250527204411525

  • 这里因为name是私有属性所以不可访问 并且不可访问属性还使用了isset()所以调用了__isset()魔术方法显示123

  • 为什么echo empty($person->sex) 为1

    原因是:重写了 __isset() 魔术方法 PHP 做了下面这些步骤:

    1. 检查 $person->sex 能不能访问;
    2. sex 是公共属性,所以可以访问,不走 __isset()
    3. 但出于一致性,PHP 会调用 __isset() 方法来判断属性是否存在;
    4. 你的 __isset() 方法返回:
    return isset($this->$content);
    
    • $content'sex'
    • $this->$content相当于$this->sex,值是 "男"
    • 所以:isset("男")true
    1. 但是 empty() 要的是:如果 issetfalse 或者值是 空的值(如 0, "", null),那就返回 flase。
    2. 可这里:虽然值是 "男",但是你的 __isset() 返回的是 true,
    • PHP 会在你重写了 __isset() 之后只看返回值,不再检查值本身是否为空
    • 也就是说 empty() 依赖 __isset() 的返回值判断“是否存在”,然后认为这个变量的值是 未定义的或不可用的

    所以最终 PHP 认为这个变量是空的,empty() 返回了 true,于是输出 1

image-20250527204605485

__unset()

  • 在不可访问的属性上使用unset()时触发 销毁对象的某个属性时执行此函数

image-20250527214023590

3、演示案例-PHP-DEMO3-反序列化漏洞产生

序列化漏洞产生原理

简单案例

  • 这里没有调用类所以无法触发 __destruct()方法 ipconfig没有被执行

image-20250527214218496

  • 调用了类 出发__destruct方法

image-20250527214350431

反序列化漏洞如何产生

原理:未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码执行,SQL注入,目录遍历等不可控后果。在反序列化的过程中自动触发了某些魔术方法。

简单案例

  • 将要执行的代码进行序列化为O:1:"B":1:{s:3:"cmd";s:3:"ver";}
  • 然后打开3.php执行O:1:"B":1:{s:3:"cmd";s:3:"ver";} 因为这里是unserialize 将我们的序列化的代码进行反序列化为了ver所以造成了命令执行
  • image-20250527215654525
  • image-20250527215746242

4、演示案例-PHP-CTFSHOW-POP触发链构造

-反序列化常见起点(见图)
-反序列化常见跳板(见图)
-反序列化常见终点(见图)

b89050ab42fb6cfcb31c7288a7e815cc

254-对象引用执行逻辑

  1. 从代码分系可以看到如果想要打印$flag必须触发vipOneKeyGetFlag()方法

  2. 触发vipOneKeyGetFlag()的条件是里面的if($this->isVip)如果要触发if的条件必须要得到checkVip()的返回值

  3. checkVip()触发要让if($user->login($username,$password))触发去执行 if($user->checkVip())

  4. 但是这里的checkVip()里面的变量$isVip为flase 所以要让他为true得满足if($this->username=$u&&$this->password=$p)条件就能染眉膏isvip为true

    image-20250528103350619

255-反序列化变量修改

  1. 用反序列化cookie接受user
  2. 用user接受password和username 触发login
  3. login方法返回username和password的结果 断真假
  4. 如果为真进入下面的if($user->checkVip())调用 $this->checkvvip() 但是这里的$isvip为flase 所以我们要让他为true
  5. 我们在这里对public $isVip=flase;进行序列化 O:11:"ctfShowUser":1:{s:5:"isVip";b:0;}
  6. 但是这里存在“ : 等存在许多干扰 url 所以要对传进去的cookie的值进行url编码O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

image-20250528170048029

image-20250528170127265

256-反序列化参数修改

  1. 这一关比上关多了一个判断值if($this->username!==$this->password)
  2. 要去传进去的username和password不想等
  3. 修改username和password属性的值重新序列化

O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22111111%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22222222%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

image-20250528170633759

image-20250528170850707

257-反序列化参数修改&对象调用逻辑

  1. 这里接受方法和上面的一样重点看上面两个魔术方法
  2. __construct当对象new的时候会自动调用 ___destruct当对象被销毁时会被自动调用 在这里 destruct一定会被调用
  3. destruct里面会调用$this->class->getInfo(); 这里clase等于info调用此类里面的getInfo方法
  4. 在这里backDoor类里面有eval($this->code)代码执行 我们需要修改里面的private 属性为public 属性
  5. 让$class=backDoor 调用类执行里面的getinfo方法

O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A23%3A%22system%28%27tac+flag.php%27%29%3B%22%3B%7D%7D


image-20250528171625928

image-20250528172126575

image-20250528181114312

image-20250528181158471

257-反序列化参数修改&对象调用逻辑

  1. 这关代码和上面的差不多不同的是这关对:进行了过滤 还要将private $class 替换为public $class
  2. 使用replace替换掉里面:

O%3A%2B11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A23%3A%22system%28%27tac+flag.php%27%29%3B%22%3B%7D%7D

image-20250528181433348

image-20250528183017061

image-20250528183112226

http://www.hskmm.com/?act=detail&tid=9834

相关文章:

  • 059-Web攻防-XXE安全DTD实体复现源码等
  • 061-WEB攻防-PHP反序列化原生类TIPSCVE绕过漏洞属性类型特征
  • 051-Web攻防-文件安全目录安全测试源码等
  • Dilworth定理及其在算法题中的应用
  • 050-WEB攻防-PHP应用文件包含LFIRFI伪协议编码算法无文件利用黑白盒
  • error: xxxxx does not have a commit checked out
  • 049-WEB攻防-文件上传存储安全OSS对象分站解析安全解码还原目录执行
  • 云原生周刊:MetalBear 融资、Chaos Mesh 漏洞、Dapr 1.16 与 AI 平台新趋势
  • AI一周资讯 250913-250919
  • 045-WEB攻防-PHP应用SQL二次注入堆叠执行DNS带外功能点黑白盒条件-cnblog
  • linux 命令语句
  • 用 Kotlin 实现英文数字验证码识别
  • 达芬奇(DaVinci Reslove)字体文件 bugb标签
  • 语音芯片怎样挑选?语音芯片关键选型要点?
  • KingbaseES Schema权限及空间限额
  • HTTP库开发实战:核心库与httpplus扩展库示例解析
  • QMT交易系统向服务器同步订单丢失问题排查
  • 笔记1
  • 用 Python 和 Tesseract 实现英文数字验证码识别
  • 实用指南:OSPF特殊区域、路由汇总及其他特性
  • 禅道以及bug
  • 中电金信 :MCP在智能体应用中的挑战与对策
  • 第一次参与开源的时序数据库 IoTDB Committer:这份成就感是无可替代的
  • ECT-OS-JiuHuaShan 框架元推理的意义、价值、作用、应用场景和哲学理念的充分阐述:AGI奇点
  • CSP 2025 复赛复习总目标与计划
  • mysql区分大小写吗,你可能忽略了这些关键细节
  • route-link 和 a 的区别
  • WPF 调用 Windows 桌面右键新增文件菜单的实现方案
  • HR 需了解的绩效评估应包含的内容
  • 解题报告-P12022 [USACO25OPEN] Hoof Paper Scissors Minus One B