图像隐写

binwalk

分析文件里面包含的隐藏文件

安装 binwalk:

sudo apt install binwalk
  1. 通过扫描发现目标文件中包含的所有可识别的文件类型
binwalk 文件名
  1. 自动提取出已知的文件类型
binwalk -e 文件名

zsteg

检测 pngbmp 图片里的隐写数据

Linux 下安装:

sudo gem install zsteg
  1. 查看 LSB 分析结果
zsteg 文件名
  1. 快速提取所有隐藏信息
zsteg 文件名 --all
  1. 从某个文件的偏移地址处提取出隐藏文件
zsteg -e "偏移地址" 源文件名 > 提取文件的文件名

foremost

将隐藏在文件中的其他文件分离出来

  1. 将文件分离并存放到 output 文件夹下
foremost 文件名

如果已经知道文件中包含了一个其他的文件类型,通过 binwalk 得到偏移地址,可以直接在 WinHex 中定位到该偏移地址,然后将文件的内容直接复制到一个新建的文件中,即可得到包含的文件


strings

打印文件中可打印字符串

  1. 将文件中包含的可打印字符串输出出来(有点类似于 IDA 里的 shift + F12 查看字符串)
strings 文件名
  1. 仅输出文件中包含 "flag" 的字符串
strings 文件名 | grep flag

Stegsolve

轻量级的图片隐写工具(Stegsolve 是一个 jar 包,首先需安装好 java 环境)

  1. 运行 Stegsolve
java -jar Stegsolve.jar所在路径

pngcheck

用于测试 png 图像文件的损坏、显示大小、类型、压缩信息

Linux 下安装:

sudo apt install pngcheck

Windows 版:pngcheck Home Page

  1. 使用 pngcheck 测试 png 图片
pngcheck png文件名   # 如果图片被修改了宽高,会显示:"CRC error in chunk IHDR"

其实被修改过的 png 图片在 Linux 下是无法打开查看的

因为 CRC 校验错误,双击会显示:读入PNG图像文件时发生严重错误:"IHDR:CRCerror"

png 文件头结构如下图:

隐写1.png

  1. 检测是否存在 IDAT 隐写
pngcheck -v png文件名

假设输出如下:

  chunk IHDR at offset 0x0000c, length 13
    547 x 962 image, 32-bit RGB+alpha, non-interlaced
  chunk sRGB at offset 0x00025, length 1
    rendering intent = perceptual
  chunk gAMA at offset 0x00032, length 4: 0.45455
  chunk pHYs at offset 0x00042, length 9: 5669x5669 pixels/meter (144 dpi)
  chunk IDAT at offset 0x00057, length 65445
    zlib: deflated, 32K window, fast compression
  chunk IDAT at offset 0x10008, length 65524
  chunk IDAT at offset 0x20008, length 65524
  chunk IDAT at offset 0x30008, length 65524
  chunk IDAT at offset 0x40008, length 65524
  chunk IDAT at offset 0x50008, length 65524
  chunk IDAT at offset 0x60008, length 65524
  chunk IDAT at offset 0x70008, length 65524
  chunk IDAT at offset 0x80008, length 65524
  chunk IDAT at offset 0x90008, length 45027
  chunk IDAT at offset 0xa0008, length 138
  chunk IEND at offset 0xa2e55, length 0
No errors detected in xxx (16 chunks, 68.3% compression).

IDAT有固定的长度,正常的 PNG 图片只有最后一个 IDAT 块的长度是比其他的要短的,如果在中间的位置出现了与前面不同的长度,说明存在 IDAT 隐写

因此异常数据位于 0xa0008 处,共 138 字节,提取该位置的 IDAT 数据

使用 zlib 进行压缩:

import zlib
import binascii

