过几天有比赛了,总结一下自己遇到过的知识点,争取能把签到题做出来
除了题目描述和给的提示外,注意图片名
和图片里的内容
,很有可能是接下来要用到的隐写工具或者加密方法的提示
。
例如第四届蓝帽杯决赛
的一道misc:MISC隐写
给了一张图片,里面是一条蛇,这个提示的是后面会用到的一种解密方法;然后从图片中提取出一个pdf文件,文件名是no password.pdf
,也提示了需要用到工具,不需要输入密码。
拿到一个图片时,建议查看一下它的exif信息,可能会有意想不到的收获
出题人经常在图片的exif信息中藏flag或者提示信息,这里以bugku的misc题目有黑白棋的棋盘
为例
这里是直接右键查看属性,不过这样能获取的信息十分有限
;
ctfshow中八神出的misc入门
的misc18-21
考察的都是这个知识点,具体可以看我另一篇博客。
拿其中的misc20
为例,直接右键查看属性,翻看详细信息,得不到任何线索,推荐使用一个在线查看exif信息的网站,这里能得到的结果更详细,也可以使用exiftool
很多时候,所给的图片的宽高,甚至crc32校验值都是被修改过的,需要我们去爆破得到正确的值。
这里推荐使用010editor
,它的模板功能
非常好用,我是010editor+winhex配合使用的。
png图片修改宽高还是很容易的,这里是png.bt
模板,框中的值分别是宽高
和crc值
,这里修改之后保存即可
对于png,一般情况下,是把高度改大
,看下面有没有内容
运用jpg.bt
,可以很方便修改jpg的宽高
对于jpg,一般情况下也是把高度改大
,能看到图片下面的内容
整体和前两种差不多,借助gif.bt
,这里比较特殊的是,每一帧都有独立的宽高
,因为不知道flag藏在哪一帧,一般建议把所有帧的高度都改大
,然后用Stegsolve
打开,翻看每一帧图片。
借助bmp.bt
,整体和前面差不多,当宽度错误时,图片显示很乱
问题就是如何计算正确的宽度和高度,以ctfshow-misc入门的misc24
为例,
目前是900*150=135000
个像素大小,文件头占了53个字节,文件尾的位置在675053字节处(后面两个字节是windows的”补0”),又因为每个像素点由3个字节(十六进制码6位)表示,每个字节负责控制一种颜色,分别为蓝(Blue)、绿(Green)、红(Red),所以文件真实的像素大小为:(675053-53)/3=225000
这题中给出了正确的宽度900,所以正确的高度就是225000/900=250
png图片,已知正确的IHDR块的CRC值
时,爆破宽度和高度
import zlib
import struct
# 同时爆破宽度和高度
filename = "misc32.png"
with open(filename, 'rb') as f:
all_b = f.read()
data = bytearray(all_b[12:29])
n = 4095
for w in range(n):
width = bytearray(struct.pack('>i', w))
for h in range(n):
height = bytearray(struct.pack('>i', h))
for x in range(4):
data[x+4] = width[x]
data[x+8] = height[x]
crc32result = zlib.crc32(data)
#替换成图片的crc
if crc32result == 0xE14A4C0B:
print("宽为:", end = '')
print(width, end = ' ')
print(int.from_bytes(width, byteorder='big'))
print("高为:", end = '')
print(height, end = ' ')
print(int.from_bytes(height, byteorder='big'))
png图片,如果IHDR块的CRC的值被修改过
,那就直接爆破,运行后会生成很多个图片,看一下哪个是正常的就行
这里是已知高度的情况下爆破宽度
,根据自己需要修改脚本
import zlib
import struct
filename = "misc34.png"
with open(filename, 'rb') as f:
all_b = f.read()
#w = all_b[16:20]
#h = all_b[20:24]
for i in range(901,1200): #界定宽度的范围
name = str(i) + ".png"
f1 = open(name,"wb")
im = all_b[:16]+struct.pack('>i',i)+all_b[20:]
f1.write(im)
f1.close()
jpg图片,已知高度,爆破宽度
如果跑出来的图片看不到想要的东西,可能是狗出题人把原本的高度调小了
,可以试一下把高度改大,再跑一遍试试
import zlib
import struct
filename = "misc35.jpg"
with open(filename, 'rb') as f:
all_b = f.read()
#w = all_b[159:161]
#h = all_b[157:159]
for i in range(901,1200): #界定宽度范围
name = str(i) + ".jpg"
f1 = open(name,"wb")
im = all_b[:159]+struct.pack('>h',i)+all_b[161:]
f1.write(im)
f1.close()
gif图片,已知高度爆破宽度
如果跑出来没东西,试试把高度改高
import zlib
import struct
filename = "misc36.gif"
with open(filename, 'rb') as f:
all_b = f.read()
for i in range(920,951):
name = str(i) + ".gif"
f1 = open(name,"wb")
im = all_b[:38]+struct.pack('>h',i)[::-1]+all_b[40:]
f1.write(im)
f1.close()
使用010editor和winhex对文件进行分析
如果图片打开错误,先看看文件头和文件尾出错没,如果有错误进行修改
JPEG (jpg),
文件头:FFD8FF 文件尾:FF D9
PNG (png),
文件头:89504E47 文件尾:AE 42 60 82
GIF (gif),
文件头:47494638 文件尾:00 3B
ZIP Archive (zip),
文件头:504B0304 文件尾:50 4B
TIFF (tif),
文件头:49492A00
Windows Bitmap (bmp),
文件头:424D
CAD (dwg),
文件头:41433130
Adobe Photoshop (psd),
文件头:38425053
Rich Text Format (rtf),
文件头:7B5C727466
XML (xml),
文件头:3C3F786D6C
HTML (html),
文件头:68746D6C3E
Email [thorough only] (eml),
文件头:44656C69766572792D646174653A
Outlook Express (dbx),
文件头:CFAD12FEC5FD746F
Outlook (pst),
文件头:2142444E
MS Word/Excel (xls.or.doc),
文件头:D0CF11E0
MS Access (mdb),
文件头:5374616E64617264204A
WordPerfect (wpd),
文件头:FF575043
Adobe Acrobat (pdf),
文件头:255044462D312E
Quicken (qdf),
文件头:AC9EBD8F
Windows Password (pwl),
文件头:E3828596
RAR Archive (rar),
文件头:52617221
Wave (wav), 文件头:57415645
AVI (avi), 文件头:41564920
Real Audio (ram), 文件头:2E7261FD
Real Media (rm), 文件头:2E524D46
MPEG (mpg), 文件头:000001BA
MPEG (mpg), 文件头:000001B3
Quicktime (mov), 文件头:6D6F6F76
Windows Media (asf), 文件头:3026B2758E66CF11
MIDI (mid), 文件头:4D546864
推荐使用winhex
或者notepad
,打开后直接拉到底部,看有没有什么额外信息
然后直接ctrl+f搜索key
、flag
、password
等字样,没准就拿到flag了
也有可能不是直接给到的,需要进行进一步的处理
其实更常见的是,在尾部隐写另一个文件的数据,一般是一个压缩包,可以手动把数据提取出来,或者使用foremost
或binwalk
提取。
stegsolve是非常常用的工具,功能十分强大
用stegsolve打开图片后,建议先把所有的图层都看一遍
,可能会有flag或者提示信息
如果是gif图片,可以使用frame browser
查看所有帧
如果是两张很相似的图片,但是其中一张有很难以辨认的文字痕迹,可以用image combiner
功能
在翻看图层的时候,可能会发现lsb隐写的痕迹(不太好描述,做习惯了就知道)
使用stegsolve的data extract
,选上对应的通道(比较常见的是如下配置),就可以得到隐藏的信息
项目地址:https://github.com/cyberinc/cloacked-pixel
这个项目是基于python2
的,如果环境中同时有Py2和Py3需要注意下
加密
python2 lsb.py hide <img_file> <payload_file> <password>
解密
python2 lsb.py extract <stego_file> <out_file> <password>
打开图片后点decode进行解密
可以注意到有bmp和jpg两种,如果有密码,勾选encrypteddata
输入密码再解密即可
也是很常用的工具,如果解题需要用到这个工具,出题人一般会给提示,比如我们的秘密是绿色的
,其中的秘密英文是Secret,就是暗示用这个工具。
也是windows下的软件,界面如下
使用也很简单,在右侧(UNHIDE)打开文件,输入密码,再点击UNHIDE就行
我用的是windows版本的,界面如下
使用起来也很简单,点击open jpeg
打开图片,然后点击seek
,如果有密码就输入密码,没有就直接回车
不算太常见的一个软件,123分别是
解密的图片的位置
如果有密码就勾选,然后输入密码,没有就直接跳过
解出文件放在什么位置
kali中安装,直接git clone https://github.com/matthewgao/F5-steganography
具体使用:
进入f5-steganography文件夹后,打开终端
# 解密
java Extract filename.jpg -p 密码
运行后会在文件夹里生成一个output.txt,打开即可
# 加密
java Embed 原图.jpg 生成图.jpg -e 隐藏的文件.txt -p 密码
kali中安装:
先下载
git clone https://github.com/crorvick/outguess
然后进入outguess文件夹,打开终端输入./configure && make && make install
成功之后即可
使用:
进入文件夹后打开终端
加密
outguess -k 密码 -d hidden.txt 1.jpg 2.jpg
#hidden.txt是要隐写的内容,运行后1.jpg会覆盖2.jpg
解密
outguess -k 密码 -r 2.jpg out.txt
outguess -r 2.jpg out.txt #不用密码的情况
kali中的安装:sudo apt-get install steghide
使用:
加密
steghide embed -cf out.jpg -ef flag.txt [-p 密码]
把flag.txt隐写到out.jpg中,如果要添加密码,尾部接上 -p 密码
解密
steghide info out.jpg #查看图片中嵌入的文件信息
#提取隐藏内容
steghide extract -sf out.jpg -p 密码
steghide extract -sf out.jpg
steghide本身不支持爆破密码,可以借助https://github.com/Va5c0/Steghide-Brute-Force-Tool
使用前还要安装一个库:pip install progressbar2
使用方法:
python steg_brute.py -b -d [字典] -f [jpg_file]
项目地址:https://github.com/chishaxie/BlindWaterMark
具体安装过程自行百度
使用:
加密
python bwm.py encode 1.png water.png 2.png #PY2
python bwmforpy3.py encode 1.png water.png 2.png #PY3
解密
python bwm.py decode 1.png 2.png out.png #PY2
python bwmforpy3.py decode 1.png 2.png out.png #PY3
py2和py3的算法不一样,得到的out.png也不一样,建议都试一下
脚本:
# coding=utf-8
import cv2
import numpy as np
import random
import os
from argparse import ArgumentParser
ALPHA = 5
def build_parser():
parser = ArgumentParser()
parser.add_argument('--original', dest='ori', required=True)
parser.add_argument('--image', dest='img', required=True)
parser.add_argument('--result', dest='res', required=True)
parser.add_argument('--alpha', dest='alpha', default=ALPHA)
return parser
def main():
parser = build_parser()
options = parser.parse_args()
ori = options.ori
img = options.img
res = options.res
alpha = options.alpha
if not os.path.isfile(ori):
parser.error("original image %s does not exist." % ori)
if not os.path.isfile(img):
parser.error("image %s does not exist." % img)
decode(ori, img, res, alpha)
def decode(ori_path, img_path, res_path, alpha):
ori = cv2.imread(ori_path)
img = cv2.imread(img_path)
ori_f = np.fft.fft2(ori)
img_f = np.fft.fft2(img)
height, width = ori.shape[0], ori.shape[1]
watermark = (ori_f - img_f) / alpha
watermark = np.real(watermark)
res = np.zeros(watermark.shape)
random.seed(height + width)
x = range(height / 2)
y = range(width)
random.shuffle(x)
random.shuffle(y)
for i in range(height / 2):
for j in range(width):
res[x[i]][y[j]] = watermark[i][j]
cv2.imwrite(res_path, res, [int(cv2.IMWRITE_JPEG_QUALITY), 100])
if __name__ == '__main__':
main()
使用命令:python BlindWaterMarkplus.py --original 1.png --image 2.png --result res.png
如果得到的res.png有问题,把1.png和2.png互换位置试一下
项目地址:https://github.com/ww23/BlindWaterMark/releases
使用命令:java -jar BlindWatermark.jar decode -c bingbing.jpg decode.jpg
kali安装:gem install zsteg
使用:
zsteg 1.png
zsteg 1.bmp
一般在windows系统下使用,在文件夹中打开cmd命令行
输入:PNGDebugger.exe filename.png
windows系统下的一个软件,是很好用的一个PNG图像浏览工具
用来增加或者删除png图片的IDAT块
很方便,之前做过八神的一个题,就是删除了一个png的图片中的部分IDAT块,保存得到一张不同的图片,其中就有flag,这里因为对png的结构了解的不是很透彻,原理说不清楚。
在使用这个软件打开图片之前,建议先用PNGDebugger
看一下图片中有多少IDAT块的crc32是出错的,因为在使用这个软件的时候,每一个错误都会有一个弹窗。
比如misc入门的misc44
就不建议用这个软件打开
先写这么多,想起来再补