CTF之misc杂项解题技巧总结(1)——隐写术

2023-12-23 09:11:46 浏览数 (2)

隐写术Steganography

(一)NTFS数据流隐写

(二)base64隐写

(三)图像隐写

(四)零宽字符隐写

(五)word隐写

(六)PYC隐写

(七)音频隐写

(八)文件合成与分离

(九)BMP/PDF隐写

【附】检测工具

(一)NTFS数据流隐写

NTFS是微软Windows NT内核的系列操作系统支持的、一个特别为网络和磁盘配额、文件加密等管理安全特性设计的磁盘格式。NTFS比FAT文件系统更稳定,更安全,功能也更为强大。

这个NTFS数据流文件,也叫Alternate data streams,简称ADS,是NTFS文件系统的一个特性之一,允许单独的数据流文件存在,同时也允许一个文件附着多个数据流,即除了主文件流之外还允许许多非主文件流寄生在主文件流之中,它使用资源派生的方式来维持与文件相关信息,并且这些寄生的数据流文件我们使用资源管理器是看不到的。

(二)base64隐写

可以看出一串base64的编码最多也只有4bit的隐写空间,所以实现隐写往往需要大量编码串。,隐写时把明文的每个 字符用8位二进制数表示,由此将整个明文串转为bit串,按顺序填入base64编码串的可隐写位中即可实现隐写。)

题目:

[GXYCTF2019]SXMgdGhpcyBiYXNlPw==

Base64码表:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 /=

Base64是一种用64个可打印字符来表示二进制数据的方法。

base64编码

1个字节对应8个比特,一个可打印字符对应6个比特,即一个单元,将目标字串变成二进制数据流,然后6个一单元划分对应成码表的索引,用base64码表中的字符替换。

码文c和明文m的关系为len(c)×6==len(m)×8len(c)×6==len(m)×8,即len(c)×3==len(m)×4len(c)×3==len(m)×4,那么必须码文字符串的长度必须为4的倍数,明文字符串的长度必须为3的倍数。

对于明文字符串长度不足3的倍数的情况用每一个二进制位用0 bit0 bit补足直到满足明文字符串长度为3的倍数。

不难看出,一个base64码文最多可以有2个‘=’,最少可以没有等号(此时明文长度刚好是3的倍数)。

base64解码

把码文末端的‘=’去除

在其二进制数据的末尾丢弃最小数目的二进制位使二进制位数为8的倍数,然后8位一组进行ASCII编码。

base64隐写原理

在base64解码中,去除等号之后将末尾一些二进制位丢弃使二进制位数为8的倍数,所以一些隐藏数据可以写在可以被丢弃的部分,这部分可以随意写成任意值而不用担心影响解码的结果,同时也说明了不同的base64码文可能生成相同的明文。

下面是提取脚本

importre

path ='flag.txt'#your path

b64char ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 /'

withopen(path,'r')asf:

cipher = [i.strip()foriinf.readlines()]

plaintext =''

foriincipher:

ifi[-2] =='=':# There are 4-bit hidden info while end with two '='

bin_message =bin(b64char.index(i[-3]))[2:].zfill(4)

plaintext = bin_message[-4:]

elifi[-1] =='=':# There are 2-bit hidden info while end with one '='

bin_message =bin(b64char.index(i[-2]))[2:].zfill(2)

plaintext = bin_message[-2:]

plaintext = re.findall('.{8}', plaintext)# 8bits/group

plaintext =''.join([chr(int(i,2))foriinplaintext])

print(plaintext)

下面是隐写脚本

#!/usr/bin/env python

importbase64

withopen('./gitanjali.txt','r')asf:

data = [i.strip()foriinf.readlines()]

base64Data = [base64.b64encode(i)foriindata]

b64char ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 /'

msg ='Gitanjali'# 隐写内容,注意隐写内容不应超过最大隐写bit数

msg_bit =''.join([bin(ord(i))[2:].zfill(8)foriinmsg])

offset =0

new_data = []

foriinbase64Data:

ifi[-2]=='=':# There are 4-bit hidden info while end with two '='

offset =int(msg_bit[:4],2)

i = i.replace(i[-3], b64char[b64char.index(i[-3]) offset])

msg_bit = msg_bit[4:]

elifi[-1]=='=':# There are 2-bit hidden info while end with one '='

offset =int(msg_bit[:2],2)

i = i.replace(i[-2], b64char[b64char.index(i[-2]) offset])

msg_bit = msg_bit[2:]

new_data.append(i "n")

withopen('./encodeFile.txt','w')asf:

f.writelines(new_data)

(三)图像隐写

有时候会出现许多文件的情况,此时想找出某一个关键的信息字段可以用下面的指令

exiftool *|grep flag#搜索当前文件夹下所有文件的exif信息中的flag字符

还有直接在图片属性的备注里给出flag,这种情况可以用010editor或者winhex等工具打开图片搜索关键字如flag、ctf等查看。

宽高修改

IHDR隐写(.png)

