资讯中心

CTF MISC入门实战:从文件伪装到二维码编码翻转的完整工具链复盘

📅 2026/9/25 4:53:16
CTF MISC入门实战:从文件伪装到二维码编码翻转的完整工具链复盘
很多人刷题时遇到“签到题”三个字就默认它是来送分的点开附件扫一眼找不到 flag 就去看 Writeup。说实话我原来也差不多。但这次在 NSSCTF 上重新做 SUCTF 2019 的 MISC 签到题反而让我觉得值得停下来好好复盘一篇一道合格的签到题它不会考你多么刁钻的技巧却会把 MISC 入门最常用的工具链路串一遍——文件伪装、附加数据隐藏、压缩包弱口令、二维码识别、编码翻转。对刚接触 CTF 的新手来说认真走完这一套流程比零散地刷十道知识点重复的简单题要有用得多。这篇文章不是让你直接抄 flag 的我把当时的实际操作过程和踩过的坑完整记录下来重点是解释每一个步骤背后“为什么这么做”、工具在幕后发生了什么、哪些细节容易翻车。你可以跟着命令一步步复现也可以把某个环节替换成自己顺手的工具——流程通了换个题目照样能用。1. 拿到题目后的第一件事确定文件的真实身份1.1 别信扩展名信文件头题目给了一个附件名字叫sign_in.zip但双击之后系统直接提示“文件损坏”或者“格式不支持”。很多新手这时候就开始怀疑平台传错文件了其实这正是出题人设下的第一个观察点。再强调一遍这个 MISC 基础中的基础扩展名只是给操作系统看的标签它决定的是“双击时默认用哪个程序打开”而文件本身是什么格式取决于文件开头那几字节的魔数Magic Number。Windows 默认隐藏扩展名导致很多人从来没有完整看过文件名更不会去探究一个文件真实身份到底是什么。但在 CTF 里把png改成zip、把zip改成jpg是最常见的开局手法。碰到附件打不开第一反应不应该是“文件坏了”而是“它可能不是这个格式”。1.2 用 file 命令看真实类型Kali 或者任意一个 Linux 终端里一行命令就能搞清楚file sign_in.zip实际输出长这样sign_in.zip: PNG image data, 500 x 300, 8-bit/color RGBA, non-interlaced看到没文件名后缀写着 zip现实是个 PNG 图片。file命令的原理说白了就是读文件头和它内置的一份“文件签名特征库”做比对。PNG 图片开头固定是89 50 4E 47 0D 0A 1A 0A也就是十六进制里你能看到的‰PNGZIP 压缩包开头则是50 4B 03 04对应 ASCII 字符PK。常见格式的魔数最好能记几个刷题会非常有用文件格式文件头十六进制对应 ASCIIPNG 图片89 50 4E 47‰PNGZIP 压缩包50 4B 03 04PK..JPEG 图片FF D8 FF E0不可见GIF 图片47 49 46 38GIF8PDF 文档25 50 44 46%PDF如果你手头连 Linux 环境都没有用 HxD、010 Editor 这类十六进制编辑器打开文件直接看第一行字节对照上表也能判断出来。1.3 改名后重新打开既然真实类型是 PNG那直接改名就好mv sign_in.zip sign_in.png改名只是改了文件名的标签并不会动文件里的任何二进制内容。这一步做完再用图片查看器打开sign_in.png就能看到一张看起来很普通的风景图。这是一个特别典型的“信息隐藏”开局让你看到一个表面正常的东西实际上真正的线索藏在这个正常表面之下。到这一步题目想考察的第一个点已经出来了——文件身份识别。如果你直接从这一步跳过去看后面的内容等于没打好地基。2. 静态信息提取不能只靠肉眼2.1 先跑一遍 strings图片打开是正常的肉眼看不到任何可疑的字符。别慌CTF 里判断一个文件有没有线索有一条铁律先用最原始的方式把文件里的所有“可打印字符串”拽出来看一眼。strings sign_in.png | grep -iE flag|ctf|suctf|key|pass|hintstrings这个命令会把文件中长度超过阈值、且属于可打印 ASCII 字符的连续字节序列提取出来。你可以把它理解成“把文件里的文字碎片全部捞出来”。在 MISC 里很多时候 flag 或者密码就直接以明文形式躺在文件尾部、Exif 信息里、甚至压缩包备注里先跑一遍 strings 往往是最快的捡漏方式。我在这个文件里 grep 了一圈干干净净什么也没匹配到。这说明出题人没打算把线索直接写在明面上。但这不代表文件里没有东西只是说明这些字符串可能被压缩、编码或者藏在二进制层面。2.2 为什么必须打开十六进制编辑器再看一眼strings 找不到东西很多新手就卡在这里不知道下一步干什么。其实还漏了一个关键动作用十六进制编辑器把文件完整看一遍。strings的工作原理决定了它有局限性——它只提取“可打印字符序列”。如果一个数据被压缩过比如 zlib 压缩流、被加密过或者根本就是二进制结构那 strings 什么也捞不到。这时候必须看文件本身的二进制结构。用 HxD、010 Editor 或者 Linux 下的xxd打开sign_in.png把它从头到尾过一遍。PNG 的结构很规律开头是 8 字节文件签名然后是若干数据块每个数据块由“长度 类型标记 数据 CRC 校验”组成。正常情况下PNG 的最后一块必须是IEND块看到49 45 4E 44 AE 42 60 82也就是IEND加上固定 CRC就走完了。但我在这张图的IEND之后又看到了一段不寻常的字节——开头正是50 4B 03 04。这时候再翻一下上面的魔数表一切就清楚了这个 PNG 图片的尾部被追加了一个完整的 ZIP 压缩包。PNG 解析器读到IEND就会停止解析所以尾部的额外数据完全不影响图片正常显示只有当你用十六进制编辑器或者专门的分离工具去端详整个文件时它才会露出马脚。这是一种很基础的隐藏手法文件拼接/尾部追加数据。但恰恰是这种基础手法每年比赛都能捞到一堆人。3. 分离藏在图片里的压缩包3.1 binwalk按特征签名扫描既然已经确认图片尾部藏了一个 ZIP下一个问题就是“怎么把它完整地抠出来”。方法很多最省事的是用自动化工具binwalk。binwalk sign_in.png输出大概会是这样的DECIMAL HEXADECIMAL DESCRIPTION 0 0x0 PNG image, 500 x 300, 8-bit/color RGBA, non-interlaced 41 0x29 Zlib compressed data, default compression ... 123456 0x1E240 Zip archive data, at least v2.0 to extract, compressed size: 2050binwalk做的事情也是特征签名扫描——它把文件从头到尾的字节流和内置的签名字典做匹配遇到匹配项就报告偏移位置。看到 Zip archive data 的报告就说明这里有货。直接自动化分离binwalk -e sign_in.png它会根据扫描结果把识别出的文件提取到_sign_in.png.extracted目录里。3.2 分离失败与 foremost 补救但这里有个我实际踩过的坑binwalk -e自动分离出来的 zip 文件是坏的unzip直接报错。原因不复杂。binwalk的签名扫描是基于特征匹配它检测到“这里像是 zip”但自动切分时偏移量可能不够精确更麻烦的是PNG 内部本身就有 zlib 压缩数据流扫描结果里会出现很多看起来像数据的条目自动模式容易把一些无关数据块也打包进去最后导出一个没法用的文件。遇到这种情况我的习惯是立刻换foremost。这个工具是专门的“数据雕刻”Data Carving工具原理比 binwalk 更“暴力”——它会从文件头开始扫描签名命中后按已知的尾部特征/文件大小结构去切块重点是针对 ZIP、JPEG、PNG 这类文件做了很好的优化恢复成功率更高。foremost -i sign_in.png -o extracted运行完extracted目录下会多出zip这个分类文件夹里面通常有一个00000000.zip。把文件名改回正常形态mv extracted/zip/00000000.zip hide.zip提取完立刻file hide.zip再确认一遍确保这次拿到的是一个结构完整的压缩包。3.3 手动提取与安全意识除了工具你也可以在十六进制编辑器里手动操作从50 4B 03 04那个偏移开始选中到文件末尾复制出来另存为新的 zip。手动操作的好处是“所见即所得”但坏处是很费眼睛而且遇到大文件容易选中失误。工具能解决的事情不值得用手工去冒风险。另外多说一句安全意识从 CTF 附件里分离出来的东西在没确认安全之前不要直接双击运行。虽然这道题只是个压缩包但现实中的比赛偶尔会有出题人往附件里塞恶意样本的设计。虚拟机或者隔离环境是处理陌生附件的最低配置养成这个习惯不亏。4. 弱口令爆破面对带锁的压缩包4.1 先按正常思路试一遍拿到hide.zip之后直接解压unzip hide.zip它弹出来一句“password required”。说明压缩包不是裸奔的这很符合签到题的定位——你得再往前迈一步。很多新手第一反应是去网上搜“zip密码破解”但其实遵循“先易后难”的顺序是很重要的先把显而易见的密码试一遍比如空密码、123456、password、SUCTF这些。题目描述、题目标签、甚至刚才 strings 扫出来的线索里都可能有密码提示。我这次没有直接从这些里试到密码所以才把破解工具搬了出来。4.2 zip2john 提取校验哈希传统 ZIP 加密的原理是 ZipCrypto 流加密文件头里保存了 CRC 校验值、压缩方式、文件名等信息。John the Ripper 这类工具没法直接对着一个 zip 文件爆破它需要先把 zip 的密码校验过程转化成它能处理的哈希格式。这一步由zip2john完成zip2john hide.zip hash.txt cat hash.txt生成的内容是一串包含$zip2$标记的哈希字符串里面封装了压缩包的加密算法、校验值、文件名等关键信息。John 的爆破逻辑就是“拿字典里的每个候选密码按照同样的加密算法算出校验值再和你这份哈希做对比”。4.3 john 的字典与爆破逻辑接下来上字典爆破john --wordlist/usr/share/wordlists/rockyou.txt hash.txtrockyou.txt是 Kali 自带的老牌字典收集了上亿条现实泄漏的常用密码。每秒能跑多少个候选密码取决于 CPU/GPU对于 ZipCrypto 这种老算法CPU 跑几十万甚至上百万次每秒没什么压力一个简单的弱口令几秒钟就能出来。我这次跑出来的密码是123456。看到这个结果我不禁笑了一下签到题还是那个签到题出题人并不是真想拦你只是希望你把工具链走一遍。如果你用的系统里没有rockyou.txt可以安装wordlists包或者用crunch之类的工具临时生成一个纯数字短字典crunch 1 6 0123456789 num.dict john --wordlistnum.dict hash.txt不过要泼一盆冷水爆破是万不得已时的最后手段不要指望每次比赛都能靠弱口令字典打开压缩包。现实中很多压缩包密码藏在题目信息、图片参数、LSB 隐写里先找线索再爆破顺序不要搞反。4.4 解开压缩包拿到密码后直接解压unzip -P 123456 hide.zip解压出来一个qr.png。保险起见再file qr.png确认一次这次是真的 PNG 图片不是又被改装过的文件。到这里我们已经从最初的sign_in.zip实际是 PNG走到了一个真正的二维码图片。题目框架到此基本清晰伪装文件 → 隐藏 zip → 弱口令 → 二维码后面就剩临门一脚了。5. 二维码识别与最后的编码翻转5.1 二维码扫不出来怎么办用图片查看器打开qr.png是一个完整的二维码。但当我掏出手机扫的时候微信、支付宝都识别失败提示“无法识别”或者直接没反应。这是二维码题目里非常常见的翻车点。原因通常有三个图像对比度不够、二维码周围缺少足够的白边quiet zone、或者图像被压缩/拉伸变形导致定位角点不完整。手机扫码软件对图像质量要求不低不像专用解码器那么宽容。正确做法是先用工具对二维码图做预处理。我的习惯是用 Python 的 PIL 加 pyzbarfrom PIL import Image, ImageOps from pyzbar import pyzbar img Image.open(qr.png).convert(L) # 二值化像素值大于阈值的置为白色否则黑色 img img.point(lambda x: 255 if x 128 else 0, 1) # 四周补白边给识别器留出安全区 img ImageOps.expand(img, border20, fill255) img.save(qr_clean.png) data pyzbar.decode(img) if data: print(data[0].data.decode())灰度化 → 二值化 → 补白边这套操作能解决绝大多数二维码识别失败的问题。如果你不想写代码也可以用 Stegsolve 打开图片一个个颜色通道看过去或者调整 Brightness/Contrast 直到二维码边缘变得锐利清晰Windows 下也可以用 CQReader、QRazyBox 这类离线工具。5.2 为什么二维码里装的是 Base64预处理之后pyzbar 成功从二维码里解出了一串文本ZmxhZ3t3ZWxjb21lX3RvX3N1Y3RmXzIwMTl9看到这种以大小写字母、数字、、/组合、结尾可能带的字符串第一反应就是 Base64。为什么出题人会选择在二维码里放 Base64而不是直接放明文原因很实际二维码能承载的字节数是有限的而且不同的字符集编码效率不一样。如果二维码内容都是大写字母、小写字母、数字配合 QR 码的 alphanumeric 模式容量利用率最高。Base64 可以把任何二进制数据、中文字符串转换成这些可见字符既压缩了字符集又顺手给 flag 加了一层“看起来有点东西但一步就能解”的伪装。说白了它是在有限的二维码容量里装下更多信息同时让解题路径多一道工序。5.3 解码 flag 与编码变种陷阱Base64 解码是一行命令的事echo ZmxhZ3t3ZWxjb21lX3RvX3N1Y3RmXzIwMTl9 | base64 -d输出结果就是 flag。具体内容这里先不贴全以flag{开头留给你自己跑一遍验证印象会深得多。如果你手边没有 Linux直接用 CyberChef 也很快把字符串丢进输入框选 From Base64或者直接点 Magic 让它自动识别。但这里要提醒一个坑不是所有 Base64 字符串都长成标准样子。有些题目会用 URL-safe 变种把换成-把/换成_这时候标准的base64 -d会报错。遇到解码失败先判断是不是变种字符集或者试一下 Base32、Base16不要死磕一个方向。6. 常见坑点与排查技巧实录6.1 一张坑点速查表把这道题相关的坑整理成一张表刷同类题目直接对照查现象原因排查思路压缩包双击提示损坏扩展名和真实格式不符file确认真实类型修改后缀strings 搜不到任何 flag文本被压缩、编码或加密看文件尾部、做 binwalk/foremost 分离查 Exif/LSBbinwalk 没提示 zip附加数据太小或格式被加工过换 foremost 或手动检查十六进制尾部二维码扫码失败对比度低、白边不足、变形灰度化、二值化、补白边或用开箱即用解码器Base64 解码出乱码字符集变种、混入了换行符去掉换行尝试 URL-safe 变种再考虑 Base32/16zip 需要密码且弱口令字典跑不出密码复杂或用了 AES 加密翻题目隐藏线索必要时换 7z2john 等更专用工具6.2 我踩过的三个真实小坑第一个坑在上文已经提过binwalk -e自动分离出来的 zip 是坏的。我盯着报错信息愣了两分钟才反应过来应该换foremost而不是反复用同样的命令重试。教训是工具识别到“这里有个 zip”和工具能“正确切出 zip”是两码事分离结果一定要二次验证。第二个坑出现在john的环节。我第一次跑john --wordlist/usr/share/wordlists/rockyou.txt hash.txt系统提示找不到字典文件。Kali 有些镜像里rockyou.txt是压缩包形式的需要先sudo gunzip /usr/share/wordlists/rockyou.txt.gz解压才能用。这种“路径没对上”的问题看起来很蠢但在比赛现场就是会耽误你几分钟。第三个坑是解码那一侧的小事pyzbar 返回的识别结果是 bytes 类型我直接print(data[0].data)的时候终端输出一大串bZmxhZ3...乍一看以为是另一个编码差点又走弯路。其实只要.decode()转成字符串它就是上面那串标准的 Base64。很多新手就是被这种“格式的皮”唬住平白多走了弯路。6.3 怎么把这道题吃透最后给新手一个实操建议这道题刷完之后不要直接跳到下一题花十分钟把命令行从头到尾手动敲一遍不要复制粘贴。然后试着回答这几个问题——file命令是看哪个偏移量判断出 PNG 的foremost为什么能恢复出 zipzip2john到底把什么东西变成了 hash每个问题都能准确答出来才说明你真的掌握了。做完之后可以顺手把自己用的命令整理成一份 checklist存成一个笔记。以后再做 MISC 题从文件身份识别开始按部就班地过file → strings → 十六进制查看 → binwalk/foremost → 压缩包处理 → 编码识别。这套流程熟到不需要思考之后你再看类似题目基本一眼就能看出考点了。最后再说两句实在话刷完这道 SUCTF 2019 的签到题我最直观的感受是它确实不难但“不难”不等于“没有收获”。一道好的签到题知识点一个都不超纲却要求你把 MISC 最基本的那套工具流程完整过一遍还在中间埋了几个很容易翻车的细节。如果你只是冲着 flag 去看到二维码那步直接用手机扫出来、或者干脆跳去看别人的 writeup那这套题的价值就全浪费了。我的建议是把上面每一个命令都亲手走一遍把每一个报错信息都停下来想一想再去 NSSCTF 上找两道差不多难度的 MISC 题独立复现一遍。等你不需要依赖任何 writeup也能顺着“文件识别→字符串提取→分离隐藏数据→解压→二维码解码→编码翻转”这条路走到终点这类签到题对你来说就真的只是签个到而已了。

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案