一、附加式图片隐写

这种隐写方式通常是使用某种方式在载体文件中直接附加上要被隐写的信息。

在CTF中,这类图片隐写大概有两种经典方式:

​ 1、直接附加字符串

​ 2、图种形式的隐写

附加字符串

这种类型可以用strings命令来查找

关于strings命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
strings命令在对象文件或二进制文件中查找可打印的字符串。字符串是4个或更多可打印字符的任意序列,以换行符或空字符结束。 strings命令对识别随机对象文件很有用。

用法:strings [选项] [文件]
打印 [文件] (默认为标准输入) 中可打印的字符串
选项为:
-a --all:扫描整个文件而不是只扫描目标文件初始化和装载段
-f –print-file-name:在显示字符串前先显示文件名
-t --radix={o,d,x} :输出字符的位置,基于八进制,十进制或者十六进制
-e --encoding={s,S,b,l,B,L} :选择字符大小和排列顺序:s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit

-d --data Only scan the data sections in the file
-n --bytes=[number] Locate & print any NUL-terminated sequence of at
-<number> least [number] characters (default 4).
-w --include-all-whitespace Include all whitespace as valid string characters
-o An alias for --radix=o
-T --target=<BFDNAME> Specify the binary file format
-s --output-separator=<string> String used to separate strings in output.
@<file> Read options from <file>
-h --help Display this information
-v -V --version Print the program's version number
strings:支持的目标: elf64-x86-64 elf32-i386 elf32-iamcu elf32-x86-64 pei-i386 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big pe-x86-64 pe-bigobj-x86-64 pe-i386 srec symbolsrec verilog tekhex binary ihex plugin

例如strings 1.jpg |grep flag查找1.jpg中可打印字符串中含有flag的字符串

这种类型一般是将信息插到图片的尾部,少数是插到中间。

图种形式的隐写

图种这是一种以图片文件为载体,通常为jpg格式的图片,然后将zip等压缩包文件附加在图片文件后面。因为操作系统识别的过程中是,从文件头标志,到文件的结束标志位,当系统识别到图片的结束标志位后,默认是不再继续识别的,所以我们在通常情况下只能看到它是只是一张图片。

利用Linux中的binwalk命令即可识别此图片文件都包含了什么文件 查询命令binwalk 1.jpg分离命令binwalk -e 1.jpg

分离文件也可用foremost foremost 1.jpg

binwalk可以自动识别出图片中藏的zip文件以及显示出偏移,binwalk命令还可以解压zilb数据

不想用命令的话可以用16进制编辑器打开图片文件,手动提取出压缩包,这就要求了要熟悉各种常见文件的文件头标识和结束标识(自行百度

二、基于文件结构的图片隐写

主要介绍关于png图片的隐写,关于png文件结构戳这里

重点了解一下png图片文件头数据块以及png图片IDAT块,这次的隐写也是以这两个地方为基础的。

png图片文件头数据块(IHDR)

IHDR中,包括了图片的宽,高,图像深度,颜色类型,压缩方法等

IDAT数据块

它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。这是一个可以存在多个数据块类型的数据块。它的作用就是存储着图像真正的数据。因为它是可以存在多个的,所以即使我们写入一个多余的IDAT也不会多大影响肉眼对图片的观察

高度被修改导致的隐写

图片的高度,宽度的值存放于PNG图片的文件头数据块,那么我们就可以通过修改PNG图片的高度值,来对部分信息进行隐藏的。

辨别:图片在Windows系统下能正常显示而Linux系统不能正常显示,这时候就要考虑图片高度是否被修改了

推荐一手010editor(一个16进制编辑器),可以运行图片模板,运行模板后可以轻易的找到图片的各个数据块位置及内容

知道高度被修改后可以直接改大高度也可以用脚本根据crc校验值爆破出来

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
import struct
import binascii
from Crypto.Util.number import bytes_to_long

img = open('图片的绝对路径', 'rb').read()

for i in range(0xFFFF):
stream = img[12:20] + struct.pack('>i', i) + img[24:29]
crc = binascii.crc32(stream)
if crc == bytes_to_long(img[29:33]):
print(hex(i))#输出高度的十六进制

隐写信息以IDAT块加入图片

图片的IDAT块是可以存在多个的,这导致了我们可以将隐写信息以IDAT块的形似加入图片。

可以使用pngcheck对图片进行检测 具体实例看这里

这里不再赘述

我自己出了一个题可以检验一下 附件 密码T0MR

三、LSB图片隐写

lsb介绍戳这里

在ctf中,最常用于检测lsb隐写的工具为stegsolve (这里有

提取rgb最低位脚本–来自这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from PIL import Image

im = Image.open("extracted.bmp")
pix = im.load()
width, height = im.size

extracted_bits = []
for y in range(height):#y,x代表的是图片的高以及宽度,进行一个循环提取
for x in range(width):
r, g, b = pix[(x,y)]
extracted_bits.append(r & 1)
extracted_bits.append(g & 1)
extracted_bits.append(b & 1)

extracted_byte_bits = [extracted_bits[i:i+8] for i in range(0, len(extracted_bits), 8)]
with open("extracted2.bmp", "wb") as out:
for byte_bits in extracted_byte_bits:
byte_str = ''.join(str(x) for x in byte_bits)
byte = chr(int(byte_str, 2))
out.write(byte)

四、基于DCT域的JPG图片隐写

关于JPG戳这里

常见关于JPG的隐写方法有 JSteg、JPHide、Outguess、F5等 常用Stegdetect来检测是哪种隐写方式

关于Stegdetect和JPHS戳这里 压缩原理及工具使用戳这里

1
2
3
//Stegdetect
如果检测结果显示该文件可能包含隐藏信息,那么Stegdetect会在检测结果后面使用1~3颗星来标识
隐藏信息存在的可能性大小,3颗星表示隐藏信息存在的可能性最大。

五、数字水印隐写

LSB顺序替换嵌入与提取实现

加强版