从EML到Flag:BUUCTF俄罗斯套娃题全流程实战解密指南
1. 初探EML文件:邮件中的秘密宝藏
当你第一次拿到这个CTF题目时,可能会对.eml文件格式感到陌生。EML实际上是Outlook等邮件客户端使用的标准邮件存储格式,它完整保留了邮件的所有元素——包括正文、附件和元数据。在Windows系统中,最简单的查看方式就是直接用记事本打开,但更专业的做法是使用邮件客户端或专用解析工具。
提示:如果系统没有安装邮件客户端,可以尝试使用在线EML查看器或Python的email模块进行解析。
通过分析附件中的eml文件,我们发现两个关键组件:
- Matry_Oshka.key- PGP私钥文件
- hack.pgp- 加密的PGP文件
但真正的第一个突破口其实隐藏在邮件头中。在"Face"字段处,有一段Base64编码的数据:
import base64 face_data = "BASE64编码字符串" # 替换为实际数据 decoded = base64.b64decode(face_data).decode('utf-8') print(decoded)解码这段数据会得到一个二维码图片的URL,扫描后将获得密码"h4ck_the_plan3t"。这个密码将成为我们后续解密PGP文件的关键。
2. PGP解密实战:从密钥导入到文件提取
2.1 PGP工具的选择与使用
虽然GnuPG(GPG)是命令行下的标准工具,但对于CTF比赛来说,PGPTool的图形界面更加友好。以下是使用PGPTool解密的详细步骤:
- 访问 PGPTool官网
- 点击"Key ring" → "Import PGP Key"
- 选择Matry_Oshka.key文件
- 在弹出的密码框中输入"h4ck_the_plan3t"
- 回到主界面,选择"Decrypt"功能
- 上传hack.pgp文件
注意:如果导入密钥时遇到错误,检查密钥文件是否完整,或者尝试用文本编辑器打开.key文件确认其格式正确。
2.2 解密后的文件处理
成功解密后,我们会得到一个名为file.bin的文件。使用file命令检查其类型:
file file.bin输出显示这是一个lzip压缩文件。但直接使用lzip解压会失败,因为文件头部有多余数据。我们需要用十六进制编辑器(如010 Editor)删除前10个字节:
| 操作步骤 | 具体命令/操作 |
|---|---|
| 1. 删除前10字节 | 在010 Editor中选中前10字节并删除 |
| 2. 保存修改 | 另存为clean_file.bin |
| 3. 解压文件 | lzip -d clean_file.bin |
解压后将得到file.bin.out,实际上是一个PDF文档。
3. 隐写术分析:从壁纸到隐藏数据
3.1 PDF中的秘密
打开PDF后,里面只有一张Windows XP的经典壁纸"Bliss"。这显然不是终点,我们需要提取其中的图片进行分析:
from PyPDF2 import PdfFileReader pdf = PdfFileReader(open('file.bin.out', 'rb')) for page in pdf.pages: for obj in page['/Resources']['/XObject'].values(): if obj['/Subtype'] == '/Image': with open('xp_wallpaper.png', 'wb') as f: f.write(obj._data)3.2 Stegsolve的高级应用
使用Stegsolve分析提取出的图片,重点关注以下通道:
- Blue通道:常被用于LSB隐写
- Red/Green通道差异:可能隐藏不同信息
- Alpha通道:如果存在透明度信息
在Blue通道0位平面,我们发现了类似二维码的结构。但与原始Windows XP壁纸对比后,确认这是人为添加的隐藏信息。将两张图片进行像素级对比:
from PIL import Image, ImageChops original = Image.open('bliss_original.png') modified = Image.open('xp_wallpaper.png') diff = ImageChops.difference(original, modified) diff.show()差异图像中清晰地显示出二维码图案,解码后得到一段特殊的Base64编码数据。
4. Base64变种与7z文件提取
4.1 非标准Base64解码
获取的Base64数据包含特殊字符"-",这是非标准变种。标准Base64使用"+"和"/"作为第62和63个字符,而这里显然做了替换。Python的base64模块支持通过altchars参数处理这种情况:
from base64 import b64decode data = "/Td6WFoAAATm1rRGAgAhARwAAAAQz1jM4ELCAORdABhgwwZfNTLh1bKR4pwkkcJw0DSEZd2BcWATAJkrMgnKT8nBgYQaCPtrzORiOeUVq7DDoe9feCLt9PG-MT9ZCLwmtpdfvW0n17pie8v0h7RS4dO/yb7JHn7sFqYYnDWZere/6BI3AiyraCtQ6qZmYZnHemfLVXmCXHan5fN6IiJL7uJdoJBZC3Rb1hiH1MdlFQ/1uOwaoglBdswAGo99HbOhsSFS5gGqo6WQ2dzK3E7NcYP2YIQxS9BGibr4Qulc6e5CaCHAZ4pAhfLVTYoN5R7l/cWvU3mLOSPUkELK6StPUBd0AABBU17Cf970JQABgALDhQEApzo4PbHEZ/sCAAAAAARZWg==" with open('flag.7z', 'wb') as f: decoded = b64decode(data, altchars='-/') f.write(decoded)关键点解析:
altchars='-/'表示用"-"替换标准中的"+",用"/"替换标准中的"/"(虽然第二个替换是冗余的)- 解码后的数据实际上是7z压缩文件的二进制格式
4.2 最终Flag提取
使用7zip解压得到的文件:
7z x flag.7z解压后得到的二进制文件,可以使用CyberChef进行快速分析。在"Magic"模式下,CyberChef会自动识别文件格式并提取可读内容,最终我们获得了flag:
flag{delat_iz_muhi_slona}5. 解题技巧与常见问题
5.1 工具链准备
为了高效解决此类CTF题目,建议准备以下工具集:
| 工具类别 | 推荐工具 | 主要用途 |
|---|---|---|
| 文件分析 | file, binwalk | 识别文件真实类型 |
| 十六进制编辑 | 010 Editor, HxD | 手动修改文件结构 |
| 隐写分析 | Stegsolve, zsteg | 图像隐写分析 |
| 加解密 | GPG, PGPTool | PGP加密解密 |
| 编码转换 | CyberChef | 各种编码转换和分析 |
5.2 常见错误排查
PGP解密失败:
- 检查密钥文件是否完整
- 确认密码完全正确(注意大小写和特殊字符)
- 尝试不同的PGP工具(GPG vs PGPTool)
Base64解码问题:
- 注意非标准变种(字符替换、填充缺失等)
- 尝试不同的altchars组合
- 检查解码后的文件头是否符合预期
隐写分析技巧:
- 尝试不同的位平面组合
- 对比原始图像和修改后的图像
- 检查EXIF等元数据
在实战中,我经常遇到Base64变种解码的问题。有一次比赛中的Base64数据使用了"!"和"@"作为替换字符,花了我近一个小时才意识到这一点。关键是要仔细观察数据中的特殊字符,并尝试不同的替换组合。