IDAT = "789C5D91011280400802BF04FFFF5C75294B5537738A21A27D1E49CFD17DB3937A92E7E603880A6D485100901FB0410153350DE83112EA2D51C54CE2E585B15A2FC78E8872F51C6FC1881882F93D372DEF78E665B0C36C529622A0A45588138833A170A2071DDCD18219DB8C0D465D8B6989719645ED9C11C36AE3ABDAEFCFC0ACF023E77C17C7897667".decode('hex')

result = binascii.hexlify(zlib.decompress(IDAT))

print (result.decode('hex'))

print (len(result.decode('hex')))

Steghide

一个可以将文件隐藏到图片或音频中的工具,也可以将文件从图片中分离

Linux 下安装:

sudo apt install steghide
  1. 查看图片中嵌入的文件信息
steghide info 图片
  1. 提取图片中的隐藏内容
steghide extract -sf 图片 -p 密码(如果有)

如果没有密码,输入:steghide extract -sf 图片 后直接回车即可

  1. 将文件隐藏到图片中
steghide embed -cf 图片 -ef 需要隐藏的文件 -p 密码(如果有)

盲水印

盲水印是一种肉眼不可见的水印方式,不影响原图,还可以作为版权保护

CTF 赛题中如果给了两张看起来一模一样的图片,可以考虑盲水印的可能性

  • Python 盲水印工具

Python 2.7 版本:linyacool/blind-watermark: Watermark added to the frequency domain by Fourier transform

Python 3 版本:linyacool/blind-watermark at python3

使用前需要安装 cv2 模块:

pip install opencv-contrib-python
  1. 合成盲水印图
