直接晒一下我当时的现场状态:打开攻防世界 misc 方向的“选手投递”,看到题面只有一句话,附件一个压缩包,很多第一次刷题的人都是顺手解压、拖进工具、扫一遍,然后卡死在原地——flag 就藏在那儿,你却看不见。这道题之所以叫“看不见的一百分”,就是因为它的答案永远不在你第一眼能看到的地方,后来我在好几个 CTF 训练平台刷到同类型的题,包括 bugku misc、buuctf 里那些签到题,思路其实都是一套。这篇就把我踩过的坑和完整解题思路都展开聊清楚,不给你直接报答案,但保证你读完就知道这类题应该怎么一步步扒干净。
这道题适合谁?刚入 CTF、misc 方向不知道怎么入手的新手,以及已经刷了不少题但总觉得“漏了什么”的人。它解决的问题不是某一个工具怎么用,而是面对一个完全陌生的附件,你应该按什么顺序、用什么方法、怎么判断“这里有问题”然后再往下深挖。对,misc 的核心从来不是你会多少神器,而是你能不能从任何杂乱的输入里找到那一小段“不该存在”的数据。
1. 题目初见:从“一百分”入手拆题干
第一次打开这道题的时候,我的第一反应其实和大多数人是反着来的。大多数人先看附件,直接把文件名、压缩包、文件类型丢进工具链里跑一遍,直到所有工具都扫不出来,才回头重新读题面。这就是“看不见的一百分”的第一层陷阱——题面这句话本身就是信息,而且很可能是整套题里最直接的提示。
1.1 题面里的隐藏线索怎么说
“选手投递”这个名字本身就有说法。结合攻防世界 misc 方向的出题习惯,这类题名往往是一个场景化的包装,对应的就是“某选手往某个地方投递了文件”,那么投递的方式、投递的文件载体、投递后的状态,都可能是考点。而“看不见的一百分”这句话,则是在提醒你:这题的分数就在那儿,但通过正常的查看方式,你看不到它。
如果你在实战里拿到这类描述,我的建议是先把题面拆成几个关键词,逐一对号入座:
- 投递:可能跟文件附加、隐写、追加数据有关,也可能跟流量、协议、上传操作有关。
- 看不见:优先怀疑隐藏属性、隐藏文件、隐写、文件结构异常、权限或类型伪装。
- 一百分:说明 flag 的形态是完整且唯一的,不会出现半截、多解的情况,锁定“只有一个正确答案”的搜索思路。
这种拆法不是玄学。CTF 的题目描述其实是在给你一个“语义索引”,每句话都在圈定排查范围。就拿“看不见”来说,既然题面已经说了看不见,那大概率就不是明文存储,也不是简单改后缀就能看到的东西,而是需要你借助工具或脚本去“看”底层数据。
1.2 附件和压缩包的第一轮检查
先不急着上高级工具,把最基础的动作做一遍。这里有一个很多人容易忽略的点:拿到一个未知附件,第一件事不是解压,而是先看文件本身到底是什么类型。
Windows 下,后缀名是骗人的,但是攻防世界里大部分环境是 Linux,直接跑一句 file 就能看到真实类型:
bash复制file 附件文件名
如果返回的是一张图片,那就进入图片隐写的排查流程;如果返回的是一个 Zip 压缩包,哪怕后缀名写的是 .jpg,也要立刻把它的扩展名改成 .zip 再尝试解压。这种“伪造后缀”的思路在 misc 题目里出现得非常频繁,尤其是攻防世界的早期题目,几乎就是必考项。
压缩包解开之后,不要急着找 flag 文件。先把所有文件列出来,看有没有隐藏文件开头的点号文件,看文件大小有没有异常——那些只有几十字节的小文件往往就是藏答案的地方。比如一些题目会把 flag 放在压缩包里的一个 README.txt 里,但注释区、附加数据区里还有一层。
我到这一步的时候,用 binwalk 扫过一遍压缩包,看看有没有嵌套的额外数据:
bash复制binwalk 附件文件名
这条命令干什么用的呢?它就是检测文件里是否存在被追加、拼接、嵌入的“其他文件”。很多“看不见的 flag”其实不是看不见,而是被藏在了一个看似正常的文件尾部,binwalk 扫一遍就能看到偏移量和文件特征。比如你看到一个压缩包解出来只有一个普通的图片,但 binwalk 显示在这个图片尾部还有一个 ZIP 文件或一个文本文件,那就说明答案藏在附加数据里。
我对新手的一个忠告:这些基本功每一样看起来都很简单,但完整走一遍和直接拖进工具是两个概念。工具只能扫你让它扫的东西,而命令行能让你看到每一个文件结构的真实边界。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 图片隐写是重灾区:这一轮必须扒到像素层
从攻防世界到 bugku misc、buuctf misc,图片隐写几乎覆盖了 40% 以上的简单题和中档题。如果你拿到附件后看到一张 PNG 或 JPG,直接 strings 扫一遍、再用 Stegsolve 翻一遍通道,这是最基础的动作,但还不够。因为“选手投递”这种题既然叫“看不见的一百分”,它的重点肯定不是让你一眼就在字符串里捞到 flag。
2.1 从 strings 和 010 Editor 看元数据与附加区
先用 strings 扫出可打印字符,这一步能解决所有“明文藏在文件里”的情况:
bash复制strings -n 6 图片文件
-n 6 表示只输出长度大于等于 6 的字符串,避免刷出大量无关的短字符。如果里面直接出现 flag{...},那这题就是签到难度。但大多数“看不见”的题没有这么温柔,strings 输出里只会出现一堆 PNG 块名称,或者图片作者、软件等元数据信息。
如果没有明文 flag,第二步就是打开 010 Editor,直接看十六进制。重点看两个区域:文件头的前 64 字节,以及文件尾部最后 256 字节。PNG 文件头应该是 89 50 4E 47 0D 0A 1A 0A,JPG 文件头是 FF D8 FF E0 或 FF D8 FF E1,ZIP 文件头是 50 4B 03 04。如果文件头不对,说明后缀被篡改过;如果文件尾有多余的数据,那就照第二节的方法处理。
很多新手在这里会忽略一个细节:图片的 Exif 信息。exiftool 可以直接列出所有元数据:
bash复制exiftool 图片文件
不要小看这个步骤。很多平台的低分题把 flag 直接放在图片的 Description 或 Comment 字段里,你用看图软件根本看不到,只有解析元数据才会浮现。这也是“看不见”的最朴素含义。
2.2 LSB 隐写和分析工具链的完整闭环
如果元数据和附加区都干净,那就进入 LSB(最低有效位)隐写排查。原理不复杂,图片的每个像素由 RGBA 四个通道组成,每个通道占 8 bit,修改最低位对人眼来说几乎没有影响,所以隐写者可以把一个文本或另一张图片的二进制数据塞进这些最低位里。
手动看 LSB 的经典工具是 Stegsolve。打开图片后,在 Analyse 菜单里选择 Bit Planes,逐通道、逐 bit 去翻。你会看到一个诡异的现象:某个 bit 平面上出现规律的亮暗条纹,那就有问题了。最典型的是最低位平面出现明显的纹理异动,而不是纯随机的噪点。
Stegsolve 还有个 Data Extract 功能,可以批量提取 7 个 bit 平面组合。那我自己用的时候更倾向于直接写 Python 脚本,用 Pillow 库自己实现一遍 LSB 提取逻辑。为什么?因为 Stegsolve 能处理 8 bit 图,但遇到 16 bit 深度或者其他特殊编码时就容易出错,而自己写脚本可以完全掌控每一步。
举个例子,假设你怀疑 flag 以 LSB 方式顺序藏在 RGB 三个通道的最低位,读取逻辑就是:
python复制from PIL import Image
img = Image.open("picture.png")
pixels = img.load()
width, height = img.size
bits = []
for y in range(height):
for x in range(width):
r, g, b = pixels[x, y][:3]
bits.append(r & 1)
bits.append(g & 1)
bits.append(b & 1)
byte_data = bytearray()
for i in range(0, len(bits) - 7, 8):
byte = 0
for j in range(8):
byte = (byte << 1) | bits[i + j]
byte_data.append(byte)
print(byte_data[:200])
如果输出里能看到可识别的文本,那就直接顺着这个方向往下抠;如果输出是乱码,也别急着放弃,把读取顺序从“行优先”改成“列优先”,或者把比特顺序反转,都试一遍。这类题唯一的难点就是编码方向,方向对了答案就在眼前。
我建议你把这一整套流程理解成“翻像素层的底牌”。元数据是房子的外观,附加数据是墙里的夹层,LSB 则是地板砖缝里藏的东西——不掀开砖,永远看不见。
2.3 其他图片隐写套路:DCT 和双图融合
LSB 之外,还有两种常见套路值得单列出来说。第一种是 JPG 的 DCT 隐写,也就是把数据藏在频域系数里,单纯分析像素值看不出任何异常,这通常需要专门的工具或脚本处理。第二种是双图融合,附件里给了两张看起来差不多的图片,这时候用 compare 或直接计算像素差异,往往能还原出一张包含 flag 的新图。
攻防世界的老题里有一种非常经典的出题方式:两张图从视觉上看几乎一模一样,但其中一张在像素级和另一张有细微差异,把这些差异提取出来,就是一条完整的信息。处理这种题的核心思路是“找不同”,但不是用人眼找,而是用脚本找。
这类知识点很细碎,但正是这些细碎的东西构成了 misc 方向的基础盘。我的建议是遇到一种学一种,不要急着全部记住,而是反复用真实题目去锤炼,等到做的题够多了,你看到一张图片的时候,心里就会自动过一遍以上所有排查点。
3. 压缩包和文件结构:最容易藏“看不见”的地方
说句实话,我在 misc 题目里踩过的坑,十有八九出在压缩包上。因为压缩包太常用了,又太容易藏东西了——你看到的解压结果和压缩包内部实际存在的东西,很多时候根本不是一个版本。
3.1 压缩包伪加密和真实加密的判断
用 7-Zip 或命令行解压一个 zip 文件,如果提示需要密码,第一反应先别猜密码。在 CTF 场景里,很多这类“需要密码”的压缩包其实是伪加密。伪加密的原理是 zip 文件头部的通用位标记(general purpose bit flag)被改成了 1,解压软件判断这个包是加密的,但实际上文件数据根本没加密,只要把标记改回 0,就能正常解压。
用十六进制编辑器打开 zip,找到目录区或本地文件头里的标志位偏移,把加密标志位从 01 改成 00,保存后再试一次。操作起来不难,但需要一点对 zip 文件结构的熟悉度。如果你用的是 Kali,直接安装一个 zip 修复工具,或者直接用 zipdetails 查看文件头详细信息,都能快速定位密码标记。
真正需要密码的压缩包,那就进入爆破流程。简单密码用 fcrackzip 或者 zip2john 加 John the Ripper 就能跑,常见密码字典里 90% 的低分题密码都能扫出来。我自己更习惯先用弱口令字典跑一遍,速度非常快,跑不出来再说上掩码爆破。
3.2 zip 中的隐藏文件与注释区
还有一种情况特别容易忽略:压缩包里明明只有几张图片,但压缩包内部却存在隐藏文件。在 Linux 下,zip 包内的文件名可以以 . 开头,这一整个文件在资源管理器里默认不显示,但用 unzip -l 就能看到完整列表。
所以我的习惯是拿到压缩包第一件事先执行:
bash复制unzip -l 文件名.zip
这里注意看每个文件的大小。如果某个文件大小异常,比如只有 50 字节,但它显示成一个“图片”,那基本可以判断这个是骗人的伪装文件,本质是个文本。用 unzip 解压后再用 file 查看真实类型,十有八九就能直接看到 flag。
另外,zip 文件本身还有注释区。一些出题人喜欢把 flag 写在压缩包的注释里,你在 GUI 里右击“属性能看到备注”,但命令行下不会显示。所以 zipcomment 或直接在十六进制里看文件尾部,也是一步必查项。
这个环节我最大的体会是:永远不要相信你“看到”的解压结果,要相信 unzip -l 列出的所有条目和文件大小。
4. 这题到底“看不见”在哪——实战排查流程复盘
聊到现在,是时候把整套思路落在一个具体的排查流程上了。我用“选手投递”这个场景,基于同类题目的常见设计,做了一份完整的实战复盘。这样做的好处是,你不必照着某一道题背答案,而是可以用同样的步骤处理任何模糊不清的 misc 题目。
4.1 结构化的文件体检四步走
第一步,类型确认。不管你面对的是什么,先 file 看真实类型,再看后缀名和真实类型是否一致。如果发现不一致,改后缀并重新走一遍流程。
第二步,常规扫描。binwalk 扫全部文件,strings -n 6 扫所有文件,exiftool 看元数据。这些动作应该在五分钟内完成,快速排除“送分”情况。
第三步,细查可疑点。凡是 binwalk 报出文件偏移的地方,都提取出来单独分析。凡是 strings 输出里出现 {、}、flag、key 等关键字的行,都单独复制出来看上下文。这里多说一句,strings 输出的乱码区域里有时也夹着信息,比如用 Unicode 或 UTF-16 编码的字符串,默认 strings 可能扫不出来,建议加 -e l 再扫一遍。
第四步,隐写深入。如果以上都没结果,进入图片隐写流程:Stegsolve 逐 bit 翻、Python 脚本跑 LSB、DCT 工具跑 JPG 隐写。如果附件里有音频,就看一下频谱图和波形图,频域中的一行字也是一种“看不见的 flag”。
这套四步走我在现场执行的时候,每一步都是纯粹的重复劳动,但恰恰是这种不遗漏任何一步的重复,才能保证最终能挖到隐藏的信息。不要因为前两步没结果就以为题目有问题,CTF 题目前面越是平淡无奇,后面藏的东西往往越深。
4.2 为什么“看不见”而不是“找不到”
标题这句话最关键的地方在于区分了两个概念。很多时候我们找不到 flag,是因为方法不对;但“看不见”暗示的是 flag 其实一直在你眼前,只是你的查看方式不对。
举个典型例子:一张 PNG 图片,通过颜色通道把文字刷成了全白或全透明,你用正常看图工具只能看到一片空白,但把图片拖进 Stegsolve 选择指定颜色通道,文字就浮出来了。你并没有“找不到”,只是“看不见”。
类似的还有:文字用透明字体藏在 PDF 里;文件名是空格加 . 的隐藏文件;或把 flag 伪装成一个长得很像乱码的字体文件。这些都属于“改变查看方式就能看见”的范畴。
所以当你盯着附件怎么都看不出问题的时候,不要急着怀疑题目,而是反问自己:我还有没有别的“查看方式”没有试过?我有没有只看了外观、没看内里?这个思路上的转变,比学会十个工具都重要。
4.3 工具链之外:写脚本的“穷举心态”
到了这一步,如果还没看到 flag,那就进入“穷举心态”。所谓穷举,就是把所有可能的编码方式、所有可能的读取顺序、所有可能的掩码方案都试一遍,直到有结果。很多 misc 新手卡住不是因为没有工具,而是因为试了两种方法没结果就放弃了。
我当时处理这类题目时,有个习惯是写一套“批量尝试脚本”。比如怀疑 LSB,我就会一次性把 RGB 三个通道、每种 bit 平面组合、每字节的 bit 顺序都跑出来:
python复制from PIL import Image
import itertools
img = Image.open("picture.png")
pixels = list(img.getdata())
width, height = img.size
channels = [
("R", lambda p: p[0]),
("G", lambda p: p[1]),
("B", lambda p: p[2]),
("A", lambda p: p[3] if len(p) > 3 else 0),
]
for name, getter in channels:
bits = [getter(p) & 1 for p in pixels]
data = bytearray()
for i in range(0, len(bits) - 7, 8):
byte = 0
for j in range(8):
byte = (byte << 1) | bits[i + j]
data.append(byte)
text = data.decode("utf-8", errors="ignore")
if "flag" in text.lower() or "{" in text:
print(f"[{name}] found: {text[:300]}")
这种脚本的意义不是替代工具,而是让你在一个可控的范围内穷尽所有变量。CTF 的隐写题本质上就是一个“未知编码方案”的还原题,你必须把变量逐一排除,才能定位到真正的隐藏信息。
5. 从“选手投递”延伸:CTF misc 的共性与成长路径
如果只盯着这一道题,你可能觉得 misc 就是隐写和压缩包的小技巧。但把视野拉高一点,你会发现这类题目背后有一套统一的思考框架,而且这套框架在整个 misc 方向上都具有通用性。
5.1 签到题、送分题和硬核题的差异
先说签到题。bugku misc、buuctf misc 里的签到题,通常就是让你走一遍最基础的流程:拿到附件,strings 或者 binwalk 扫一下,flag 直接暴露。这类题的意义就是让新手建立信心,熟悉题目格式,明白 flag 长什么样。
而“选手投递”这类题目,介于签到和硬核之间。它不要求你掌握复杂的密码学长文,也不要求你逆向一段程序,但要求你比“签到”多走几步——知道去翻元数据、知道去查附加区域、知道看文件结构、知道用脚本提取隐写内容。这是一种“半送分”的设计,目的是测试你是否有系统化处理未知文件的能力。
真正的硬核 misc 题,往往需要组合使用多个方向的知识:图片隐写加压缩包密码、流量分析加编码变换、音频隐写加密码破解等。这类题没有固定套路,考察的是你对数据形态的敏感度和工具运用的熟练度。但无论怎么升级,基础排查流程都是一样的,只是每个环节里多嵌套了一层或多层变换罢了。
5.2 对比平台差异:攻防世界、bugku、buuctf 题目风格
平时刷题较多的平台基本就是攻防世界、bugku、buuctf,它们的 misc 题目风格其实是有些差别的。
攻防世界作为老牌 CTF 训练平台,题目编号系统比较完整,早期题目普遍偏简单,很多是直接考察单项技能,比如一个纯 LSB、一个纯伪加密。后期题目开始走向综合,但整体风格仍然比较“应试”,注重基础逻辑的连贯性。
bugku misc 的方向更偏脑洞,很多题目需要你对常见工具和常见套路非常熟悉,但也会有一些冷门的 Trick,比如利用某些文件格式的特殊性或者浏览器解析差异来藏信息。
buuctf 更像一个题目聚合平台,收录了大量 CTF 赛事的原题和复现题,很多题目都是真实比赛里出现过的。它的 misc 题目难度跨度最大,既有送分题,也有让我卡一整天的综合题。它的好处是你能在同一个平台上体验到不同出题人的风格。
我的建议是:不要只刷一个平台。先用攻防世界建立基础盘,再用 bugku 锻炼脑洞和对非常规套路的敏感度,最后去 buuctf 刷综合题检验自己的完整能力。三个平台交替着刷,比单独刷任何一家都更能提升综合水平。
5.3 misc 方向怎么练才不走弯路
如果说我对 misc 方向有什么核心建议,就一句话:把“流程”练成肌肉记忆,而不是记住某个题的解法和答案。
什么意思呢?比如你做完这道题后,不要只记住“图片有 LSB 隐写”或者“压缩包有伪加密”,而要把整个排查流程内化成自己的默认动作。拿到任何附件都先 file、binwalk、strings、exiftool,再根据文件类型进入细分流程。只有流程是确定的,你面对新题目时才不会慌乱,不会因为前两步没结果就心态崩掉。
还有一点是学会使用搜索引擎和工具文档。CTF 圈子更新太快,昨天你还没见过的工具,今天可能就已经成为解某道题的标准答案了。不要害怕用新工具,也不要觉得用脚本就显得自己不如别人。真正重要的永远是你对文件结构和数据编码的理解,工具只是加速这个过程的手段。
6. 实操心得:那些我在排查时踩过的坑
最后聊几个我在刷 misc 题时踩过的比较典型的坑,也是看完这篇内容你自己动手时最可能遇到的情况。
第一个坑是高估了后缀名的可信度。一开始我拿到文件后,习惯先根据后缀名选工具,结果很多题目专门利用这一点,把 zip 改成 png 后缀,把文本改成 jpg 后缀。后来我强迫自己一律先 file 确认真实类型,这个习惯救了我很多次。
第二个坑是 strings 输出里没有直接看到 flag 就急着进入高级分析。事实上很多题目的 flag 字符串被拆开、倒序、编码过,直接用 strings 是搜不出来的。这时候不要慌,应该把 strings 输出的所有内容先保存下来,然后搜索可疑的高熵字符串,再对这些字符串尝试 base64、hex、URL 解码等常见编码。这个过程很枯燥,但很有用。
第三个坑是只分析主文件,忽略了附带的小文件。比如一个压缩包里既有大图又有小文件,我一开始只盯着大图分析,结果 flag 其实就在那个只有几十字节的 config.txt 里,打开就是。这算是最低级的失误,但也最能说明一个道理:misc 题目的信息分布是任意的,你必须对每一个文件都一视同仁。
第四个坑是解压时没有检查压缩包内的文件路径。有些 zip 包里的文件名看似是一个目录,但解压到本地后可能带有 ../ 路径穿越,或者文件名以隐藏字符开头,导致你以为解压失败,其实文件已经静静地躺在某个子目录里了。我建议解压后使用 ls -la 查看所有文件,包括隐藏文件,再进入下一步分析。
这些坑单独拎出来看都很小,但实际做题时任何一个都会导致你卡在一个完全没必要的地方。你可以把这四条当作一张检查清单,每次卡住就从头过一遍,至少能解决一半的问题。
写到这,刚好把这道题从题面、文件排查、隐写分析到平台对比的完整路径都梳理了一遍。按照我个人的实操经验,拿到“看得见但找不到”的题目,最重要的不是马上用工具跑,而是先冷静拆解题干、制定排查顺序,再一步步执行。等你把这种排查习惯练成自然反应,再回头看“选手投递”这种“看不见的一百分”,你会发现它其实并没有那么难。
