资讯动态

CTFShow Web入门40-50题:SSRF与文件包含漏洞利用实战详解

发布时间:2026/10/16 9:46:04 来源:尧图企业网站定制
CTFShow平台的Web入门系列一路刷下来前40题基本是热身和熟悉套路真正开始上强度的时候就是40到50这个区间。这段时间你会明显感觉到题目不再是把flag摆在明面上让你找而是逼着你理解漏洞的原理自己去构造攻击链。我爬完这十道题最大的感受是这个阶段的题目设置很巧妙就像打游戏过新手村之后遇到的第一批精英怪看着唬人打法其实有规律可循。这篇文章就把我在这组题上沉淀下来的思路、踩过的坑和一些解题细节好好梳理一遍希望能给正在这条路上爬坡的朋友一些参考。1. 这组题到底在考什么——从“找flag”到“利用漏洞”的思维转变1.1 题目难度的真实分布曲线第40到50题从整体知识栈来看主要压在两个大方向上服务端请求伪造SSRF和文件包含漏洞LFI/RFI中间穿插一些命令注入和日志利用的变体。很多新手做到这里会有点懵因为前30多题可能还在玩SQL注入的联合查询、布尔盲注或者简单的绕waf拼字符串到了这个区间题目环境突然变成了一个实实在在的内网环境你的对手不再是SQL语句的过滤规则而是服务端到底会不会把请求发出去包含文件时能不能把参数可控点利用起来这种更底层的逻辑问题。这里说句实在话第40到50题刚好卡在一个分水岭往前的题目很多是可以靠搜wp、背payload混过去的往后做就不行了你要是搞不懂file://和http://在服务端请求时有什么区别连题目在问什么都不知道。这个阶段熬过去你的Web渗透思路基本就成型了。1.2 为什么40题是个坎我见过不少朋友刷题时卡在这里反复看wp都看不明白。问题不在于题目多难而是思维方式没转过来。前面做CTF题目大家习惯是找到注入点-丢进工具-出结果本质上还是在用工具不理解数据在代码层面是怎么流动的。到了SSRF和文件包含工具帮不了你了你必须去看服务端代码到底做了什么。比如一个URL参数你传http://xxx.com它就去请求外网你传file:///etc/passwd它可能就把服务器上的文件内容加载出来了。这个参数到函数再到资源的链条不亲手画一遍、不亲自在靶场里试错光靠背payload是记不住的。另外这个阶段的题目还考察一个容易被忽略的能力信息收集的耐心。很多题不是一步到位的拿到一个flag可能需要先探测端口、发现内网服务、再通过协议利用拿到shell最后才有flag。这种层层递进的做题节奏对新手来说是很好的思维训练。2. SSRF专题从“能发请求”到“会打内网”的跨越2.1 SSRF到底是怎么产生的SSRF这个概念用大白话说就是本来是你客户端去访问一个网址但因为服务端代码把URL地址这个参数拿来直接用了比如curl($_GET[url])或者file_get_contents($_GET[url])变成服务器替你去访问了。这时候你给的URL地址就很关键了你给的是一个公网地址服务器就帮你访问公网你给的是http://127.0.0.1:6379/服务器就会去尝试连接它自己本地的Redis端口。这个行为本身极其危险因为服务器和内网是天然信任的很多内网服务不会做严格的访问控制一旦服务器能主动去访问它们相当于给攻击者递了一把伸进内网的手。CTF里最常见的SSRF出题点就是URL参数。进入内网之后目标通常有两类读文件用file://协议直接读取服务器上的本地文件。探端口、打内网服务用http://或dict://协议探测内网开放的服务端口再结合漏洞利用。2.2 协议选型file、http、dict、gopher各自怎么用这个阶段的题目玩的就是一个协议选型问题。你手上握着几种协议每种协议的利用方式差别很大不能搞混。file://协议最简单直接用来读本地文件。比如第一个SSRF题常常就是构造一个file:///etc/passwd的请求flag文件直接摆在服务器某个路径下读出来就行。这类题属于送分题基本考的是你知不知道有file://这种协议存在以及路径拼接的细节——比如是file:///flag三个斜杠还是file://flag这跟服务端解析URL的方式有关需要在靶场里实测。http://协议适合做内网端口探测。当你猜到一个内网IP段最常见的就是127.0.0.1和10.x.x.x这类可以用http://127.0.0.1:端口/的形式去探测端口是否开放。很多题目还会给你一个内网地址列表让你通过SSRF去访问某个内网Web服务拿到只有内网才暴露的页面上的flag。dict://协议是一个很容易被忽略但很好用的协议。它本来是用来访问字典服务的但可以用来向任意TCP端口发送简单的请求。比如你想探测内网一个Redis服务的版本可以构造dict://127.0.0.1:6379/info它会把info命令发过去并接受返回。这种探测方式在CTF里很常用因为它不需要你写复杂的脚本直接在URL里就能完成。gopher://协议是最重量级的。它允许你向任意TCP端口发送构造好的、任意内容的请求相当于你可以伪造Redis命令、FastCGI请求甚至整个HTTP请求。在CTF里最常见的利用是通过gopher打内网的Redis服务用set命令写一句话木马到Web目录或者写计划任务反弹shell这里注意反弹shell也好、写木马也好都必须在CTF靶场环境内进行不能对真实系统操作。构造gopher协议payload的核心难点在于URL编码层数、协议头构造、目标服务的协议细节。我用过的工具是Gopherus可以一键生成Redis、MySQL、FastCGI等服务的gopher payload非常省时间但前提是你得知道目标服务开在哪个端口、服务类型是什么。2.3 绕过过滤的思路让服务器“认错”地址前几道SSRF题可能是直给的后面的题就开始设卡了。最常见的过滤是服务端检查你传入的URL必须是以http://开头才能请求或者干脆做了关键词黑名单把127.0.0.1、localhost、file这些词直接拦截掉。面对这种情况需要掌握的绕过思路基本有这几类IP地址的进制混淆127.0.0.1可以写成整数形式2130706433或者八进制形式0177.0.0.1十六进制0x7f.0.0.1。很多过滤是基于字符串匹配的看到127就拦截但它不认识数字换成进制之后的等价表示。域名解析绕过用一些特殊域名指向127.0.0.1比如localtest.me这类如果服务端只过滤localhost这个关键词而不过滤域名就能直接绕过。URL解析差异绕过利用http://baidu.com127.0.0.1/这种形式很多URL解析库解析到后面的地址但语法检查时看起来是一个正常的域名。还有一种情况是利用#锚点截断http://127.0.0.1#.com某些解析器看到结尾的.com就认为是外网域名放过了但实际curl请求的是127.0.0.1。302重定向绕过这是比较骚的一招思路是你自己准备一个公网服务器上面放一个302跳转跳转到内网地址。服务端如果对重定向不设防就会跟着跳过去。实操时可以在自己的服务器上用几行代码搞一个简单的302跳转服务。提示这些绕过技巧我建议你在靶场里一个一个试不要只看wp。每个平台的过滤方式不一样你亲手试过才知道为什么这个写法能过、那个写法过不了这对理解URL解析的底层机制非常有帮助。3. 文件包含专题PHP伪协议是绕不过去的坎3.1 从包含漏洞到代码执行的链路过了SSRF那几道题马上就会撞上文件包含。文件包含漏洞的产生原因很简单服务端为了代码复用会把一些模板文件、页面组件用include($_GET[page])这种形式加载进来但变量page是用户可控的导致你能控制被包含的文件名。这个漏洞的核心玩法在于当包含什么由你说了算的时候你能不能把包含目标变成一个可以产生实际影响的东西比如包含一个远程服务器上的恶意代码文件或者包含一个PHP伪协议来读取源码甚至包含一个日志文件把一句话木马写进去。3.2 php://filter 读取源码最稳的起手式在文件包含题里flag往往不是明晃晃放在 /flag 下让你直接include而藏在PHP源码里。那怎么在不能直接执行代码的情况下看到源码这时候就要用到php://filter这个伪协议。它的标准用法是php://filter/readconvert.base64-encode/resourceindex.php这行的意思用大白话说把index.php的内容读出来然后base64编码之后返回。为什么要base64编码因为PHP文件本身有?php ?标签如果不编码就直接包含这些代码会被服务器当成PHP执行你就看不到源代码了。先base64编码一下输出的就是一堆纯文本源码内容全都能看到。实际操作的时候我一般会先包含index.php看看源代码里有没有flag或者线索没有的话再通过代码里的提示去包含flag.php。这里有个细节resourceindex.php里的路径是相对路径要从当前工作目录开始写有时候直接写文件名不行得写完整的./index.php或者根据目录结构写../xxx/index.php这是个容易卡住新手的坑。这个阶段还考过一个经典变形把读取的文件换成攻击者的思路比如php://filter/convert.base64-encode/resourceflag.php如果直接读不了可以考虑用多级过滤器链比如convert.iconv.*系列过滤器来构造任意文件读取甚至RCE。这里我不展开全部filter链的细节但提醒一句filter链算是文件包含的高阶玩法第40-50题里可能会碰到一次能掌握基础用法就行后面进阶再深入。3.3 php://input 与 data://从读到执行当文件包含漏洞遇上 allow_url_includeOn 的配置就会产生质变——你不仅能包含文件还能执行代码。php://input这个伪协议作用是把POST请求的请求体当作文件内容来处理。配合文件包含攻击方式就是用POST方法发送一段PHP代码然后把这个请求体作为被包含的文件执行。POST /?pagephp://input HTTP/1.1 Host: target ?php system(ls /); ?由于POST体里的内容被当成PHP代码执行了你就有了一条直接命令执行通道。这个方法简单粗暴前提是环境开了allow_url_include不然php://input不可用。另一个思路是data://协议它可以直接把URL里的数据当作文件内容。构造方式如下/?pagedata://text/plain,?php system(ls /); ?如果代码里对?php这种尖括号做了过滤还可以用base64编码绕/?pagedata://text/plain;base64,PD9waHAgc3lzdGVtKCdscyAvJyk7Pz4这两个思路我放在一起说是因为本质都是把可控数据变成可执行代码区别只在于数据传输的载体不同。做题时先看phpinfo或者报错信息判断哪些伪协议可用再决定走哪条路。3.4 日志包含服务器自己写出的“后门”并不是所有文件包含题都开了allow_url_include这时候php://input和data://就废了。那怎么办还有一条经典路径包含日志文件。Web服务器比如Nginx会把每个访问请求记录到日志文件里比如access.log里面包含请求的User-Agent、URL等信息。思路就是你先构造一个带恶意PHP代码的请求服务器把这段代码当作正常请求内容写进日志然后你再通过文件包含漏洞去包含这个日志文件日志里的PHP代码就被执行了。具体做法是这样先给一个正常的GET请求URL参数不变但在User-Agent头里写入?php system(ls); ?。服务器把这行原样写进/var/log/nginx/access.log。然后你构造?page/var/log/nginx/access.log把日志文件包含进来User-Agent里那段PHP代码就执行了。我用这种方法时踩过一个坑日志文件特别大包含的时候响应会非常慢而且日志里的PHP代码被触发时会把整个日志都输出出来造成页面内容很杂乱。这时候可以在payload里加点特征字符串比如LEO包含之后先搜索LEO出现的上下文就能精准定位输出。类似的路子还有包含/proc/self/environ文件这个文件里也存着HTTP请求头信息包含它也能触发代码执行。但Nginx环境下通常读不到Apache CGI环境读到的概率更大。做题时多试试几个路径哪个好用用哪个。4. 命令注入与日志利用getshell的另类路径4.1 命令注入的过滤绕过套路这一阶段有些题表面上是文件包含或者别的漏洞但最终getshell的路径是通过命令注入。命令注入的产因是服务端代码把输入拼进了系统命令的字符串里比如system(ping . $ip)这种。你传入的不是一个IP而是127.0.0.1; cat /flag分号分隔了前后两条命令后面的cat /flag就被执行了。过滤拦不住你的情况很常见经典的绕过姿势我整理过一批过滤点绕过方式分号过滤用%0a换行符或者、||替代空格过滤用${IFS}替代或者$IFS$9、重定向字符关键字cat、ls过滤用变量拼接比如cat、c\at、或$(printf cat)反引号过滤用$(命令)形式替代有个很实用的经验过滤规则是黑名单还是白名单做题方式完全不同。如果只过滤了某几个关键词黑名单可以无限换写法去绕如果只允许某几个字符白名单那就得考虑无字母数字webshell的路子了那个复杂度就上去了。第40-50题目前最多卡在黑名单层面每个都记录下来后面考命令执行的题目可以直接套。4.2 通过文件包含getshell的完整攻击链在CTF实战里文件包含和命令注入常常是串联起来的。比如一个文件包含题常规思路有三种我按优先级排伪协议直接执行如果能用php://input、data://。日志包含getshell当伪协议受限但能包含绝对路径文件。远程文件包含allow_url_include打开时直接包含一个放在你自己的临时服务器上的txt文件里面写着PHP恶意代码。一个典型的攻击链长这样先用php://filter读源码在源码里发现Nginx日志路径再用普通请求往日志里注入PHP代码最后用include(/var/log/nginx/access.log)触发代码执行拿到shell然后找flag。这套链路里每一步都有坑。往日志里注入的时候URL里直接写PHP代码会被 URL 编码转义最好的地方是User-Agent因为它通常不会被转义太多。还有日志路径不确定的问题我一般是读/etc/nginx/nginx.conf找到日志路径或者从源码里直接找。这个阶段如果能独立打通一条完整的日志包含getshell链路那你对文件包含的理解基本就到位了。5. 实战解题流程复盘从读题到拿flag的标准作业5.1 我自己沉淀的解题SOP整个40-50题刷下来我整理出一套自己用的做题流程每次碰到新题都先按这个走效率高不少读题找参数先看URL上有哪些参数是可用的常见的?url、?page、?file、?img这些参数名本身就是强烈暗示。先试无害请求把参数改成内网地址或本地文件观察响应差异。比如你传http://www.baidu.com看它会不会真的请求这个网站并返回内容传file:///etc/passwd看会不会报错提示不应该出现的信息。读源码看逻辑如果存在文件包含优先用php://filter读index.php等关键文件搞清楚服务端到底过滤了什么、拼接了什么。这一步往往能直接看到flag文件路径或pass。确定利用协议根据能不能读源码、有没有开远程包含、过滤规则严不严决定走伪协议执行、gopher还是日志包含。按需构造payload先在本地环境把payload测通再去靶场打。第5步是我特别想强调的。CTF题目里的payload不是纯靠背的要结合题目环境变量来改。比如gopher协议构造Redis命令时命令里的路径、文件名都要根据源码和目录结构来定制直接拿网上的通用payload去怼很容易失败。5.2 我常用的效率和排错工具这个阶段我用到的工具其实不多但每样都用得比较深Burp SuiteSSRF题必须用Burp来抓包改包尤其是往请求头里注入日志payload的场景只在浏览器地址栏里改URL完全不够用。我用Burp的Repeater功能反复试探各种payload变体比每次在浏览器里重新输入省太多时间。Gopherus生成gopher协议payload的神器。之前手动写gopher载荷要在URL编码和原始请求之间反复改来改去很容易出错Gopherus直接按目标服务类型生成好省心。本地PHP环境有些payload拿不准我在本地搭一个相同版本PHP的环境先跑一遍确认语法和执行效果再上靶机。这一步建议有条件的一定要做尤其是filter链和伪协议相关的payload本地验证一下能少走很多弯路。6. 踩坑记录与排错思路那些让我卡了一个小时的蠢问题6.1 文件包含题常见问题速查刷这一组题的时候我在同一个坑里掉进去过好几次有些问题事后回头看特别蠢但当时确实卡了很久症状原因解决办法payload代码没执行原样显示在页面上伪协议没有生效allow_url_include没开换日志包含思路别死磕php://inputphp://filter读出来是乱码base64编码后直接当文本显示了没有解码把响应内容丢进Burp的Decoder或在线工具base64解码包含日志文件后页面卡死日志文件太大输出内容过多payload加特征字符串请求头里用随机标记再在响应里搜索标记定位gopher payload打过去没反应URL编码层数不够请求没被正确还原检查编码层数服务端解析一层就多编一层一般至少两层内网IP探不到网段不对payload写死了IP根据题目提示比如源码里的ip段换网段试别盲打6.2 几个我印象深刻的教训第一个教训是不要轻视读源码这一步。有一道题我没读源码就直接拿payload去试试了半小时都失败后来老老实实php://filter读源码发现里面过滤了localhost和所有IP形式但没过滤127.0.0.1的八进制写法0177.0.0.1伪造一个八进制IP就进去了。你说这玩意靠盲试得试到什么时候。第二个教训是日志用户代理注入时一定要保持格式干净。我有次往User-Agent里写PHP代码那行代码里带了空格和分号导致日志被截断或者转义折腾了很久才发现是User-Agent里不能带空格会被记录成 %20 之类。后来我改成在User-Agent里写?php system(ls);?并且确保没有多余空格问题才解决。这个细节靶场里不同环境还不一样需要多试几次。第三个也是最重要的教训多注意payload里的编码问题。无论是SSRF里绕过IP形式还是文件包含里的base64编码都是最容易出错的环节。看起来一模一样的payload差一个URL编码层就是执行和不执行的区别。我现在做任何payload都习惯在Burp里把原始请求和编码后的请求对照着看一遍确认没有重复编码或漏编码。6.3 最后给后来者的一些心得刷到第40-50题这个阶段我的心态已经从求数量变成了求理解。题目做完了不是终点我会回头想三件事第一这题的漏洞点本质是什么代码逻辑导致的如果让我自己写一段有漏洞的代码我会怎么写把这两件事对上号下次换个马甲出现我就不慌了。第二这道题的过滤有没有别的绕过姿势我每次解完题都会顺手把其他绕过方法也试一遍比如题里用file://读的我会把http://的绕过也试一遍不为别的就是练手感。第三能不能把这道题的思路迁移到别的题型SSRF里的IP进制绕过在命令执行的waf绕过里也能用日志包含的思路遇到LFI题目都能拿来当备选方案。知识就是这样一点一点串成网的。希望这篇文章能帮你在这个阶段少踩几个坑。刷题这件事本身没有捷径但站在别人踩过的坑上至少能让你爬坡的时候稍微稳一点。

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

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

免费获取报价 →
↑