[ misc 知识点 ] 图片隐写
2026-08-22 20:05:38
1.图片隐写(决策树版)
用法:拿到图片 → 走”做题顺序” → 命中特征再查对应节。
原百科版备份:_backup_md/pre-rewrite-20260818/1.图片隐写.md
- 宽高修改 / 结构隐写 / LSB / EXIF / FFT隐写 / JPG隐写 / GIF提取 / 盲水印 / 数字水印 / 汉信码 / 像素处理 / 图片分离 / 光栅图片 / IDAT隐写 / 图片修复 / Arnold / Steghide / Silenteye / Outguess / APNG / EZStego / 二维码 / 马赛克
🏷️ 例题:
| 20251201ISCTF 星髓宝盒/阿利维亚的传说/小蓝鲨的二维码
| 20260124SpringCTF ez_signin(二维码修复)/看图猜flag
| 20251108浙江省赛 RealSignin
| 20251206Mini VN welcome.pdf(汉信码+盲水印)
| NSSCTF刷题 zystego(LSB+DCT+PGP)/ Picture
| LitCTF2026 lit_lsb_base64 / lit_rush_qr
| 例题-图片隐写 0和255 / 网鼎杯-青龙-虚幻2(二维码修复)
做题顺序(默认流程)
010看文件尾有没有附加数据;binwalk -eM分离exiftool扫元数据(Comment/Artist 常直接藏 flag)zsteg/stegsolve扫 LSBpngcheck -v看 chunk 结构(IDAT 数量异常?CRC 对不上?)- 宽高爆破(PNG 有 CRC 校验才能爆;JPG 看 SOF0)
- 都没有 → 盲水印 / FFT / 像素级 / 工具隐写(steghide/outguess/silenteye)
png
- 块结构:IHDR / IDAT / IEND,每块末尾 4 字节 CRC32(注意拼写:
49 48 44 52) - 宽高被改但 CRC 没更新 → 爆破宽高匹配 CRC:
1 | import zlib |
jpg
- 基于标记的流式格式,宽高无 CRC 校验
- 标记表(记住 C0/C4/DB 的区别):
| 标记 | 含义 |
|---|---|
FF D8 |
SOI |
FF E0 |
APP0(JFIF) |
FF E1 |
APP1(EXIF) |
FF C0 |
SOF0(帧头,宽高在这里) |
FF C4 |
DHT(霍夫曼表) |
FF DB |
DQT(量化表) |
FF DA |
SOS(压缩数据开始) |
FF D9 |
EOI |
- 工具:
jpeginfo -c 1.jpg检查错误;exiftool -v3 1.jpg看 SOF 位置 - 坑:
FF D8和FF D9之间多余的FF Ex段 = 附加数据;ZIP 常直接接在FF D9后面
bmp
- 无 CRC / 校验字段;文件头 14 字节 + 信息头 40 字节,宽高 4 字节小端(
84 03 00 00→ 0x384 = 900) - 详解见 Misc tools bmp 段
LSB
- 特征:zsteg/stegsolve 直接出东西;RGBA 图 Alpha 通道只有 254/255(最低位正好编码 0/1)
- 原理一行:改最低位人眼不可见;R/G/B/A 每个通道都能藏
- 工具:zsteg / stegsolve / 自写提取脚本(见 20260322polarctfmisc 隐藏的二维码)
1 | # alpha.py:查看 Alpha 值分布是否只有 254/255 |
盲水印 / 数字水印
- 特征:给两张”一模一样”的图 → 先像素差/XOR;什么都没有 → 盲水印(频域)
- 工具:BlindWaterMark(python/java 版);有的题给一张图 + 嵌入参数就能提
- 例题:例题-图片隐写
EXIF
- 工具:
exiftool image.jpg;010 搜Exif/JFIF - 藏匿点:Comment(最常用)/ Artist / ImageDescription / Make / Model
- 写入:
exiftool -Comment="flag{...}" image.jpg
JPG 隐写工具
| 工具 | 特征 | 用法 |
|---|---|---|
| steghide | JPG/BMP/WAV,体积不变,需要密码 | steghide extract -sf file -p pwd;无密码→爆破/看提示 |
| outguess | 专攻 JPG | outguess -r |
| stegdetect | 检测工具,判断 jsteg/jphide/outguess/f5 | stegdetect target.jpg |
| silenteye | 图片+音频,特征=电子噪音/蜂鸣声 | GUI |
GIF / APNG
- 逐帧:stegsolve Frame Browser /
convert input.gif frame_%02d.png/ ezgif split;APNG 用apngdis - 坑:帧间隔时间本身也能编码信息
1 | # gif帧提取:python gif_frames.py xxx.gif [out_dir] |
FFT / 频域隐写
- 特征:图有规律条纹/网格/对称花纹;频谱图(幅度谱)有异常亮点
- 流程:
np.fft.fft2→fftshift→ 看幅度谱 → 提取
1 | import numpy as np |
IDAT 隐写
- 检查:
pngcheck -v target.png;010 看每个 IDAT 块大小 - 特征:IDAT 数量异常 / 块间有冗余数据 / 插了不参与渲染的数据
图片修复
| 问题 | 处理 |
|---|---|
| 文件头损坏 | 补魔数:PNG 89 50 4E 47 0D 0A 1A 0A;JPG FF D8 FF;GIF 47 49 46 38;BMP 42 4D |
| 文件尾缺失 | PNG IEND 49 45 4E 44 AE 42 60 82;JPG FF D9;GIF 00 3B |
| 宽高被改 | PNG → CRC 爆破;JPG → SOF0 段改宽高 |
| 中间嵌文件 | binwalk -eM / foremost / 010 搜 50 4B、52 61 72 剪切 |
Arnold 置乱
- 特征:提示 Arnold / 周期性纹理的马赛克图
- 公式:
x' = (x+y) mod N, y' = (x+2y) mod N(变换有周期,继续变换能复原)
1 | import numpy as np |
二维码
- 残缺/被遮挡 → 补三个定位图案(有容错率);反色/颜色异常 → 反色再扫;多码拼接 → 分离后单独扫
- 扫码优先手机/微信(pyzbar 对破损码识别差)
- 深入(结构化拼接/SA Header/掩码)→ 7.二维码;修复 → Qrazybox
马赛克
- 给了原图+马赛克 → 对比猜测被盖区域
- 只有马赛克 → 一般不可逆;但棋盘格/同色块替换可以推(同色块=同一值)
光栅图片 / 视觉密码
- 两张随机噪声图 → 重叠(AND/XOR)出图案:
1 | from PIL import Image |
图片分离
binwalk -eM target.png(基于签名,能识别嵌入格式)foremost target.png(基于文件头尾雕刻,只认内置格式)- 手动:010 搜
50 4B(ZIP)/52 61 72(RAR),剪切另存
像素处理
- 特征:zsteg/steghide 都没结果,但图里明显有异色小点
- 玩法:坐标 (x,y) 映射 / 只取某个通道 / 只取特定颜色像素(如纯红 FF0000)
其他工具
- EZStego:索引色图(GIF/PNG-8)调色板重排隐写;zsteg 可扫
- 汉信码:定位图案是散布四角的同心小方块(不是三个角大方块);微信小程序”汉信码”扫
- OurSecret / DeepSound / OpenPuff / 零宽:见 Misc tools
附:LSB 深入(含调色板 LSB)
← 返回 图片隐写 | 相关工具 Misc tools
🏷️ 例题:
| 20260124SpringCTF 橘师傅切他上路(调色板LSB)
| 20251206Mini VN wav也能像png那样美丽吗(WAV LSB)
| 20260130春秋杯 隐形的守护者
LSB的核心思想是
任何可以被量化为离散数值的载体,其最低有效位都可以被替换来藏信息。
一、本质:LSB到底在操作什么
1 | 原始值 V → V' = (V & 0xFE) | secret_bit |
改动量最大是±1,肉眼无法察觉。这个操作对任何整数型数据都成立
二、图像类LSB变体
1.经典RGB/RGBA像素LSB
2.调色板LSB——易踩坑
为什么调色板LSB不一样
索引色图像(GIF PNG-8)的像素值不是颜色,而是调色板索引号。
数据结构如下
1 | 调色板 (Palette): |
隐写可以发生在两个层面:
| 层面 | 操作对象 | 隐写方式 | 检测难度 |
| 调色板颜色值 LSB | 调色板中 RGB 分量 | 修改调色板条目的 R/G/B 最低位 | 低(调色板通常很小,肉眼可对比) |
| 像素索引值 LSB | 像素引用的索引号 | 修改像素的索引号最低位 | 高(需要理解索引与颜色的映射关系) |
关键陷阱:索引号的 LSB 改变不等于颜色的LSB改变
exp
1 | from PIL import Image |