LSB与NTFS隐写

部分内容转载自:

https://segmentfault.com/a/1190000016223897?utm_source=tag-newest

https://www.cnblogs.com/Chesky/p/ALTERNATE_DATA_STREAMS.html

LSB隐写

PNG图片中的图像像数一般是由RGB三原色(红绿蓝)组成,每一种颜色占用8位,取值范围为0x00~0xFF,即有256种颜色,一共包含了256的3次方的颜色,即16777216种颜色。而人类的眼睛可以区分约1000万种不同的颜色,这就意味着人类的眼睛无法区分余下的颜色大约有6777216种。

LSB,Least Significant Bit,是最低有效位的意思;MSB,Most Significant Bit,即最高有效位

LSB隐写就是修改RGB颜色分量的最低二进制位,也就是最低有效位(LSB)。而人类的眼睛不会注意到这前后的变化,每个像数可以携带3比特的信息。

上图我们可以看到,十进制的235表示的是绿色,我们修改了在二进制中的最低位,但是颜色看起来依旧没有变化。我们就可以修改最低位中的信息,实现信息的隐写。我修改最低有效位的信息的算法就叫做lsb加密算法,提取最低有效位信息的算法叫做lsb解密算法。

PNG图片和BMP图片都是没有经过压缩的图片格式,可以在这两种文件格式上进行LSB隐写。而JPG图片是有损压缩的图片格式,如果我们修改了JPG文件的像数信息,那么图片就会损坏

相关工具

windows下:stegsolve

其中,Bit Plane Order代表颜色(三原色)的排序方式

linux下:zsteg

https://github.com/zed-0xff/zsteg

只需使用命令gem install zsteg即可安装使用

查看隐写的信息:

zsteg 图片名称

例题

2019 oppo ogeek ctf中的一道LSB隐写题目:

将提取出来的字符串base64-ascii85解码后即可得到flag

NTFS隐写

在NTFS文件系统中存在着NTFS交换数据流(Alternate Data Streams,简称ADS),这是NTFS磁盘格式的特性之一。每一个文件,都有着主文件流和非主文件流,主文件流能够直接看到;而非主文件流寄宿于主文件流中,无法直接读取,这个非主文件流就是NTFS交换数据流。

ADS的作用在于,它允许一个文件携带着附加的信息。例如,IE浏览器下载文件时,会向文件添加一个数据流,标记该文件来源于外部,即带有风险,那么,在用户打开文件时,就会弹出文件警告提示。再如,在网址收藏中,也会附加一个favicon数据流以存放网站图标。

ADS也被用于一些恶意文件隐藏自身,作为后门。

如果文件原本是在压缩包内的,这时使用除WinRAR以外的软件进行提取会造成数据流丢失。所以务必使用WinRar进行文件解压

相关工具

windows下:NtfsStreamsEditor2

例题

bugku 猫片

发现隐藏的不是普通的数据,查看详细数据信息:

发现有个png图片格式的数据,这里使用windows下的stegsolve比较容易提取:

点击save bin保存后,用010editor打开,将前面多余的两个字节删除,因为png文件头标志是89 50 4e 47

之后打开是半张二维码,计算正确高度:

1
2
3
4
5
6
7
8
9
10
11
import os
import binascii
import struct
crcbp = open("999.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) & 0xffffffff
if crc32 == 0x08ec7edb: #当前的CRC值
print i,j
print "hex",hex(i),hex(j) #输出宽度和高度

更改png高度:

打开后是张反着色的二维码:

在windows下用图片查看器打开后,可以用Ctrl+Shift+i将图片反着色;不过无论是不是反着色微信都能扫出来~

扫描得到百度网盘链接,将rar文件下载下来解压,得到一个txt文件,内容提示flag不在这里:

之后进行NTFS提取(注意解压rar文件时要用WinRAR):

将pyc文件导出,用在线反编译工具反编译(或uncompyle6),得到python源码:

解密即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ciphertext = [
'96', '65', '93', '123', '91', '97', '22', '93', '70', '102', '94', '132', '46', '112', '64', '97', '88', '80', '82', '137', '90', '109', '99', '112']

ciphertext = ciphertext[::-1]

#print(len(ciphertext)) # 24

for i in range(24):
s = int(ciphertext[i])
if i % 2 == 0:
s = s - 10
else:
s = s + 10
flag = chr(i ^ s)
print(flag, end='')