对.png格式的图片进行宽高的修改进而隐藏图片关键信息

原理:png图片的宽和高信息在png的IHDR数据块内,通过修改图片的宽和高数据使图片仅显示一部分,另一部分不显示

特征:010 Editor中打开后会出现CRC校验值错误的报错提示

破解:可以通过CRC值来暴破获取正确的宽值或者高值

importzlib

importstruct

filename =#图片路径

crc_str=#图片的CRC值

# 同时爆破宽度和高度

withopen(filename,'rb')asf:

all_b = f.read()

data =bytearray(all_b[12:29])

n =4095

forwinrange(n):

width =bytearray(struct.pack('>i', w))

forhinrange(n):

height =bytearray(struct.pack('>i', h))

forxinrange(4):

data[x 4] = width[x]

data[x 8] = height[x]

crc32result = zlib.crc32(data)

#替换成图片的crc

ifcrc32result == crc_str:

print("宽为:", end ='')

print(width, end =' ')

print(int.from_bytes(width, byteorder='big'))

print("高为:", end ='')

print(height, end =' ')

print(int.from_bytes(height, byteorder='big'))

.jpg宽高隐写

SOF0段的X_image和Y_image分别记录图片的宽和高,直接修改,不用担心校验错误。

.bmp宽高隐写
IDAT隐写(.png)

