
1. 内容整体设计与思路拆解1.1 FLAG 为什么是 CTF 的“终极目标”CTFCapture The Flag夺旗赛的核心玩法很简单——题目里藏着一个字符串叫 FLAG你把它找出来、提交上去就能得分。比赛排名看的就是谁能更快、更稳地把这个字符串“薅”出来。某种程度上FLAG 就像一场寻宝游戏里的宝藏坐标解题过程就是你根据各类线索一步步逼近坐标的过程。很多刚接触 CTF 的朋友容易走进一个误区以为 FLAG 一定藏在某个固定的、显眼的地方。实际上FLAG 的藏法千奇百怪——可能就在网页源码的注释里可能在流量包某个不起眼的 TCP 流里可能藏在图片的 EXIF 信息里也可能需要你修复一个损坏的压缩包才能看到。我打了几年 CTF最大的体会是与其漫无目的地刷题不如先把“FLAG 都藏在哪些地方”这个问题彻底摸清楚。这篇训练笔记是系列第五篇打算专门把“获取 FLAG 的常见方法”系统整理一遍。我按 CTF 最常见的几个方向——Web、杂项、隐写、逆向与 PWN——把典型的拿 FLAG 路径拆开讲每一条方法都会结合真实题目场景说明“为什么这么找”。由于内容量确实大这篇先整理到一半后续实战中遇到新思路我会继续补充。1.2 拿到题目后的第一反应判断 FLAG 的藏匿维度我见过不少人在题目上耗了几个小时最后发现 FLAG 其实就在眼皮底下。问题往往出在“一开始就没判断清楚 FLAG 的藏匿维度”。这里我说的“维度”指的是FLAG 到底藏在数据文件里、藏在协议交互里、藏在程序运行逻辑里还是藏在某个加密/编码的变形中判断维度的方法其实很朴素——先看题目类型和题目描述。Web 题目的 FLAG 通常在服务端需要通过漏洞拿到杂项题目的 FLAG 通常在给出的附件中需要通过拆解文件、分析隐写、解码等方式提取逆向和 PWN 题目的 FLAG 往往在你成功利用程序漏洞或逆出算法后由远程服务直接回显密码学题目的 FLAG 则大概率藏在密文背后需要你识别加密方式并还原明文。这个“第一反应”特别重要。因为在 CTF 里效率就是分数。你花 30 秒判断出题方向就能少走好几个小时的弯路。举例来说如果一道题给了你一个压缩包而且题目描述里写着“小明的生日”你的第一反应不应该是去暴力破解压缩包密码而应该去尝试生日相关数字组合同时检查压缩包是不是“伪加密”——这两个方向里伪加密的检测优先级更高因为它能让你在不知道密码的情况下直接解压。2. 核心细节解析与实操要点2.1 Web 方向拿 FLAG 的常见入口Web 方向的 FLAG 获取本质上就是“找到服务端程序的薄弱点让程序帮你把 FLAG 吐出来”。这里我不谈太深奥的利用链只聊几个出现频率极高的入口也是我在实战中反复见到的。2.1.1 命令执行漏洞FLAG 就在 shell 的回显里命令执行类题目的典型场景是代码里某个参数被拼接到系统命令中没有做过滤于是你可以在参数里注入额外的命令。常见的函数有system()、exec()、shell_exec()、passthru()等。PHP 里还有一个容易被忽略的passthru()它和system()很像但会把原始输出直接送到浏览器一般用于输出二进制数据比如图片很多题目偏偏就爱用它。拿到命令执行漏洞后第一步是确认你能执行什么命令。我通常先提交一个无害的命令比如id或whoami看回显。接下来就是找 FLAG 的过程。FLAG 文件名没有统一标准常见的有flag、flag.txt、flag.php、f1ag、flag_is_here等所以我会直接执行一个组合命令ls -la; find / -name *flag* 2/dev/null。这里有个细节很多题目环境是 Docker 容器find命令不一定存在。如果find不可用就老老实实用ls -la /、ls -la /var/www/html、cat /flag这种逐个排查的方式。还有一种情况是命令执行结果被截断了只显示前面几行这时可以用cat /flag | base64把内容编码后输出避免特殊字符干扰显示。我在一些题目里遇到 FLAG 中含有空格和特殊符号直接cat会被程序解析出错用 base64 编码输出再本地解码几乎不会失手。命令执行类题目还有一个常见考点绕过过滤。如果程序过滤了空格你可以用${IFS}代替如果过滤了/可以尝试$(echo ${PWD} | cut -c1)拼出斜杠。这些绕过技巧不是死记硬背就好关键是理解过滤的“位置”——是只过滤了 GET 参数还是连 POST 也过滤了是只过滤了某个字符还是没有过滤编码后的字符搞清楚这些才能判断该用哪套绕过方案。2.1.2 文件包含与 PHP 伪协议文件包含漏洞File Inclusion也是 Web 方向的常客。核心原理是程序通过参数动态加载文件但没有对用户输入做严格限制导致你能读服务器上的任意文件。这里最常用的“武器”是 PHP 伪协议。场景举例URL 是index.php?pageabout你改成index.php?pagephp://filter/readconvert.base64-encode/resourceflag.php就能把flag.php的源码以 base64 编码的形式读出来再解码拿到 FLAG。为什么用php://filter因为直接pageflag.php时如果目标文件是 PHP 文件服务器会先执行它而不是显示源码FLAG 可能已经被程序“藏起来”了。用 base64 编码的方式读取源码可以绕过这种“执行后输出”的逻辑。这个技巧在我接触的题目里出现频率非常高值得反复练习。文件包含还有几个变体data://协议可以让你把一段纯文本或 base64 编码的 PHP 代码作为数据流包含进来直接执行php://input则可以把 POST 请求体当作代码执行expect://协议在部分环境下能直接执行系统命令。每种协议的环境要求不同遇到题目时最好先确认 PHP 版本和可用的协议列表。2.1.3 直接看源码FLAG 可能根本不需要“打”很多人一上来就想着“攻击”反而忽略了最简单的方式——打开网页右键查看源码。CTF 里大量入门题的 FLAG 就在 HTML 注释里、JS 代码里、或者藏在robots.txt中。robots.txt是很多新手容易忽略的文件。它本来是给搜索引擎爬虫看的文件说明哪些路径可以爬、哪些不可以。但 CTF 出题人经常把 FLAG 藏在被 Disallow 的路径后面你在浏览器里访问robots.txt就能看到类似Disallow: /flag_here.html的提示跟着路径走FLAG 到手。另一个容易被忽略的是.git目录泄露。有些开发者在部署网站时把.git文件一起传上去了导致整个代码仓库可以被下载。题目场景常见的是git clone后的网站目录里存在.git直接访问http://target/.git/得到目录列表。我通常会用GitHack这类工具把源码拉下来然后通过git log、git diff查看历史提交记录——很多出题人会故意在历史版本里删掉 FLAG但你依然可以从 commit 记录里翻出来。2.2 杂项Misc方向拿 FLAG 的典型套路杂项在我心里是 CTF 里最 “不讲武德” 的方向因为它什么都能考——文件分析、编码转换、流量分析、内存取证、压缩包破解、隐写术…… 但也正因为它杂所以掌握基础套路后拿分效率往往比 Web 更高。2.2.1 压缩包处理伪加密与暴力破解压缩包是杂项题目的“常客”FLAG 经常被塞进一个 zip 文件里。拿到 zip 后第一反应不是去解压而是先看它的加密状态。这里有一个非常关键的细节zip 文件可能是“伪加密”。所谓的伪加密是指 zip 的加密标志位被篡改过资源管理器或者部分解压工具会误认为它加密了要求你输入密码。但实际上文件内容并没有真正加密你只需要用工具纠正标志位就能直接解压出里面的文件。判断伪加密的方法不复杂。用 010 Editor 或 Hex Fiend 打开 zip 文件找到中央目录区Central Directory中对应文件条目里的“通用位标志”General Purpose Bit Flag如果第 0 位数值 1为 1表示文件是加密的。把这一位改成 0保存后重新解压如果成功就说明是伪加密。工具层面ZipCenOp.jar可以直接一键修复伪加密这条命令我用了无数次java -jar ZipCenOp.jar r flag.zip。如果 zip 确实是真加密那就需要考虑暴力破解或字典攻击。这里要注意不到万不得已不要直接上全字符暴力破解除非题目描述明确告诉你密码很短。比较高效的思路是结合题目描述猜密码比如“小明的生日”就围绕生日数字组合做字典如果附件里有一个看起来像提示的图片或文本优先在提示里找线索——密码很可能是某个英文单词、某个年份或者某段歌词的拼音首字母。2.2.2 流量包分析FLAG 藏在协议交互里流量包分析是杂项题目的重头戏。附件通常是一个.pcap或.pcapng文件里面记录了某段时间的网络通信数据FLAG 可能是明文出现在某个包的数据部分也可能需要你重组 TCP 流才能看到。Wireshark 是我做流量分析的主力工具。拿到 pcap 文件后我一般按三步走第一步看协议统计。通过Statistics - Protocol Hierarchy快速判断这个流量包里的主要协议是什么。如果 HTTP 流量很多FLAG 大概率跟网页请求/响应有关如果全是 TCP 且没有应用层协议那就需要追踪 TCP 流如果有 DNS 查询流量也不要放过因为有的题目会把 FLAG 拆成多段藏在 DNS 查询的域名里。第二步过滤关键词。Wireshark 支持直接在过滤器里搜字符串frame contains flag或者tcp contains FLAG。这个方法虽然简单粗暴但往往是最快的。很多入门题目就是把 FLAG 以明文方式放在某个包里一过滤就出来了。第三步追踪 TCP 流。如果 FLAG 不是直接在包里那就得右键任意一个 TCP 包选择“追踪 TCP 流”把整个会话的数据都看一遍。我遇到过 FLAG 被分在两个请求里一个请求发送了前半段另一个发送了后半段需要把流内容拼起来才能看到完整值。流量包里还有一种常见情况是“上传/下载文件”比如通过 HTTP 传了一个压缩包或者图片FLAG 就藏在这个文件里。这时候可以用 Wireshark 的File - Export Objects - HTTP直接把传输的文件导出再离线分析。2.2.3 隐写术图片、PDF、音频里的玄机隐写术Steganography是把我认为“最抓狂也最有趣”的方向因为它的核心是“藏”而你要做的就是“找”。找的线索可能隐藏在图片的像素里、声音的频谱里或者 PDF 文件的元数据里。图片隐写是最常见的。FLAG 可能直接写在图片的 EXIF 信息里用exiftool就能查看可能附加在图片文件末尾用strings命令就可以发现可疑字符串也可能用 LSB最低有效位隐写把 FLAG 编码在图片像素颜色的最低位上人眼看不出区别需要用zsteg或StegSolve这类工具提取。PDF 隐写比较冷门但也出现过。我的习惯是先用 PDF 阅读器打开看一遍有没有明显的文字遮挡再用pdf-parser.py检查 pdf 对象结构看是否有隐藏的文本对象或注释最后用strings直接扫 PDF 文件里的不可见字符串。有些题目会把 FLAG 以全白色文字塞在 PDF 页面里你肉眼看不见但全选复制就能发现。音频隐写的常用思路是看频谱图。用 Audacity 打开音频文件切换到频谱图视图有时候 FLAG 会被绘制成一段文字图案藏在频谱中。这种情况用耳朵是听不见的但眼睛一看就懂。3. 实操过程与核心环节实现3.1 从零开始做一道命令执行题完整解析这里我以一个典型的命令执行漏洞题为例演示完整的解题链。题目页面是一个简单的 IP 查询工具输入 IP 地址后端执行ping命令代码大概是这样的?php $ip $_GET[ip]; system(ping -c 3 . $ip); ?首先测试是否存在命令注入。在输入框提交127.0.0.1页面正常回显 ping 结果。接着提交127.0.0.1; whoami如果页面上出现了当前用户信息比如www-data说明命令注入成功。注意这里用的是分号;因为分号可以让多条命令顺序执行。如果把分号过滤了还可以尝试换行符%0a、管道符|、逻辑与、逻辑或||。每种符号的效果不同|只显示后一条命令的输出||在前一条命令失败时才执行后一条是前一条成功才执行后一条。根据实际回显判断过滤规则再选择最合适的连接符。拿到命令执行权限后执行ls -la /; cat /flag 2/dev/null; find / -name *flag* 2/dev/null如果 FLAG 文件就在根目录下且名为flag直接cat /flag就结束了。但如果页面把命令输出限制在某个区域或者只显示前几行那就需要换一种输出方式。我的习惯是把 FLAG 内容写入一个 Web 目录下的临时文件再通过浏览器访问。比如cat /flag /var/www/html/flag.txt然后直接在浏览器打开http://target/flag.txt。这个方法在命令执行漏洞利用里非常实用因为它绕开了命令行输出的各种限制。3.2 流量包分析实战从 pcap 到 FLAG某次训练赛中遇到一个流量包附件大小约 30MB。打开 Wireshark 后第一眼看到的是大量 HTTP 流量这让我提高了警惕——通常有大流量里面多半藏着文件传输或可疑请求。我按前面说的三步走。先看协议统计HTTP 请求数量确实很多于是直接File - Export Objects - HTTP把所有 HTTP 传输对象导出。导出的文件里有一个 ZIP 压缩包名字很可疑secret.zip。用 7-Zip 打开这个 ZIP提示需要密码。此时我先检查加密标志位——用 010 Editor 打开发现通用位标志中的第 0 位是 1看起来确实是加密的。但出于谨慎我还是先尝试用ZipCenOp.jar修复伪加密java -jar ZipCenOp.jar r secret.zip修复后重新解压ZIP 成功解压出了一个flag.txt打开就是完整的 FLAG。这道题的坑点在于破解密码会浪费大量时间但实际上它只是个伪加密。所以再次强调拿到任何加密压缩包第一步永远是“检测伪加密”而不是埋头跑字典。3.3 图片隐写分析用 strings、exiftool 和 zsteg 三板斧图片隐写题目我做了很多积累了一套固定流程。第一板斧是strings直接扫描图片中所有可打印字符串。如果 FLAG 以明文方式附加在图片末尾strings会直接输出它。比如strings cat.jpg | grep -i flag第二板斧是exiftool查看图片的元数据。FLAG 可能藏在作者、版权、描述等字段里exiftool cat.jpg第三板斧才是真正的“科学分析”用zsteg检测 LSB 类隐写。如果图片是 PNG 或 BMP 格式zsteg可以检测多种隐写方法zsteg -a cat.png这套流程覆盖了 90% 以上的图片隐写场景。如果这三板斧都没结果再考虑更进阶的分析比如把图片拆成多个色阶通道对比、查看不同位平面的差异图或者用stegsolve手动滑动通道查看。不过在动手做这些“重活”之前一定要先确认前面的基础检查都做完了因为大部分题目没有你想的那么复杂。3.4 Git 泄露利用从 .git 到源码再到 FLAG题目环境是一个模拟的网站备份目录访问http://target/.git/可以看到目录列表说明存在 Git 泄露。用 GitHack 把源码拉下来python GitHack.py http://target/.git/拉取完成后进入源码目录执行git log --oneline git diff HEAD HEAD~1通过git log发现有两个提交记录第二个提交的 message 写着 “remove flag”。这时候基本可以断定FLAG 在第一个提交里。执行git show HEAD~1就能看到之前提交版本中的flag.php文件完整内容FLAG 就在里面。这类题目的核心逻辑是出题人把 FLAG 提交到了 Git 仓库然后又删掉了模拟的是开发者在解决完问题后提交了新的代码版本。但 Git 的设计决定了历史记录不会被真正抹去任何被提交过的内容都可以从版本历史中找回。4. 常见问题与排查技巧实录4.1 遇到 403 报错怎么办在 Web 题里“做ctf网站老报403”是新手问得最多的问题。403 表示访问被拒绝了可能的原因有三种目录权限设置、WAFWeb 应用防火墙拦截、文件本身不存在。如果是目录权限问题更换访问路径、尝试直接访问文件而非目录列表即可如果是 WAF 拦截那就要考虑对请求做变形比如使用编码、大小写混写等方式绕过如果文件本身不存在服务器也可能返回 403 而不是 404这是常见的安全配置策略用来防止路径探测。我的建议是遇到 403不要慌先尝试访问一个肯定不存在的路径看服务器返回什么状态码。如果返回 404说明 403 只是针对某些特定路径的策略如果也返回 403那说明服务器对所有非法路径统一返回 403此时可以放心大胆地在合法路径范围内继续找线索不用过于在意那个 403。4.2 压缩包破解跑不出密码怎么办很多人一拿到加密压缩包就开始跑字典结果跑了一夜都没结果。这里有几个排查点先确认是不是伪加密。这个问题前文反复强调过但实际操作中我见过太多人忽略检测直接开跑白白浪费时间。再确认密码是否就在题目描述或附件名里。比如题目叫“helloctf小明的生日”附件里有一张明显是生日日期的图片那你就要围绕日期去生成一个精简字典而不是用默认字典。最后再考虑真正的暴力破解。如果确认密码是纯数字且位数不长用fcrackzip指定数字范围跑如果是一段有意义的话建议用john配合规则字典。但说实话如果这个环节过了 10 分钟还没结果我通常会把题目重新读一遍因为我碰到过很多情况是题目里其实写明了线索只是我一开始没注意。4.3 流量包太大Wireshark 卡顿怎么办流量包动辄几十 MB、上百 MB用 Wireshark 打开和操作都会卡。这时候我建议分两步先用tshark做命令行层面的快速分析。比如想提取所有 HTTP 请求中的 URI可以执行tshark -r capture.pcap -Y http.request -T fields -e http.request.full_uri想搜索包含 “flag” 字符串的包tshark -r capture.pcap -Y frame contains \flag\命令行跑完后你会对流量内容有大致概念然后再过滤出小分量的包用 Wireshark 做细致的交互分析。这个流程可以显著减少卡顿带来的烦躁感。4.4 拿到内容但不是 FLAG编码与格式判断我遇到过一个很有趣的情况费尽千辛万苦拿到了一个字符串但提交上去报错。后来才发现这个字符串是经过编码的需要进一步解码才是真正的 FLAG。判断是不是最终 FLAG 有几个依据看格式。CTF 的 FLAG 一般有固定格式比如flag{...}、ctf{...}或者题目自定义的包裹格式。如果你拿到的字符串长得不像就要考虑解码。看字符集。如果看到的是一串 base64 字符大小写字母和数字加/先尝试 base64 解码如果是形如%XX%XX的内容考虑 URL 编码如果是\x开头的一串十六进制考虑转 ASCII。考试环境里常用“随波逐流 CTF 工具箱”这类工具做编码解码覆盖的编码类型很全包括 base64、URL、Unicode、摩斯密码、栅栏密码、凯撒密码等。我个人的建议是别指望一次性找到正确编码可以按概率排序先试最常见的几种再结合题目场景判断。4.5 命令执行被过滤得很死怎么办有些题目对命令执行的过滤做得比较完善比如过滤了空格、过滤了/、过滤了cat等。这时候不要急着放弃因为过滤永远有绕过空间。空间可以用${IFS}cat可以用tac、more、less、head、tail替代如果过滤了关键词可以在关键词中间插入反斜杠或拼接变量。下面是一条常用的绕过命令ac;bat;c/flag;$a$b $c先用变量拼出cat再用变量拼出/flag最后执行。这种方式在关键词过滤的场景里非常好用。还有一种是利用通配符/bin/?at /fl?g?能匹配任意单个字符所以会实际执行/bin/cat /flag。如果连问号都被过滤了试试*但要注意*可能匹配过多文件导致命令出错。总之命令执行的绕过本质上是“拼接 → 变形 → 再拼接”的过程多试几种组合总有一条路能走通。5. 常用的工具清单与使用场景工欲善其事必先利其器。下面这个表格是我日常练习中的高频工具按使用场景做了分类可以直接收藏方向工具名称典型用途编码解码随波逐流 CTF 工具箱覆盖常见编码、古典密码、凯撒、栅栏、摩斯等压缩包7-Zip / ZipCenOp压缩包管理、修复伪加密标志位压力破解fcrackzip / johnzip 密码破解、字典规则生成和高级破解流量分析Wireshark / tsharkpcap 可视化分析、命令行快速筛选、提取文件图片隐写zsteg / exiftoolLSB 隐写检测、EXIF 信息提取、附加数据扫描文件分析strings / binwalk扫描文件中可打印字符串、检测和分析嵌入式文件Web 辅助Burp Suite / hackbar抓包改包、Payload 构造、请求重放Git 泄露GitHack一键恢复 .git 泄露的源码树十六进制010 Editor / Hex Fiend查看二进制文件、手动修复文件头、分析加密标志位综合平台CTFd / 动态靶场搭建本地练习环境熟悉比赛平台和提交机制工具固然重要但我不建议刷题一上来就疯狂装工具。很多时候strings和grep就能解决问题。工具是把“可能性”变大的助手而不是解题的核心。真正核心的是脑子里对“FLAG 可能在哪”的判断。6. 最终提醒拿到 FLAG 后的规范动作最后分享一个非常实用的小习惯。很多新手千辛万苦拿到 FLAG 后直接复制粘贴去提交结果提交格式错误。这里有一个容易被忽略的细节FLAG 必须包含完整的头尾标识常见的格式是flag{...}、FLAG{...}、ctf{...}不要把flag{和}漏掉也不要在 FLAG 两边粘贴多余的空格或换行。另外部分比赛的 FLAG 提交对大小写敏感所以提交前要认真核对不要全凭记忆敲打。如果题目要求的是flag{...}你只提交...的内容系统会判错同理如果你把FLAG{...}写成了Flag{...}也可能提交失败。还有一个是我在实战中养成的习惯拿到 FLAG 后顺手截个图或者复制到本地笔记里。因为比赛中你可能会同时解好几道题提交完就忘赛后复盘或者写 writeup 的时候这些记录能帮你快速回忆起每道题的解法。CTF 训练的价值恰恰在于复盘而不是单纯追求当场解出的快感。按我个人经验CTF 解题能力的提升速度其实跟“总结方法”这件事高度相关。我不太赞成纯粹靠刷题数量堆经验因为题目变化无穷但 FLAG 的藏匿逻辑是有规律可循的。这套“总结获取 FLAG 方法”的笔记我会持续更新下去。下一篇预计会重点补充 PWN 和逆向方向的拿 FLAG 思路以及一些高强度比赛中的选题策略。如果你在实战中碰到什么有意思的 FLAG 获取方法欢迎一起交流。