CTFMisc之隐写基础学习
0x00 基础概念
本质: “藏信息于无形”。将秘密信息(Payload)
嵌入到一个看似无害的普通载体文件(Cover Medium)
中,产生一个含密文件(Stego Medium)
。关键在于隐蔽性——让观察者无法察觉到秘密信息的存在。
与密码学的区别:
- 密码学
(Cryptography)
: 保护信息的内容。信息是可见的(乱码),但无法理解。 - 隐写术
(Steganography)
: 保护信息的存在本身。信息被隐藏起来,观察者不知道有秘密存在。
CTF
解题目标:
- 检测
(Detection)
: 判断给定文件是否可能包含隐藏信息(寻找异常)。 - 提取
(Extraction)
: 使用正确的工具和技术,无损地将隐藏信息(Flag)
取出。 - 理解/解码
(Decoding)
: 提取出的信息可能需要进一步解码(Base64
,Hex
, 二进制等)或解密才能得到Flag
。 - 核心挑战: 信息隐藏的方式千变万化,需要敏锐的观察力、对文件格式的理解、熟悉各种工具以及一定的创造力。
0x01 隐写术分类
-
按载体类型
(Cover Medium)
- 图像隐写
(Image Steganography)
: 最常见。载体:JPG, PNG, BMP, GIF, TIFF, WebP
等。 - 音频隐写
(Audio Steganography)
: 载体:WAV, MP3, FLAC, OGG, AU
等。 - 视频隐写
(Video Steganography)
: 载体:MP4, AVI, MOV, WebM
等。可视为图像+音频隐写的组合,或利用帧间特性、时间戳。 - 文本隐写
(Text Steganography)
: 载体:TXT, HTML, PDF, DOCX, PPTX
,甚至源代码文件。隐蔽性高,检测难。 - 文件结构隐写
(File Structure Steganography)
: 利用文件格式本身的特性: - 文件拼接/附加
(Appending/Concatenation)
: 将秘密文件(如ZIP
)直接附加到载体文件末尾。 - 文件容器
(File Containers)
: 将文件藏在另一个文件的未使用空间(如ZIP in PNG
)。 - 元数据
(Metadata)
: 在文件头尾、注释区或专用字段(如EXIF
,ID3
)中隐藏信息。 - 特殊文件系统特性: 如
NTFS
交换数据流(ADS
)。 - 网络协议隐写
(Network Protocol Steganography)
: 在网络包(IP/TCP
头字段、时序、包序)中隐藏信息(多见于流量分析题)。 - 其他载体: 可执行文件
(EXE)
、文档(PDF
深层对象)、文件系统镜像、甚至二维码/条形码。
- 图像隐写
-
按信息嵌入方式
(Embedding Method)
- 主要针对数字媒体- 空域/时域隐写
(Spatial/Temporal Domain)
: 直接修改原始数据。 - 最低有效位
(LSB - Least Significant Bit)
: 最最常用! 修改像素颜色值(R/G/B/Alpha)
或音频样本值的最低1-N
位。 - 位平面操作: 操作图像的不同比特位平面。
- 变换域隐写
(Transform Domain)
: 修改载体在变换域(如频域)的系数。 - 离散余弦变换
(DCT)
:JPEG
图像核心,在DCT
系数(尤其AC
系数)中嵌入。 - 离散小波变换
(DWT)
: 在图像/音频的小波系数中嵌入。 - 离散傅里叶变换
(DFT)
: 在频域系数中嵌入。 - 压缩域隐写: 直接在压缩后的数据流(如
JPEG
的熵编码流、MP3
帧)中嵌入。 - 生成式隐写: 利用
AI
模型(如GAN
)生成本身就包含隐藏信息的载体。 - 利用格式特性: 如
GIF
的调色板排序、PNG
的辅助块(tEXt, zTXt
)、文件格式的填充区/保留区。
- 空域/时域隐写
0x02 元数据 (Metadata)
- 图像
EXIF
:数码照片的元信息(相机型号、时间、GPS
、注释等)。Flag
常藏在Comment、Artist、Copyright、Software、UserComment、XPComment
等字段。 - 音频
ID3 Tags
:MP3
等文件的元信息(标题、艺术家、专辑、注释等)。 - 文档属性:
PDF、Office
文档的属性(标题、作者、主题、关键词、自定义属性)。 - 文件头尾: 在标准文件头/尾的保留或填充区域写入数据。十六进制编辑器仔细检查。
也可以用exiftool
直接查看
0x03 图片宽高修改
PNG
图片格式
PNG
的宽高存储在IHDR
块的前8
个字节(宽度4
字节 + 高度4
字节),位置固定;IHDR
块位置:紧接文件头后的13
字节处 开始(第13-16
字节为宽度,第17-20
字节为高度)。
上面为正常图片,用010editor
打开
将02B1
修改为01B1
,长度缩短以后,flag
就能被隐藏起来了
还可以拿脚本进行爆破
import binascii
import struct
import os
crcbp = open("flag.png","rb").read()#填文件名
for i in range(1024):for j in range(1024):data = crcbp[12:16] + struct.pack('>i',i) + struct.pack('>i',j) + crcbp[24:29]crc32 = binascii.crc32(data) & 0xffffffffif crc32 == 0x3a9ffab2 :#此处填CRC值print (i);print (j);print (hex(i),hex(j))
JPG
图片格式
JPG
的宽高存储在SOF0
段(Start of Frame
),位置不固定,需扫描标记,结构更复杂:- 文件头:以
FF D8 FF
开头。 SOF0
标记:通过扫描FF C0
到FF CF
之间的标记定位(常见为FF C0
)。- 宽高位置:在
SOF0
标记后第5
字节开始(2
字节高度 +2
字节宽度)。
在JPG
图片中修改宽度导致图片混乱而修改高度不会,这是由于JPG
的压缩原理和MCU
(最小编码单元)机制导致的。
MCU
的作用:
JPG
将图像分割为多个8×8
像素的块(称为MCU
)- 宽度方向必须对齐
MCU
边界(通常是8
或16
像素的倍数) - 若修改后的宽度不是
MCU
的整数倍,解码器无法正确重建图像
高度与宽度的不对称性:
- 高度:可任意修改(只需是整数行),解码器按行处理
- 宽度:必须满足
width % MCU_width == 0
(否则破坏块对齐)
下面是一张正常的jpg
通过010editor
打开,查询ffc0
后,修改高的值
修改后,可以隐藏flag
了
0x04 GIF隐写
1)基于图像的隐写。GIF
中可以包含多个图像,出题人可以在某幅图像傻姑娘隐写信息。我们需要分离出GIF
的每幅图片,并针对每幅图片进一步分析。用Stegsolve
可以一帧一帧查看,往往答案就隐藏在其中一帧
2)基于时间的隐写。这种方式非常隐蔽,因为GIF
中的每幅图像都会有延迟时间,可以约定不同的延迟时间代表不同的含义,例如延迟100ms
代表1
,延迟50ms
代表0
,从而达到传输秘密信息的目的。可以通过命令获取GIF
每帧的延迟时间
用软件对比了下时间,一个是4
一个是40
查了下资料-format
相关的资料
所以基于以上信息来看是没毛病的
0x05 文件附加/拼接 (File Appending)
原理: 将另一个完整文件(常是ZIP, RAR, PDF
, 另一张图)直接追加到载体文件末尾。文件解析器会忽略尾部多余数据。
载体: 任何文件类型,图片最常见。
检测:
- 文件大小: 异常大。
binwalk
:binwalk stego.jpg
扫描内部文件签名。看到Zip archive data
或RAR archive data
就是铁证。- 十六进制编辑器: 查看文件尾部,寻找
PK(ZIP), Rar!(RAR), %PDF(PDF)
等魔术头。 strings
:strings stego.jpg | grep -i "flag"
或搜索PK/Rar
。
先制作一个文件带压缩文件的图片
提取方式:
binwalk -e
尝试自动提取。
dd
: 根据binwalk
或编辑器找到的偏移量(offset)
,精确切割
dd if=stego.jpg of=secret.zip skip=123456 bs=1 skip=78804
。
foremost
:类似于binwalk
的工具,新版kali
已经默认不安装了- 改后缀: 尝试将文件后缀改为
zip
或rar
,直接解压。
0x06 最低有效位 (LSB)
原理: 数字图像像素(RGB
各8
位,共24
位)或音频样本(如16
位)的最低几位对人眼/耳感知影响最小。用秘密信息的比特流替换这些LSB
。
载体偏好: PNG
(无损,完美)、BMP
(未压缩)、WAV
(未压缩音频)。
检测:
视觉/听觉: 大量修改时,图像可能在纯色区域出现细微噪点/色偏;音频可能有轻微底噪。
统计分析: 检查LSB
位平面0/1
分布是否偏离随机。
工具扫描: zsteg
(专攻PNG/BMP
)、Stegsolve
(Java
,可视化分析位平面)、stego-lsb
(Python
库)。
下面是一个用于写入lsb
的脚本
from PIL import Imagedef hide_message_in_image(image_path, message, output_path):# 加载原始图像img = Image.open(image_path)img = img.convert("RGB")# 将文本转换为二进制字符串message_binary = ''.join([format(ord(char), '08b') for char in message])# 获取图像像素数据pixels = img.load()pixel_index = 0message_length = len(message_binary)# 遍历像素并替换LSBfor row in range(img.size[1]):for col in range(img.size[0]):if pixel_index < message_length:# 获取当前像素的R, G, B值pixel = list(pixels[col, row])# 替换R, G, B值中的最低有效位pixel[0] = pixel[0] & ~1 | int(message_binary[pixel_index])pixel[1] = pixel[1] & ~1 | int(message_binary[pixel_index + 1])pixel[2] = pixel[2] & ~1 | int(message_binary[pixel_index + 2])pixel_index += 3# 将修改后的像素数据写回图像pixels[col, row] = tuple(pixel)else:breakelse:continuebreakimg.save(output_path)print("Message hidden successfully!")hide_message_in_image("lsbtest.png","flag{hiehiehie}","png_lsb.png")
用stegslove
可以解决,直接看到flag
0x07 word隐写
word
中隐藏字段:在Word
中选中要隐藏的字段,右击选择字体选项,在效果一栏中有隐藏选项,选中后即可隐藏。默认情况下隐藏文字是不会被打印出来的。
隐藏后如下
- 白色背景下的白字无法被识别出有隐藏的文字。
破解:全选改字体颜色为别的颜色、搜索字符串,例如flag
等
word
中隐藏图片:word
中插入的图片分为嵌入式和非嵌入式,区别在嵌入式会跟着文本的位置产生移动,即有回车后,图片下移。但非嵌入的不会跟着文本走,即有回车后,图片保持原位置不动。
破解:word
改后缀名为zip
然后解压
比如这张图在设置嵌入式后,设置成在文本下方,就伪装成了水印的效果,其实是藏了一张图片在这里。
0x08 JPEG 隐写
原理: 在JPEG
压缩过程中的量化DCT
系数(尤其是中频系数)中嵌入信息,比LSB
更抗有损处理。
工具:
outguess
: 经典工具,有特定变种。outguess -r stego.jpg output.txt
(可能需要-k
指定密钥)。
jsteg
: 较老的JPG
隐写工具。jsteg reveal stego.jpg output.txt
。
stegseek
: 针对steghide
的暴力破解工具,速度快。stegseek stego.jpg wordlist.txt
。
安装outguess
git clone https://github.com/crorvick/outguess.git
cd outguess
./configure && make && sudo make install
加密数据
outguess -k "your-secret-key" -d secret.txt carrier.jpg output.jpg
解密数据
outguess -k "your-secret-key" -r output.jpg extracted.txt
0x09 音频隐写 (Audio Steganography)
常见技术: LSB
、频谱隐写(在声谱图中藏图/二维码)、相位编码、回声隐藏、扩频隐写。
工具:
Audacity
查看波形、频谱图(Spectrogram)
、分析音轨。Sonic Visualiser
: 专业音频分析,多种视图/插件。steghide
: 支持WAV/AU
。DeepSound
: 支持在音频中隐藏文件和加密。stego-lsb
: 支持WAV
音频的LSB
隐写。
比如这个就是摩斯密码
0x10 伪加密 (Fake Encryption)
ZIP/RAR
文件设了密码但实际为空、弱密码或已知密码。
- 无加密
压缩源文件数据区的全局加密应当为0000
(504B0304
两个bytes
之后)
且压缩源文件目录区的全局方式位标记应当为0000
(504B0304
四个bytes
之后) - 假加密
压缩源文件数据区的全局加密应当为0000
且压缩源文件目录区的全局方式位标记应当为0900
- 真加密
压缩源文件数据区的全局加密应当为0900
且压缩源文件目录区的全局方式位标记应当为0900
0x11 损坏的文件头
故意修改文件头魔术字节(Magic Bytes
)使其看起来损坏或类型错误(如PNG
改成了JPG
头)。
CTF
中常见文件的文件头(十六进制)
jpg FF D8 FF E0或FF D8 FF E1或FF D8 FF E8
png 89 50 4E 47
bmp 42 4D 36 5D
gif 47 49 46 38
zip 50 4B 03 04
rar 52 61 72 21
mp3 49 44 33 03
wav 52 49 46 46
可以使用file
命令识别后,用十六进制工具补充或者修改
0x12 结束
列举了常见的一些方法,还有很多没有时间整理和总结,用到的时候再说吧(应该对我来说没啥机会吧),学不会真的学不会