如何写好CTF Writeup:从解题思路到结构化输出的完整指南

发布时间:2026/10/18 15:47:49
如何写好CTF Writeup:从解题思路到结构化输出的完整指南 很多人在赛后看完题目第一反应就是“我这题会做写个 Writeup 就完事”贴一段代码放一张 flag 截图再甩两行“学到了”。这种写法看着完整实际上你三个月后回头翻大概率想不起来当时卡在哪、为什么绕了这么大一圈。CTF 真正值钱的从来不是最后那串 flag而是题目向你亮出底牌、你一步步把它拆开的过程。写一篇合格的 CTF Writeup本质上不是记录是把你解题时的非线性思路压成一条别人能跟着走完的线性路径。这篇文章我不打算复述那些翻来覆去的基础理论而是从写作目标、结构方法、分题型套路到发布流程完整走一遍我自己在上百道题里磨出来的写作框架。看完你能直接拿着模板去套也能知道哪些写法会让自己掉价。1. 先把“写不出来”这件事说透1.1 你其实不缺技能缺的是表达套路不少人觉得自己写不好 Writeup 是因为“表达差”“语文不好”实际操作里根本不是这么回事。你缺的是把解题过程结构化拆解的套路。举个例子你解一道密码学题目脑内的路径往往是“看到密文尾部有 想到 base64解码后又是一段字符串再观察字符频率想到替换表最后还原出 flag”。这个过程中真正有价值的信息不是“用了 base64 和替换表”而是“你为什么在第一步会选择 base64”。让你写不出来是因为你不知道该把脑内闪过的这些判断依据放到哪里。我的解决方法很简单把每一步都切成“输入—判断—操作—结果”四段。输入是什么你基于哪些特征做了判断实际动了什么操作得到什么结果。别小看这个笨办法它能把你从“不知道从哪下笔”直接拉进“照着记录翻译成文字”的状态。熟练之后你甚至不需要真的写四段在草稿里用“看到 X → 想到 Y → 验证 Z”的箭头随手记就能自动生成一篇完整逻辑链。1.2 Writeup 的三个服务对象评委、队友、未来的自己不夸张地讲很多人对 Writeup 到底写给谁看是没想清楚的。我建议你直接把它当成有三个服务对象这三个人的需求完全不同。第一是评委或出题人。出题人最想看到的是“你有没有踩到考点”而不是“你有没有解出 flag”。一道 Pwn 题考点在栈迁移你全文却只写“用工具打出来了”这等于告诉出题人“我没理解考点只是抄了现成脚本”。所以写题解时一定要明确写出“这题要考的是哪一块防御机制、哪一处溢出点”哪怕判断错了也比你完全不提强。第二是队友。你赛后要跟队友复盘他们需要快速知道哪里能复用、哪里是坑。如果写得含糊队友要么刨根问底问你十分钟要么直接放弃阅读。这其实倒逼你把每一步写清楚让看的人能在两分钟内定位到“这题的关键解法是什么、难点卡在哪”。第三是未来的自己这是最容易被忽略的。我常说Writeup 是写给半年后的自己看的另一个自己。一个只有贴图的草稿半年后你根本看不懂一份记录下当时的疑问、猜错方向、验证过程的完整文档才是你参加下一场比赛时真正值钱的经验库。很多高水平的选手根本不把 Writeup 当成发给别人的东西他们就是写给自己看的解题笔记发布只是顺带。想清楚这三个对象你的写作优先级就会立刻发生变化考点分析 完整逻辑 复现细节 观赏排版。这跟你之前可能默认的“排版要好看、代码要漂亮”是完全相反的。2. 从零搭 Writeup 骨架一套能直接抄的写作框架2.1 赛题信息头一份自带检索价值的问题画像我看过太多 Writeup 的第一行直接是“这题是 RSA”。除非你是看完当场写、当场发否则这种开头没有任何信息量。一个合格的赛题信息头应当包含题目名称、题型、知识点、难度、赛后状态这几项。不要小看它这是你整个 Writeup 的元数据也是未来检索的门面。我习惯用类似这样的信息头题目名称某签到题 题目来源某线上赛-Crypto方向-签到 知识点自定义 Base64 替换表 / 字符频次分析 难度入门 状态赛时解出 / 赛后复现这几行字眼看起来琐碎但在你积累了几十篇之后价值会呈指数增长。想象一下下次比赛遇到一道新题你只需要在本地笔记里搜“替换表”三个字就能立刻翻出这篇历史 Writeup照着里面的经验直接下手比你在赛时对着搜索引擎大海捞针快得多。标题命名也要为检索服务我最常用的规则是“平台缩写-题型-题目名-考点”比如“某赛-Crypto-签到-替换表”。搜索引擎看到的标题和你看的自己笔记的标题越具体反而越好。2.2 从解题思路到输出路径怎么把脑内过程变成线性文本这一节是我觉得最有用的部分。很多人卡住是因为解题时思路完全是网状的脑子里同时挂着好几个没验证的猜测而文章是线性的必须一个点一个点写出来。这就要做“线性化”处理。我的做法分两步。第一步先用零碎笔记把整个解过程拉出主干题目给了什么、你观察到了什么、第一反应是什么、实验验证了什么、哪里卡了很久。第二步把主干收敛成一条主线通常就是“从输入数据到 flag 的这条数据流”然后再把支线的失败尝试挪到后面的“踩坑记录”里而不是塞进主流程。举个例子做 Web 题时你可能同时尝试了 SQL 注入、目录扫描、源码泄露三条路最终发现是源码泄露里的备份文件给出了数据库账号。那你的主流程就应该写“发现备份文件 → 还原源码 → 找到账号 → 登录后台拿 flag”。你前面花掉两小时试 SQL 注入的过程不要删放到后面的踩坑记录里一句话带过“先试了 SQL 注入无果因为过滤了关键字后转为源码审计”。这样做既保证了主线干净又不丢失宝贵的负向经验。2.3 截图、代码和日志的摆放顺序排版问题看起来是表面功夫实际上它直接影响读者能不能看懂。我的准则是所有验证性的证据紧跟其对应的结论而不是全部堆在最后。比如你说“发现字符串尾部有 特征”这里就该配上截图或命令输出你说“执行脚本得到以下结果”紧接着就是输出片段。一图一结论读者完全不需要上下翻页对照这种体验才是专业 Writeup 应有的。代码块也同理。不要把完整脚本全部扔到末尾当附录最好把核心代码按步骤拆开。如果你用了别人的开源脚本一定要注明来源并且只保留和当前题目相关的调用部分不要整段贴上几十行和题目无关的代码。对了别忘了给脚本里的关键参数加注释比如“这里替换成题目给出的密文”“这里是模数 n”。没有注释的代码别人拷下来跑不出来你写等于没写。3. 分类型 Writeup 的撰写套路密码学 / 逆向 / Web / Pwn / 取证3.1 密码学类讲清“怎么想到这个攻击面”密码学题目前最核心的一个问题不是“用什么算法解出”而是“我怎么从题目给的这堆字符判断出攻击面”。很多人写完密码学 Writeup只写一句“这是一道 RSA 题直接攻击低指数”就完事了。这完全漏掉了出题人设置的特征密文很短、e 很大、c 的位数远小于 n这些才是你需要写出来的判断依据。我在写密码学方向时会额外加一小节叫“题目特征”。这一节非常简单就是把题目输入里“一眼能看到的特征”列出来比如密文由可见字符组成、长度固定、base64 特征符、重复出现的模式。接着写“由这些特征我推测”然后再进入实际攻击过程。这比单纯罗列算法公式更能帮助读者建立“看到特征 → 想到方法”的思维。举个签到的例子。题目给了一段包含大小写字母和数字的字符串末尾带两个等号傻瓜都会先做 base64 解码。但如果你只写“base64 解码得到 flag”那没人会感谢你。你应该写“末端等号强烈暗示 base64但直接解码后是乱码注意到字符串中的字母顺序和标准 base64 索引表不一致怀疑是自定义替换表于是编写脚本用题目里给出的替换表替换回标准表后再 base64 解码得到 flag。”你看这里面的每一步都清晰地连接着观察和判断而不是“启动脚本-得到 flag”的两点一线。另外密码类题目一定要把你的攻击脚本贴全。原因很简单密码逻辑是纯函数式的别人要想真正理解某个参数怎么参与计算没有完整代码根本没法推敲。哪怕脚本只有十几行也要保证用户直接复制后把输入文件换成自己的题面就能跑出结果。那种贴半段脚本把核心参数隐藏起来只为了显得自己厉害的做法是最让人反感的。3.2 逆向与 Pwn从静态定位到动态验证逆向和 Pwn 的 Writeup最重要的不是“贴出最终 payload”或者“贴出 flag”而是把“定位关键函数”这个过程讲清楚。因为这类题目的真正难度不在最后那一次利用而在于你如何在茫茫代码里找到关键的校验逻辑或漏洞点。我的理想写作路径是先说程序的基本行为这个程序接受什么输入输出什么有没有交互界面有没有 anti-debug再做静态分析你用了什么工具搜索了哪些特征字符串比如 main 函数里的提示语、报错字符串、可疑的调用然后定位到关键函数或溢出点这里必须贴出关键反编译伪代码并配上自己的标注。最后再用动态调试验证你的分析假设。这个顺序不能反一旦你先写了动态调试读者会觉得你根本不知道自己在干什么纯粹靠瞎试。举个例子某道模拟程序逆向题我先用字符串搜索发现一段提示语“Congratulations”交叉引用到一处比较函数。这时候在 Writeup 里应该写“看到这个字符串后我意识到程序最终会把用户输入和某个内部值进行比较。于是我在比较指令处下断点动态运行观察寄存器中存储的内容发现是一个由固定算法变换后的值。”看到没有静态定位和动态验证是互相咬合的。你不需要事无巨细地记录每一条汇编指令但关键节点的截图和寄存器值非常值得写。还有一块很实际的东西Pwn 题中偏移量怎么来的。很多新手直接写“偏移为 112”然后没有人知道他怎么算的。要写成“用 cyclic 模式串生成 200 字节输入程序崩溃后记录崩溃地址在模式串中的偏移为 112”。这既是结论也是方法。以后你再遇到类似的题只需要改个模式串就能复用。3.3 Web 与取证类按数据流向写Web 题是最忌讳“想到什么测什么”的。如果你写的时候也是想到哪写到哪读者会认为你的解题流程毫无章法完全是靠扫描器和运气。我的建议是任何 Web 题都沿着“前端 → 服务端处理 → 数据存储/回显”这条数据流向去写。比如一道带文件上传的题你探测到存在过滤后要写的不是“过滤了后缀名于是改后缀名绕过”而是把请求和响应包都贴出来说明你通过响应包含哪些特征定位到后端用了哪种解析逻辑。再往下的反弹动作、路径、回显位置也要一步步交代。读者只有看到你是如何处理每次请求中微妙差异的才会真正相信你是会写 Web 题而不是靠工具扫出来的。取证类题目则完全不同。它的核心不是“攻击”而是“还原”。你写的时候要从已知的磁盘镜像、内存镜像、流量包出发像侦探一样逐个排查线索。流量分析尤其要按时间线展开先看到哪个数据包、发现什么可疑协议、顺着通信找到哪个恶意脚本、接着这个脚本做了什么。如果只贴最后几张关键截图过程就缺了链条读者根本不知道你怎么把线索串起来的。我自己的习惯是给取证类 Writeup 先画一个时间线列表“第 1 秒发现什么 / 第 2 步关联到哪个文件 / 最后如何恢复出密钥”写成章节标题读起来一目了然。3.4 Misc/隐写等其他方向的通用模板Misc 是所有杂题的收容所但这并不意味着你可以随便写。我总结出这样一套通用模板适配隐写、流量、社工、密码之外的任何题目第一段写“题目给了什么”包括文件名、文件类型、大小、备注信息、压缩包是否加密。第二段写“我按什么顺序尝试了哪些分离工具”文件尾部附加数据、E X I F 信息、LSB 隐写、图种等。这个“顺序”很重要不同隐写手法出现在同一题里的概率差异很大写下来能让别人也继承这个经验。第三段写“找到隐藏数据的标志”比如看到一段连续的十六进制里出现“PK”开头就知道是 zip 压缩包看到图片像素 RGB 最低位出现规律的 0/1 序列就猜测 LSB。最后一段写“如何还原出最终数据”。Misc 题目的知识点非常零散所以这种模板化的写法其实是一种降低认知负担的方式你不需要每次重新发明结构只需要按固定框架往里填内容即可。4. 实战写作流程从解出 flag 到发布一共五步4.1 解题后的 10 分钟“验尸式”复盘这个环节是我墙裂推荐的。每次你解出一道题在比赛还没结束或者刚结束的热乎劲里立刻花 10 分钟做一次复盘。不要急着写长篇大论只做两件事回忆“我最初的尝试路径”以及“我最终为什么转向了正确路径”。用一个空文档或你的笔记软件快速按时间线把关键节点记下来哪一步卡了半小时、哪一步豁然开朗、哪一步靠的是纯试错都记录下来。这两个问题的记录就是你未来 Writeup 中最具特色的“方法论”部分的原材料。我可以很负责任地告诉你如果赛后两个小时再写你的记忆就会开始美化把大量试错过程丢掉只剩下一条光鲜的成功路径。那样的 Writeup 错失了对后来者最有帮助的失败经验。趁热打铁写 10 分钟胜过冷下来回想两小时。4.2 结构化记录与草稿展开复盘记录完成之后第二步是把零散笔记展开成结构化草稿。你可以直接拿我在第 2 节里给的信息头加主线框架来搭或者套用第 3 节里分类模板的骨架。总之先不要关心措辞和排版优先确保逻辑链条完整。流程大概是把题目信息头复制进来写下“题目特征”和“我的第一步判断”然后按步骤把验证过程铺开最后补上“踩坑记录”。这一阶段我经常使用一个技巧把某个环节当成你在教一个基础尚可的队友强迫自己把跳过的步骤补回来。比如你写“执行脚本得到回显”就要问一句“脚本里的这个参数是怎么从题目数据里提取出来的”把这个问题的答案补进草稿就是在填补逻辑空洞。等草稿完整后你再开始润色语言。千万不要边想逻辑边润色否则你大概率会陷入字句优化的泥潭文章反而半天推不出来。4.3 用最小 Demo 验证脚本可复现性一篇 Wrtieup 写到“脚本可复现”这个程度才算真正完成。很多人贴代码的时候用的是赛时在临时目录里改得乱七八糟的版本变量名都是 a、b、c甚至还有硬编码路径。这种东西贴出来别人根本没法跑。所以在发布前我会单独建一个干净目录重新 copy 一份脚本用一个模拟输入跑一遍确认输出结果和题目一致。这还没完还要注意依赖环境。脚本用到了哪些第三方库版本大概是多少Python 版本是什么最好都写进题目信息头或者代码注释。遇到那种只能在特定环境跑的破解脚本也一定要注明运行环境比如“需要 Windows 某调试器配合”否则别人复制到你脚本后跑出一堆报错不仅浪费对方时间也会让读者心里给你这篇文章打个大大的差评。4.4 配图和排版的几个硬性建议配图这块我见过的最常见问题是三个一是截图太糊二是截图没有标注重点三是图文割裂。关于截图我建议使用带命令行高亮的终端主题并且把关键输出圈红或高亮。Windows 上很多人直接整屏截图截出来的图里包含无关的桌面背景这其实是不专业的表现。裁剪到只保留终端窗口或代码区域再在关键行加一个简洁的标记显然更有说服力。排版上的另外一个细节是全文语言角度要统一。我习惯全部用第一人称“我”来叙述“我观察到”“我尝试”“我猜测”。不要一会儿“我们”一会儿“攻击者”这样会让读者难以代入。最后是用标题分层一篇 1500 字以上的 Writeup起码要分成三到五个小节。层层递进的小标题不仅是为了美观更是为了帮读者梳理逻辑让他们哪怕只扫一眼小标题也能抓住你的解题骨架。5. 避坑实录那些写出来就掉价的做法5.1 过度省略 vs 过度抄源码这两个极端我都见过。过度省略的表现是“这题是解密直接上代码”没有流程没有判断依据只有一堆代码和结果。过度抄源码的反而是另一种灾难把整个项目的源码几百行全部贴上来里面百分之八十都是与题目无关的初始化代码。真正的优秀 Writeup 是两者的平衡核心思路讲清楚关键代码完整给出无关代码一行不贴必要时用一句注释交代。说白了你要时刻问自己一个问题“我贴出来的这行代码对读者理解题目有没有增量信息”如果没有就删掉。判断依据是这段代码是在解决“这个题的特殊点”还是在描述通用工具调用通用步骤用一句话带过就行比如“用二进制编辑器查看文件头发现它不是标准压缩包格式”完全不需要把二进制编辑器怎么打开写出来。5.2 把踩坑过程藏起来的后果很多人为了显示自己聪明会把踩坑过程全部隐去只保留最顺滑的那条成功路径。这是最大的浪费。因为你经历过的每一个无效方向恰恰是未来读者最可能重蹈覆辙的地方。从信息密度来看一段“我先试了 X失败了原因是 Y于是改走 Z”的内容远比“我直接做 Z 成功”更有价值。当然这不是让你把每一个失败的细节都写进去。我的判断标准是这个坑是否具有普遍性如果是题目边界条件导致的特例可以一笔带过如果是某种攻击手法在该类题目里的共性反模式值得写进“踩坑记录”。比如 SQL 注入过滤了空格于是你用注释符替代空格这个坑就有通用价值必须写。相反某个题目因为后端逻辑写错导致你没打通这种一次性问题就没必要占用篇幅。5.3 写得“优雅”但不可复现这里说的“优雅”指的是那些把代码简化得过分、让人看不懂的写法。比如有些人为了秀技巧把一个简单的字符串处理用匿名函数嵌套写成一串看起来赏心悦目但去执行时漏了一个依赖结果根本跑不出和题目一致的结果。Writeup 的代码不是比赛现场秀肌肉它的唯一目的是让读者复现结论。所以我在自己的代码里会故意保留“笨”的可读性写法变量名用明文比如 ciphertext、plaintext、original_str注释写清楚参数来源关键的 print 输出直接暴露中间结果。为了让脚本可复现我甚至会故意把脚本分成两段第一段做解析和数据预处理第二段做核心算法的调用。这样就算读者只想理解某一段也能独立看懂。5.4 搜索引擎可见性与标题命名你可能觉得这是一件小事但实际影响很大。很多 Writeup 的标题直接写“签到 wp”“某题 writeup by xxx”根本不成系统。如果你认真对待自己的笔记和输出就应该让标题里包含足够的关键词让未来的自己或同方向新手用搜索引擎能找到。推荐的命名格式是“赛事缩写 题型 题目名 考点关键词”比如“某赛 Crypto 签到自定义替换表”。正文头部的信息头也应当保留因为搜索引擎在抓取页面时会把标题、正文首段信息作为重点。更重要的在你发布到社区或个人博客时正文开头不要立刻放代码而是先用自然语言把题目背景和考点梳理清楚。这样别人搜索相关知识点时更能命中你的页面你也更有可能收到同好者的反馈和讨论。6. 从“会写”到“会教”Writeup 的进阶价值6.1 把 Writeup 当作最小教学单元从我的经验来看认真写 Writeup 这件事给你带来的最大回报不是被社区点赞而是训练你“把复杂问题讲清楚”的能力。一篇好的 Writeup 天然就是一个最小教学单元它有背景、有目标、有步骤、有验证、有易错点本质上和一篇小教程没有任何区别。反复练习这种写作会让你自然而然地开始思考“当一个完全没接触过这个知识点的人读到我这句话会不会卡住”。我自己的一个明显感受是写满几十篇之后再回头去学习新方向的题目脑子里的学习策略都会变得不一样。看到一份别人的 WP我会下意识拆解它的结构判断它哪一块写得好、哪一块有逻辑断层这比闷着头刷题效率高得多。所以不要把这当成了“赛后的作业”接力全当成一次刻意练习。6.2 建立自己的案例库与标签体系如果你只是写、发、扔那这些 Writeup 的价值仍然没有被你充分榨干。我强烈建议在本地维护一个案例库按“方向 / 考点 / 难度 / 是否解出 / 关键工具”这些标签给每篇 WP 分类。这一步很像给树苗做支架——一开始多花十几分钟后面整个学习资料库就能自己生长起来。实操时我常用一份表格维护字段包括日期、赛事、题目、方向、考点、状态、链接或本地路径、一句话备注。下次遇到新题先翻这个表格看考点有没有重合。这个习惯帮我在赛场上省下大量时间。比如某次比赛遇到一道“通过时序侧信道逐字符恢复消息”的题我立刻在表格里找到上一次类似的题目直接拿旧脚本改参数省掉了一半分析时间。6.3 我的个人体会聊到这儿我还想再分享一个很私人的感受。刚开始我也觉得写 Writeup 是为了给别人看越到后来越明白它是我自己比赛能力的记账本。那些只贴在收藏夹里没整理的题目和过眼云烟没有区别那些认真写成文章并打上标签的题目才真正变成了我知识体系的一部分。我现在的习惯是每场比赛结束后不急着发布任何东西先把所有解出的题目按结构写完保存到本地案例库。发布只是一件顺手的事写作本身已经让我把每一道题学了两遍。我希望你能试试这个方法坚持十篇之后再回看第一篇你会明显感受到自己在分析逻辑和表达上产生的变化这种变化带来的成就感远比拿到一个 flag 更持久。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询