python encode.py --image 无水印原图 --watermark 水印图 --result 加上盲水印后的原图
  1. 提取图中的盲水印(需要原图
python decode.py --original 无水印原图 --image 加上盲水印后的原图 --result 提取出的水印图

音频隐写

Audacity

Audacity 是一款音频编辑软件,可以查看音频的频率、波谱等,有时候会隐藏信息

音频分析软件 Audacity 下载地址:Audacity ® | Free


DeepSound

DeepSound 是一种隐写术工具,可以将隐藏的消息或文件嵌入到音频中

音频隐写软件 DeepSound 下载地址:DeepSound -> Download


其他隐写

Snow 隐写

“Snow 隐写就像在雪地上看到的脚印,虽然人们可能不会注意到脚印,但它们仍然存在,并且可以被检测到”

Snow 隐写是在 HTML 嵌入隐写信息,通过在行尾附加空格或制表符来隐藏 ASCii 文本中的信息,不同的空格与制表位的组合代表不同的嵌入信息

工具下载链接:Snow 隐写工具下载

可以通过 Ctrl + A 全选来查看是否含有大量空白不可见字符,从而判断是否为 Snow 隐写

参数含义
-C如果隐藏,则压缩数据,或者如果提取,则会解压缩
-Q静音模式。如果未设置,则程序报告统计信息,例如压缩百分比和可用存储空间的数量
-S报告文本文件中隐藏消息的近似空间量。考虑线长度,但忽略其他选项
-p 密码如果设置为此,则在隐藏期间将使用此密码加密数据,或在提取期间解密
-l 长度在附加空格时,Snow 将始终产生比此值短的线条。默认情况下为 80
-f 文件此文件的内容将隐藏在输入文本文件中
-m 字符串此字符串的内容将被隐藏在输入文本文件中。请注意,除非在字符串中包含一个换行符,否则在提取时不会打印换行符
  1. 常用解密命令:
SNOW.EXE -C -p 密码 Snow隐写文件
  1. 示例:

将消息 "I am lying" 隐藏在输入文件 infile 中,使用密码 "hello world" 进行加密,并将结果保存在名为 outfile 的文件中

SNOW.EXE -C -m "I am lying" -p "hello world" infile outfile

则对应的解密命令为:(生成的消息不会被换行符终止)

SNOW.EXE -C -p "hello world" outfile

零宽度字符隐写

零宽度字符是一些不可见的、不可打印的字符,主要用于调整字符的显示格式

这种隐写方式是基于零宽度字符在一般的文本编辑器中是不可见的,主要包括:

  1. 零宽度空格(\u200b
  2. 零宽度非连接符(\u200c
  3. 零宽度连接符(\u200d
  4. 从左至右书写标记(\u200e
  5. 从右至左书写标记(\u200f
  6. 零宽度非断空格符(\ufeff

例如下面这段文本:

​​​​​​​​​​​​​​​​Lorem ipsum​​​​​​​ dolor ‌‌‌‌‍‍‍sit​​​​​​​​ amet​​​​​​​​​‌‌‌‌‍‍‌, consectetur ​​​​​​​adipiscing​​​​​​​‌‌‌‌‍‬‍‬ elit​​​​​​​.‌‌‌‌‍‬‌​​​​​​​‌‌‌‌‍‬‌‍ Phasellus quis​​​​​​​ tempus​​​​​​ ante, ​​​​​​​​nec vehicula​​​​​​​​​​​​​​​​ mi​​​​​​​​. ​​​​​​​‌‌‌‌‍‬‍Aliquam nec​​​​​​​​​‌‌‌‌‍‬ nisi ut neque​​​​​​​ interdum auctor​​​​​​​.‌‌‌‌‍‍ Aliquam felis ‌‌‌‌‍‬‬‌orci​​​​​​​, vestibulum ‌‌‌‌‍‬‍sit ​​​​​​​amet​​​​​​​​​ ante‌‌‌‌‍‌‬ at​​​​​​​, consectetur‌‌‌‌‍‌ lobortis eros​​​​​​​​​.‌‌‌‌‍‍‍‌ ‌‌‌‌‍‌‌‌​​​​​​​Orci varius​​​​​​​ ​​​​​​​natoque ‌‌‌‌‍‌penatibus et ‌‌‌‌‍‬‌​​​​​​​magnis‌‌‌‌‌‌‍‌‌‌‌‌‌‍ dis ​​​​​​​‌‌‌‌‍‍parturient montes, ​​​​​​​nascetur ridiculus ‌‌‌‌‌‍‌​​​​​​​​​​​​​​‌‌‌‌‌‬‍mus. In finibus‌‌‌‌‌‌‬ magna​​​​​​‌‌‌‌‌‍ mauris, quis‌‌‌‌‍‬‌‍ auctor ‌‌‌‌‍‬‌‍libero congue quis. ‌‌‌‌‍‬‬‬Duis‌‌‌‌‍‬‌‬ sagittis consequat urna non tristique. Pellentesque eu lorem ‌‌‌‌‍‌‍id‌‌‌‌‍‬‬ quam vestibulum ultricies vel ac purus‌‌‌‌‌‌‍.

在 Windows 的文本编辑器下,会出现一些混乱:

隐写术-零宽度字符隐写3.png

而在 010 Editor 下则可以看见许多空白字符:

隐写术-零宽度字符隐写4.png

在 Kali Linux 的文本编辑器 gedit 下未见异常:

隐写术-零宽度字符隐写1.png

但如果使用 vim 打开,就可以看到很多不可见字符:

隐写术-零宽度字符隐写2.png

根据以上特点基本可以确定为零宽度字符隐写

  • 在线工具:
  1. Unicode Steganography with Zero-Width Characters

  2. Unicode Steganography with Zero-Width Characters

  • 使用 zwsp-steg-py

Github 仓库:enodari/zwsp-steg-py: Zero-Width Space Steganography, encodes/decodes hidden messages as non printable/readable characters.

安装:

pip install zwsp-steg-py

脚本:

#!/usr/bin/python  
# -*- coding: utf-8 -*-  
import zwsp_steg  
  
decoded = zwsp_steg.decode('隐写字符串', zwsp_steg.MODE_FULL)   # 另一种模式:zwsp_steg.MODE_ZWSP

print(decoded)