从蓝桥杯CTF选拔赛看起:手把手教你用Python脚本破解那道“缺失的数据”隐写题
从零破解CTF图像隐写题:Python脚本实战ZIP爆破与DWT+Arnold变换
1. 前言:当CTF新手遇到"缺失的数据"
第一次看到这道题时,我正对着一个加密的ZIP压缩包和一张看似普通的PNG图片发呆。题目描述只有简单的一句:"关键数据藏在图片里,但需要先找到打开它的钥匙"。作为刚接触CTF安全竞赛的新手,这种涉及多重加密的题目确实让人望而生畏。但经过系统拆解后,我发现这道题完美融合了 ZIP密码爆破 和 图像隐写分析 两大基础技能点,是入门数字取证的绝佳案例。
本文将带你用Python还原完整解题流程,重点解决两个核心问题:
- 如何在没有密码的情况下暴力破解ZIP文件
- 如何从图片中提取经过DWT小波变换和Arnold置乱加密的隐藏信息
2. 工具准备与环境搭建
2.1 必备工具清单
在开始前,请确保准备好以下工具和环境:
# Python库安装
pip install pywavelets opencv-python numpy
| 工具名称 | 用途说明 | 获取方式 |
|---|---|---|
| ARCHPR | ZIP密码字典攻击工具 | 官网下载绿色版 |
| Python 3.8+ | 运行隐写分析脚本 | 官方安装包 |
| 7-Zip | 压缩包处理 | 开源免费工具 |
| 文本编辑器 | 查看/修改脚本 | VS Code/PyCharm等 |
2.2 创建解题工作目录
建议按以下结构组织文件:
/CTF-Challenge
│── /original_files
│ ├── secret.zip # 待破解的加密压缩包
│ └── hint.txt # 题目提供的线索
│── /dictionaries # 密码字典存放处
│── /output # 解压和脚本输出目录
│── extract_flag.py # 隐写分析主脚本
3. 第一阶段:破解ZIP密码
3.1 分析压缩包特征
首先用7-Zip检查压缩包信息:
7z l -slt secret.zip
关键信息提取:
- 加密算法:ZIP传统加密(非AES)
- 包含文件:a.png
- 注释字段:无特殊提示
这类传统加密的ZIP对字典攻击非常敏感,我们需要准备合适的密码字典。
3.2 制作针对性字典
根据CTF出题规律,优先尝试以下密码类型:
# 常见弱密码生成示例
weak_passwords = [
"password", "123456", "qwerty",
"admin", "ctf", "flag",
"secret", "pavilion", "2023",
"password123", "welcome1"
]
专业技巧 :将题目描述中的关键词(如"缺失的数据")进行以下变形后加入字典:
- 拼音全拼:queshideshuju
- 首字母缩写:qsdsj
- 常见英文翻译:missingdata
3.3 使用ARCHPR进行爆破
ARCHPR(Advanced Archive Password Recovery)操作步骤:
- 选择ZIP文件路径
- 攻击类型选择"字典攻击"
- 加载准备好的字典文件
- 开始攻击并监控进度
注意:如果字典攻击未成功,可尝试切换为"掩码攻击"或"暴力破解",但耗时将显著增加
成功破解后,我们得到密码: pavilion ,解压获得关键文件 a.png 。
4. 第二阶段:图像隐写分析
4.1 初识DWT+Arnold隐写技术
题目使用的隐写方案结合了两种核心技术:
-
DWT(离散小波变换) :
- 将图像分解为不同频率子带
- 在HL/LH/HH等高频区域嵌入信息
- 对视觉影响小,鲁棒性强
-
Arnold变换 :
- 经典的图像置乱算法
- 通过迭代使像素位置随机化
- 需要知道变换次数才能复原
4.2 逆向分析Python脚本
从题目给出的脚本中,我们提取出关键参数:
class WaterMarkDWT:
def __init__(self, origin: str, watermark: str, key: int, weight: list):
self.key = key # Arnold变换次数=20
self.coef = weight # 小波系数=[0.2, 0.2, 0.5, 0.4]
逆向思路:
- 对a.png执行Arnold正变换20次
- 进行三级'db2'小波分解
- 按给定系数提取各子带隐藏信息
4.3 完整逆向脚本实现
import cv2
import numpy as np
import pywt
def recover_hidden_data(encrypted_img_path):
# 初始化参数(与加密时一致)
arnold_iterations = 20
wavelet_type = 'db2'
decomposition_level = 3
coefficients = [0.2, 0.2, 0.5, 0.4]
# 读取加密图像
img = cv2.imread(encrypted_img_path, cv2.IMREAD_GRAYSCALE)
# Arnold正变换(置乱)
def arnold_transform(image, iterations):
h, w = image.shape
for _ in range(iterations):
temp = np.zeros_like(image)
for i in range(h):
for j in range(w):
x = (i + j) % h
y = (i + 2*j) % w
temp[x, y] = image[i, j]
image = temp
return image
# 执行置乱还原
arnold_img = arnold_transform(img, arnold_iterations)
# 小波分解
coeffs = pywt.wavedec2(arnold_img, wavelet_type, level=decomposition_level)
# 提取隐藏信息
ca1 = coeffs[0] / coefficients[0]
ch1 = coeffs[1][0] / coefficients[1]
cv1 = coeffs[1][1] / coefficients[2]
cd1 = coeffs[1][2] / coefficients[3]
# 小波重构
recovered_watermark = pywt.waverec2([ca1, (ch1, cv1, cd1)], wavelet_type)
# 后处理
recovered_watermark = np.uint8(np.clip(recovered_watermark, 0, 255))
cv2.imwrite('recovered_flag.png', recovered_watermark)
return recovered_watermark
# 执行恢复
recover_hidden_data('a.png')
4.4 结果验证与优化
首次运行可能遇到以下问题及解决方案:
-
图像全黑/全白 :
- 检查Arnold变换次数是否正确
- 尝试调整小波系数±10%
-
部分信息模糊 :
# 添加形态学处理增强对比度 kernel = np.ones((3,3), np.uint8) enhanced = cv2.morphologyEx(result, cv2.MORPH_CLOSE, kernel) -
文字扭曲严重 :
- 在Arnold变换后添加高斯滤波
blurred = cv2.GaussianBlur(arnold_img, (5,5), 0)
最终输出的 recovered_flag.png 中应清晰显示flag内容。
5. 技术深度解析
5.1 DWT隐写原理详解
三级小波分解后的子带分布:
| 子带 | 频率特征 | 常用嵌入强度 |
|---|---|---|
| LL3 | 最低频近似成分 | 不嵌入 |
| HL3 | 水平方向高频 | 0.1-0.3 |
| LH3 | 垂直方向高频 | 0.1-0.3 |
| HH3 | 对角线方向高频 | 0.3-0.5 |
嵌入公式: $$ W' = W + \alpha \cdot S $$ 其中$W$为原始小波系数,$S$为秘密信息,$\alpha$为强度系数。
5.2 Arnold变换数学原理
Arnold变换的矩阵表示为: $$ \begin{pmatrix} x' \ y' \end{pmatrix} = \begin{pmatrix} 1 & 1 \ 1 & 2 \end{pmatrix} \begin{pmatrix} x \ y \end{pmatrix} \mod N $$
其周期性取决于图像尺寸$N$,对于$N \times N$图像,变换周期$T$满足: $$ T \approx \frac{\pi N}{2\sqrt{3}} $$
6. 防御与检测方案
6.1 如何增强隐写安全性
如果作为出题方,可以采取以下措施增加破解难度:
-
复合加密 :
# 先Arnold再DWT最后LSB img = arnold(img, 20) img = dwt_embed(img, secret) img = lsb_replace(img, key) -
动态参数 :
- 将迭代次数作为密码函数
iterations = hash(password) % 50 + 10 -
噪声干扰 :
# 添加高斯噪声 noise = np.random.normal(0, 5, img.shape) img = np.clip(img + noise, 0, 255)
6.2 隐写检测技术
使用Python检测可疑图像:
def detect_stegano(image_path):
img = cv2.imread(image_path, 0)
# 计算残差图像
blur = cv2.GaussianBlur(img, (5,5), 0)
residual = cv2.absdiff(img, blur)
# 分析统计特征
mean = np.mean(residual)
std = np.std(residual)
# 经验阈值
if std > 15 and mean > 5:
print("可能包含隐写内容!")
return True
return False
7. 扩展训练建议
想要真正掌握这类题型,建议按以下路径练习:
-
基础训练 :
- 单独练习ZIP密码爆破(尝试不同字典)
- 用Python实现Arnold变换可视化
-
中级挑战 :
- 修改脚本支持不同小波基(haar/sym等)
- 尝试彩色图像的隐写分析
-
高级应用 :
# 实时隐写检测工具 import matplotlib.pyplot as plt def analyze_frequency(image): coeffs = pywt.wavedec2(image, 'db2', level=3) plt.figure(figsize=(12,8)) for i, (c, (h,v,d)) in enumerate(zip(coeffs[:-1], coeffs[1:])): plt.subplot(3,3,i+1) plt.imshow(h, cmap='gray') plt.title(f'HL{i+1}') plt.show()
在实际CTF比赛中,这类题目通常会与其他技术(如流量分析、逆向工程)结合出现。建议从Github上的CTF题库中寻找类似题目进行针对性训练,逐步建立完整的取证分析思维体系。
更多推荐
所有评论(0)