行业资讯

CTF隐写术实战:用Binwalk与Foremost拆解图片隐藏文件

发布时间:2026/8/5 4:43:50
CTF隐写术实战:用Binwalk与Foremost拆解图片隐藏文件 1. 项目概述为什么我们要拆解图片里的“秘密”如果你玩过CTFCapture The Flag网络安全竞赛或者对数字取证、信息安全感兴趣那你一定对“图片里藏文件”这个把戏不陌生。这可不是什么魔术而是一种在信息安全领域非常经典且实用的技术——隐写术Steganography的一种常见形式。简单来说就是把一个或多个文件比如一个压缩包、一段文本、甚至一个可执行程序巧妙地“塞”进一张看似普通的图片文件里。这张图片在图片查看器里能正常显示但通过特定的工具和方法就能把里面藏着的“宝贝”给提取出来。我最初接触这个技术就是在CTF的Misc杂项题目里。题目给一张风景图让你找“flag”。你瞪大眼睛看半天也看不出个所以然直到你用对了工具才发现原来flag就藏在图片的二进制数据里。这种“恍然大悟”的感觉是驱动很多安全爱好者入门的原始动力。但这项技术的意义远不止于解题。在真实的数字取证场景中调查人员可能需要从嫌疑人的电脑里恢复被故意隐藏的数据在日常安全审计中我们也需要检查用户上传的图片是否携带了恶意载荷。因此掌握拆解隐藏文件的能力是一项非常硬核且实用的技能。本次分享我将从一个CTF实战者的角度出发手把手带你使用两个最经典、最强大的工具——Binwalk和Foremost来拆解图片中的隐藏文件。整个过程就像做一次精细的外科手术而Binwalk是我们的“CT扫描仪”Foremost则是我们的“手术刀”。更重要的是我们还会深入到一个让很多新手头疼的“陷阱”伪加密。当你千辛万苦提取出一个ZIP压缩包却发现它提示需要密码而你可能根本没有密码时该怎么办别急我会附上详细的伪加密识别与修复技巧让你能顺利拿到最终的文件。无论你是CTF新手、安全爱好者还是对文件结构好奇的极客这篇内容都将为你提供一套清晰、可复现的操作指南。2. 核心工具与原理Binwalk与Foremost如何“看透”文件在动手之前我们必须先理解我们手中的“武器”是如何工作的。知其然更要知其所以然这样在遇到问题时你才能自己分析、排查而不是机械地敲命令。2.1 Binwalk文件结构的“雷达”你可以把Binwalk想象成一个针对二进制文件的“文件格式识别雷达”。它不关心文件的后缀名是.jpg还是.png它只做一件事从头到尾扫描文件的二进制数据流寻找其中嵌入的、其他已知文件格式的“特征签名”Magic Bytes/File Signatures。核心原理文件头与文件尾几乎每一种文件格式在它的起始位置文件头和结束位置文件尾都有一些特定的、标志性的字节序列。例如JPEG图片的文件头通常是FF D8 FF E0或FF D8 FF E1。ZIP压缩包的文件头是50 4B 03 04PK..。PNG图片的文件头是89 50 4E 47(.PNG)。一个正常的文本文件.txt可能没有固定的头但一个GIF图片的头是47 49 46 38(GIF8)。当我们将一个ZIP文件追加到一张JPEG图片的末尾时这个复合文件的二进制结构就变成了[JPEG文件头] [JPEG图像数据] [JPEG文件尾] [ZIP文件头] [ZIP压缩数据] [ZIP文件尾]。Binwalk的工作就是扫描整个文件当它扫过JPEG文件尾后突然又发现了50 4B 03 04这个序列它就会兴奋地报告“嘿我在这里发现了一个ZIP文件的起始迹象”它会给出这个签名在文件中的偏移量十进制或十六进制告诉你从文件的第多少个字节开始可能隐藏着另一个文件。实操心得Binwalk的扫描结果是一个“可能性”报告。它基于特征库匹配有时会出现误报尤其是文件数据区恰好有和特征码相同的字节。所以我们需要结合其他工具或手动验证。使用binwalk -e参数可以自动提取它识别出的文件但这种方式有时不够精确特别是文件嵌套复杂或存在损坏时。因此更推荐先使用binwalk进行分析再用更专业的工具进行提取。2.2 Foremost基于文件头的“精确雕刻师”如果说Binwalk是发现目标的雷达那么Foremost就是执行精确提取的手术刀。它的原理更直接它同样依赖于文件头/尾的特征签名但它的工作模式是“雕刻”Carving。工作原理Foremost会读取整个文件或磁盘镜像的原始数据。当它识别到一个已知的文件头签名比如ZIP的50 4B 03 04时它会记下这个位置。然后它开始向后扫描寻找对应的文件尾签名对于ZIP可能是中央目录记录但Foremost通常有更复杂的逻辑或使用长度推断。一旦它认为找到了文件的结束边界它就会把这两个位置之间的所有数据“切”下来单独保存为一个新文件。与Binwalk -e 的区别binwalk -e的提取有时依赖于文件系统的元信息如果嵌入的文件本身带有完整的文件系统如一个完整的镜像其提取逻辑可能更复杂。foremost是纯粹的“数据雕刻”它不关心文件系统只认头尾签名。这种方式对于恢复损坏的、或不包含文件系统的简单嵌入文件往往更加直接和可靠。在CTF中面对一个单纯的“图片附加数据”的题目foremost通常是更稳妥的第一选择。注意事项Foremost需要一个配置文件默认是/etc/foremost.conf或当前目录下的foremost.conf来定义它要寻找的文件头尾签名。默认配置已经包含了常见格式jpg, png, zip, pdf等但对于一些偏门的格式你可能需要自己修改配置。雕刻出来的文件可能会因为原始数据损坏或边界判断不准而导致文件本身损坏需要后续验证比如提取出的ZIP能否正常解压。3. 实战演练一步步拆解藏有秘密的图片理论说得再多不如动手做一遍。下面我们模拟一个完整的CTF解题流程。假设我们拿到一个名为secret_image.jpg的文件题目提示“flag藏在里面”。3.1 环境准备与工具安装首先确保你的操作系统中安装了必要的工具。这里以Kali Linux或Ubuntu为例其他系统安装方法类似。# 更新软件包列表 sudo apt update # 安装 binwalk sudo apt install binwalk -y # 安装 foremost sudo apt install foremost -y # 可选但推荐安装 file 命令用于查看文件类型和 hexeditor十六进制编辑器用于手动分析 sudo apt install file hexedit -y如果你使用的是Windows可以考虑在WSLWindows Subsystem for Linux中安装上述工具或者寻找对应的Windows移植版如Binwalk有Windows版本但Linux环境下的兼容性和体验通常更好。3.2 第一步使用Binwalk进行初步侦察拿到文件不要急着乱试。先用file命令看看系统认为它是什么再用binwalk进行深度扫描。# 查看文件类型 file secret_image.jpg # 输出可能为secret_image.jpg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, baseline, precision 8, 500x375, frames 3 # 看起来是一张正常的JPEG图片。 # 使用Binwalk进行签名扫描 binwalk secret_image.jpg一个典型的、包含隐藏文件的Binwalk输出结果如下DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 JPEG image data, JFIF standard 1.01 30 0x1E TIFF image data, big-endian, offset of first image directory: 8 91218 0x16452 Zip archive data, at least v2.0 to extract, compressed size: 215, uncompressed size: 297, name: flag.txt 91471 0x1654F End of Zip archive输出解读第1行在文件偏移0字节处发现了JPEG文件头。这证实了文件开头确实是一张图片。第2行在30字节处有一个TIFF相关的结构这可能是JPEG文件内部的元数据属于正常情况可以忽略。关键第3行在十进制91218字节十六进制0x16452处发现了ZIP归档数据的签名它甚至分析出里面包含一个名为flag.txt的文件压缩大小215字节未压缩大小297字节。第4行在91471字节处找到了ZIP归档的结束标志。这个结果清晰地告诉我们secret_image.jpg由两部分拼接而成前91218字节是一张完整的JPEG图片从第91218字节开始附加了一个完整的ZIP压缩包。3.3 第二步使用Foremost进行精确提取虽然Binwalk已经告诉我们偏移量并且可以用binwalk -e secret_image.jpg尝试自动提取但为了演示更通用的方法我们使用Foremost。# 使用foremost提取文件-i 指定输入文件-o 指定输出目录 foremost -i secret_image.jpg -o output_foremost命令执行后会在当前目录下创建一个名为output_foremost的文件夹。进入该文件夹你通常会看到按文件类型分类的子文件夹如jpgzippng等。cd output_foremost ls -la # 可能会看到 audit.txt提取过程日志、jpg、zip等目录 cd zip ls -la # 你应该能看到一个或多个提取出来的.zip文件例如 00000000.zip实操心得Foremost提取出的文件通常会被重命名为类似00000000.zip、00000001.jpg这样的名字。数字编号代表提取顺序。一定要查看audit.txt文件它记录了提取的详细信息包括在源文件中的偏移量和提取出的文件名这对于后续分析和验证非常有帮助。如果Foremost默认配置没有识别出你想要的格式比如某种特殊的归档格式你需要编辑它的配置文件添加对应的文件头尾签名。3.4 第三步处理提取出的ZIP文件现在我们假设在output_foremost/zip/目录下找到了00000000.zip。尝试解压它unzip 00000000.zip这时你可能会遇到两种情况情况A顺利解压。你会得到一个flag.txt文件打开它就能看到flag。任务完成情况B提示需要密码。终端显示[00000000.zip] flag.txt password:。这就是我们常说的“伪加密”陷阱。4. 核心技巧ZIP伪加密的识别与修复在CTF中出题人经常不会真的去设置一个复杂的密码而是利用ZIP文件格式的一个特性——“伪加密”False Encryption来制造障碍。它看起来加密了但实际上并没有只是修改了文件头中的一个标志位来“欺骗”解压软件。4.1 ZIP文件格式简析与伪加密原理一个ZIP文件由三部分组成本地文件头Local File Header每个被压缩文件前都有一个包含文件名、压缩方法、CRC校验等。其中有一个2字节的“通用位标志”General Purpose Bit Flag。文件数据压缩后的实际数据。中央目录记录Central Directory Record位于ZIP文件末尾是文件的“索引”也包含通用位标志。伪加密的关键就在“通用位标志”的第0位最低位。如果该位为0表示文件未加密。如果该位为1表示文件已加密。伪加密的做法是只将中央目录记录中的加密标志位置1而本地文件头中的加密标志位保持为0。这样大部分解压软件如Windows资源管理器、某些版本的unzip在解压时会检查中央目录发现加密标志就索要密码。但文件数据本身其实并没有被加密算法处理过。为什么能修复因为数据本身没加密我们只需要把那个欺骗人的“加密标志位”从1改回0告诉解压软件“这是个老实文件没加密”就能直接解压了。4.2 手动修复伪加密使用十六进制编辑器这是最根本、最能加深理解的方法。我们使用hexedit工具。定位关键字节# 先用hexedit打开ZIP文件 hexedit 00000000.zip我们需要找到中央目录记录的开始。一个快速的方法是搜索ZIP中央目录的文件头签名50 4B 01 02十六进制。在hexedit中按CtrlS进入搜索模式输入50 4B 01 02进行搜索。修改加密标志位 找到50 4B 01 02后从这个签名开始往后数。中央目录记录的结构是固定的。我们需要关注的是“通用位标志”字段。从50 4B 01 02开始偏移0x06即第7个字节的位置就是低字节的通用位标志。偏移0x07第8个字节的位置是高字节的通用位标志。伪加密通常只设置低字节的第0位。所以你需要查看0x06位置的值。 例如如果0x06位置显示的值是01二进制 0000 0001那么它的第0位就是1表示加密。我们需要把它改成00。操作在hexedit中用方向键将光标移动到目标字节0x06位置直接输入00然后按回车确认修改。保存并退出 修改完成后按CtrlX退出它会问你是否保存选择Yes。验证 再次尝试解压unzip 00000000.zip如果修复成功应该不再询问密码直接解压出flag.txt。4.3 自动化修复使用zipdetails和脚本手动编辑虽然酷但效率低且容易出错。我们可以借助一些工具来辅助。方法一使用zipdetails查看结构# 安装zipdetails通常随perl的Archive-Zip包提供或直接安装perl-Archive-Zip sudo apt install libarchive-zip-perl -y # 查看ZIP文件详情 zipdetails 00000000.zip在输出中寻找Central Directory Entry部分查看GPB Flag的值。如果显示GPB Flag: 1 [加密]则证实是伪加密前提是数据本身可读。方法二使用Python脚本一键修复这里提供一个简单的Python脚本原理是定位并修改中央目录记录中的加密标志位。#!/usr/bin/env python3 import sys import os def fix_false_encryption(zip_filename): with open(zip_filename, rb) as f: # 以二进制读写模式打开 data f.read() # 查找中央目录记录签名 PK\x01\x02 cd_sig bPK\x01\x02 cd_pos data.rfind(cd_sig) # 从后往前找找到最后一个通常是第一个中央目录记录 if cd_pos -1: print(错误未找到中央目录记录。) return False # 通用位标志在签名后的第6个字节偏移0x06 gpb_flag_pos cd_pos 0x06 current_flag data[gpb_flag_pos] print(f当前通用位标志中央目录: {hex(current_flag)}) # 检查是否为伪加密仅最低位为1 if current_flag 0x01: print(检测到伪加密标志正在修复...) # 将最低位清零 new_flag current_flag ~0x01 f.seek(gpb_flag_pos) f.write(bytes([new_flag])) print(f已修改为: {hex(new_flag)}) return True else: print(未检测到伪加密标志通用位标志最低位为0。) return False if __name__ __main__: if len(sys.argv) ! 2: print(f用法: {sys.argv[0]} zip文件) sys.exit(1) zip_file sys.argv[1] if not os.path.exists(zip_file): print(f文件不存在: {zip_file}) sys.exit(1) if fix_false_encryption(zip_file): print(修复完成请尝试解压文件。) else: print(无需修复或修复失败。)将上述代码保存为fix_false_zip.py然后运行python3 fix_false_zip.py 00000000.zip注意事项该脚本只处理最简单的伪加密情况仅中央目录标志位被设置。有些题目可能会同时修改本地文件头需要更复杂的修复逻辑。修复前务必备份原ZIP文件以防操作失误损坏文件。修复后如果仍不能解压可能是其他问题如文件损坏、或真的是加密需要进一步分析。5. 进阶分析与疑难排查掌握了基本流程后我们来看看一些更复杂的情况和常见问题。5.1 当Binwalk和Foremost都“失灵”时有时候出题人会使用更隐蔽的手法修改文件头签名将ZIP的文件头50 4B 03 04改成其他值以绕过基于签名的扫描。使用非常见格式隐藏的文件可能是7z、rar、自定义格式等而你的工具配置里没有这些签名。数据被编码/混淆隐藏的数据并非直接附加而是经过Base64、XOR等简单编码后嵌入到图片的像素数据或注释段中。应对策略手动十六进制分析使用hexedit或xxd命令直接查看文件内容。搜索可能的明文flag如flag{CTF{或观察文件末尾是否有明显的、不属于图片数据的规律性字符。xxd secret_image.jpg | tail -50 # 查看文件末尾50行十六进制 strings secret_image.jpg | grep -i flag # 提取文件中所有可打印字符串并搜索flag检查图片元数据使用exiftool查看图片的Exif信息flag有时会藏在注释Comment、作者Artist等字段里。exiftool secret_image.jpg尝试其他雕刻工具如scalpel它功能与foremost类似但配置方式不同。分离文件如果知道隐藏数据的准确偏移量比如从Binwalk结果得知可以用dd命令直接“切”出来。# 假设从第91218字节开始是ZIP文件我们不知道结束位置但可以切一个足够大的块 dd ifsecret_image.jpg ofextracted.zip bs1 skip91218 count100000 # bs1 表示一次读写1字节慢但精确skip跳过前91218字节count读取100000字节。 # 然后用file命令查看extracted.zip是什么再尝试解压或修复。5.2 提取出的文件损坏怎么办即使成功提取出00000000.zip解压时也可能报错“损坏的文件”或“错误的CRC校验”。原因可能有Foremost雕刻边界不准确可能多切或少切了几个字节。隐藏的文件本身不完整出题人可能只附加了部分数据。文件经过二次处理比如提取出的ZIP本身里面还套着一层别的。排查步骤验证ZIP结构使用zipdetails -v 00000000.zip或unzip -l 00000000.zip查看内部文件列表。如果列表能正常显示说明中央目录大致完好。尝试修复ZIP有些解压工具如7-Zip有修复功能。可以尝试用7z命令7z t 00000000.zip # 测试归档 7z e 00000000.zip # 尝试解压有时比unzip更健壮回到原始文件手动分离使用dd命令结合Binwalk给出的起始偏移和结束偏移进行精确切割。例如根据之前的Binwalk结果ZIP从91218开始到91471结束注意结束偏移通常是结束标记之后的位置计算大小时要小心。# 计算大小91471 - 91218 253 字节这似乎太小了可能Binwalk的结束位置只是中央目录结束而非文件绝对末尾。 # 更稳妥的方法是用foremost的audit.txt日志里面通常有提取出的文件大小。或者用十六进制编辑器手动确认ZPK的结束位置搜索 50 4B 05 06即ZIP文件结束标记。5.3 多层嵌套与组合技巧真正的CTF题目往往不会只有一层。常见的套路有图片里藏ZIPZIP里藏图片新图片里再藏东西套娃。需要先修复伪加密解压出的文件还需要用其他工具如steghide、outguess进行隐写分析。提取出的文件需要密码密码可能藏在图片的像素值LSB隐写或文件名中。通用解题思路保持耐心逐层剥离。每得到一个文件都用file命令查看其类型用binwalk/foremost扫描用strings查看字符串用exiftool查看元数据。建立检查清单。对于任何文件都按顺序过一遍file [文件名]binwalk [文件名]strings [文件名] | grep -i -E “flag|key|pass|ctf”exiftool [文件名]如果是图片或文档根据类型用相应工具打开或解压。善用脚本自动化。对于大量文件或重复性操作写简单的bash或Python脚本能极大提升效率。6. 总结与拓展思考走完从分析、提取到修复的完整流程你应该已经掌握了对付这类“图片藏文件”题目的基本方法论。这套以Binwalk/Foremost为核心辅以十六进制分析和伪加密修复的技巧在CTF的Misc和隐写类题目中应用极其广泛。但技术总是在演进。出题人也会不断设计新的挑战例如使用更复杂的文件格式嵌套比如把数据藏在PNG的IDAT块之间。利用工具的特性差异某些工具能提取而另一些不能考验你对工具原理的理解。将隐写与密码学结合提取出的文件需要破解一个弱密码才能继续。要持续精进我建议深入理解文件格式。花时间研究ZIP、PNG、JPEG、PDF等常见文件的二进制结构。理解得越深你手动分析和解决问题的能力就越强。构建自己的工具库。除了本文提到的还有steghide需要密码的图片隐写、outguess、zsteg针对PNG和BMP的LSB隐写工具、stegsolve图形化分析工具等都值得学习和掌握。多动手实践。可以在CTFtime等平台找一些过去的Misc题目进行练习巩固肌肉记忆。最后分享一个我个人的小习惯每次成功解出一道题后不要仅仅满足于拿到flag。试着去复盘整个流程思考出题人的意图甚至尝试自己用Python构造一个类似的题目。这个过程能让你从“解题者”转变为“出题者”对技术的理解会达到一个新的层次。例如你可以写个脚本自动将flag文本加密后附加到图片末尾并设置伪加密这样就能为自己或朋友创造一道小小的练习题了。安全技术的乐趣正是在于这种不断的探索、破解与创造之中。