图像数据块 IDAT(image data chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。

储存图像像数数据

在数据流中可包含多个连续顺序的图像数据块

采用 LZ77 算法的派生算法进行压缩

可以用 zlib 解压缩

值得注意的是,IDAT 块只有当上一个块充满时,才会继续一个新的块。一旦出现不符合这个规律的情况(有一块IDAT还没填满但紧跟其后的是一个新的块),那么就是人为添加了数据块。

破解:010 editor直接提取出数据,然后扔进zlib解压脚本(如下)里解压获得原始数据。

#! /usr/bin/env python

importzlib

importbinascii

IDAT =".........".decode('hex')#填入dump出的IDAT数据

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

print(result.decode('hex'))

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

LSB隐写

LSB-Steganography工具实现的不加密隐写可以用Stegsolve查看,这种算法的特点就是LSB位前面很多0

[cloacked-pixel](https://github.com/livz/cloacked-pixel#:~:text=cloacked-pixel. Platform independent Python tool to implement LSB,Hide files within least significant bits of images.)工具实现的加密隐写(带密钥)可以用Stegsolve查看,这种算法的特点是开头有个数字,根据观察,这个数字应该是有用的数据的长度,然后才是很多个0,接着是相应长度的数据。

cloacked-pixel使用方法:

lsb.py hide   #隐写

lsb.py extract #提取

lsb.py analyse                       #分析检测

提取工具:

对于不加密的LSB隐写:Stegsolve中extract

对于带密码的LSB隐写:[cloacked-pixel](https://github.com/livz/cloacked-pixel#:~:text=cloacked-pixel. Platform independent Python tool to implement LSB,Hide files within least significant bits of images.)

outguess隐写(.jpeg)

题目:[WUSTCTF2020]alison_likes_jojo

使用outguess实现隐写加密与解密

加密:

outguess -k"my secret key"-d hidden.txt in.jpg out.jpg

加密之后,in.jpg会覆盖out.jpg,hidden.txt中的内容是要隐藏的东西

解密:

outguess -k"my secret key"-r out.jpg hidden.txt

解密之后,解密内容放在hidden.txt中

检测:使用stegdetect工具可以检测

F5隐写

检测:使用stegdetect工具可以检测

提取:F5-steganography

盲水印

盲水印是一种肉眼不可见的水印方式,可以保持图片美观的同时,保护资源版权。

提取:

ImageIN:GUI交互(建议只得到一张图的情况下使用)

BlindWaterMark:命令行python脚本(CTF题中可能会给两张一样的图,这个时候用此工具更好)

JPHide(.jpeg)

先解压压缩JPEG图像,得到DCT系数;然后对隐藏信息用户给定的密码进行Blowfish加密;再利用Blowfish算法生成伪随机序列,并据此找到需要改变的DCT系数,将其末位变为需要隐藏的信息的值,最后把DCT系数重新压回成JPEG图片。

提取:JPHS

JPHS内置JPHIDE和JPSEEK

JPHide程序主要是实现将信息文件加密隐藏到JPEG图像功能,

JPSeek程序主要实现从用JPHide程序加密隐藏得到的JPEG图像探测提取信息文件

SilentEye(.jpeg)

(四)零宽字符隐写

零宽字符是一种在浏览器中不打印的字符,大致相当于 display: none ,在许多文本应用中也不显示,比如邮箱、QQ、微信、文本编辑器等

html中有三种零宽字符 – 零宽空格、零宽连字、零宽不连字

零宽字符在浏览器中对应的转义字符

零宽空格    ---  

零宽不连字  ---

零宽连字    ---

零宽字符在Unicode中的编码为

u200B u200C u200D

(五)word隐写

word中隐藏字段:在Word中选中要隐藏的字段,右击选择字体选项,在效果一栏中有隐藏选项,选中后即可隐藏。默认情况下隐藏文字是不会被打印出来的。

破解:如果想知道是否有隐藏文本,可在文件选项中单击文件→选项→显示文件→选项→显示,在始终在屏幕上显示这些格式标记标签下选择隐藏文字复选框,即可查看,打印选项标签勾选打印隐藏文字即可打印。或者在保存文件后选择文件→检查→检查文件文件→检查→检查文件,查看是否有隐藏文字。

**白色背景下的白字无法被识别出有隐藏的文字 **。

破解:

全选改字体颜色为别的颜色

搜索字符串,例如flag等

word中隐藏图片:word中插入的图片分为嵌入式和非嵌入式,区别在嵌入式会跟着文本的位置产生移动,即有回车后,图片下移。但非嵌入的不会跟着文本走,即有回车后,图片保持原位置不动。

word改后缀名为zip然后解压

(六)PYC隐写

原理是在 python 的字节码文件中,利用冗余空间,将完整的 payload 代码分散隐藏到这些零零碎碎的空间中。

例如,从 Python 3.6开始,有一个较大的改变,就是不管 opcode 有没有参数,每一条指令的长度都两个字节,opcode 占一个字节,如果这个 opcode 是有参数的,那么另外一个字节就表示参数;如果这个 opcode 没有参数,那么另外一个字节就会被忽略掉,一般都为00。

Stegosaurus 是一款隐写工具,它允许我们在 Python 字节码文件 (pyc 或 pyo) 中嵌入任意 Payload。由于编码密度较低,因此我们嵌入 Payload 的过程既不会改变源代码的运行行为,也不会改变源文件的文件大小。Payload 代码会被分散嵌入到字节码之中,所以类似 strings 这样的代码工具无法查找到实际的 Payload。Python 的 dis 模块会返回源文件的字节码,然后我们就可以使用 Stegosaurus 来嵌入 Payload 了。

提示:Stegosaurus 仅支持 Python3.6 及其以下版本

快速入门:-p 要隐藏的文本,-r 显示最大隐藏字节,-x可以解密

(七)音频隐写

DeepSound隐写

DeepSound 是一种隐写术工具和音频转换器,可将秘密数据隐藏到音频文件中。该应用程序还使您能够直接从音频文件或音频 CD 曲目中提取秘密文件。DeepSound 可用作 wave、flac、wma、ape 和音频 CD 的版权标记软件。DeepSound 还支持使用 AES-256(高级加密标准)加密机密文件以提高数据保护。该应用程序还包含一个易于使用的音频转换器模块,可以将多种音频格式(FLAC、MP3、WMA、WAV、APE)编码为其他格式(FLAC、MP3、WAV、APE)。

DeepSound 2.0 Free Download (soft112.com)

MP3stego隐写

MP3stego是命令行工具(也有图形界面的)

decode -X -P

SilentEye隐写

https://sourceforge.net/projects/silenteye/

(八)文件合成与分离

binwalk:可快速分辨文件是否由多个文件合并而成,并将文件进行分离。如果分离成功会在目标文件的目录。

分析文件:binwalk filename

分离文件:binwalk -e filename

formost命令:formost filename -o 输出的目录名

dd:当文件自动分离出错或者因为其他原因无法自动分离时使用

(九)BMP/PDF隐写

提取工具:wbStego Steganography Tool (bailer.at)

针对.bmp/.pdf隐写,得到的_is文件用notepad 打开

【附】检测工具

stegdetect

stegdetect 用来检测jpg类型的图片是否隐藏着其他文件或内容。它可以检测到通过JSteg、JPHide、OutGuess、Invisible Secrets、F5、appendX和Camouflage等这些隐写工具隐藏的信息。

安装:

推荐在linux环境下,下载stegdetect 源码包之后进入其目录,执行下面指令

linux32 ./configure

linux32 make

使用stegdetect时会有一些参数,下面简单罗列一下:

q ——仅显示可能包含隐藏内容的图像

n ——启用检查JPEG文件头功能,以降低误报率。如果启用,所有带有批注区域的文件将被视为没有被嵌入信息。如果JPEG文件的JFIF标识符中的版本号不是1.1,则禁用OutGuess检测。

s ——修改检测算法的敏感度,该值的默认值为1。检测结果的匹配度与检测算法的敏感度成正比,算法敏感度的值越大,检测出的可疑文件包含敏感信息的可能性越大。

d ——打印带行号的调试信息。

t ——设置要检测哪些隐写工具(默认检测jopi),可设置的选项如下:

j ——检测图像中的信息是否是用jsteg嵌入的。

o ——检测图像中的信息是否是用outguess嵌入的。

p ——检测图像中的信息是否是用jphide嵌入的。

i ——检测图像中的信息是否是用invisible secrets嵌入的。

常用指令

stegdetect.exe -tjopi -s 10.0 hide.jpg

0 人点赞