MISC总结——隐写术(二)

转载自:https://www.cnblogs.com/lxz-1263030049/p/9388602.html

这一篇是继上一篇之后的另一篇关于隐写术在ctf比赛中常见的套路问题:

上一篇详情请见:https://blog.csdn.net/xuchen16/article/details/82969608

本文参考自:先知社区:https://xz.aliyun.com/t/1836

隐写术介绍:

隐写术是关于信息隐藏,即不让计划的接收者之外的任何人知道信息的传递事件(而不只是信息的内容)的一门技巧与科学。

英文写作Steganography,而这篇内容将带大家了解一下CTF赛场上常见的图片隐写方式,以及解决方法。有必要强调的是,隐写术与密码编码是完全不同的概念。

 

第一部分:基于文件结构的图片隐写

 

背景知识·:

首先这里需要明确一下我这里所说的文件结构是什么意思。文件结构特指的是图片文件的文件结构。

我们这里主要讲的是PNG图片的文件结构。

PNG,图像文件存储格式,其设计目的是试图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。

是一种位图文件(bitmap file)存储格式,读作“ping”。PNG用来存储灰度图像时,灰度图像的深度可多到16位,存储彩色图像时

,彩色图像的深度可多到48位,并且还可存储多到16位的α通道数据。

对于一个正常的PNG图片来讲,其文件头总是由固定的字节来表示的,以16进制表示即位 89 50 4E 47 0D 0A 1A 0A,这一部分称作文件头。
标准的PNG文件结构应包括:

    • PNG文件标志
    • PNG数据块
      PNG图片是有两种数据块的,一个是叫关键数据块,另一种是辅助数据块。正常的关键数据块,定义了4种标准数据块,个PNG文件都必须包含它们。
      它们分别是长度,数据块类型码,数据块数据,循环冗余检测即CRC。
      我们这里重点先了解一下,png图片文件头数据块以及png图片IDAT块,这次的隐写也是以这两个地方位基础的。
      png图片文件头数据块
      即IHDR,这是PNG图片的第一个数据块,一张PNG图片仅有一个IHDR数据块,它包含了哪些信息呢?IHDR中,包括了图片的宽,高,图像深度,颜色类型,压缩方法等等。

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

 

高度被修改引起的隐写:

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

复制代码

- 在实验中找到隐写术目录,打开图片隐写,打开图片隐写第二部分文件夹
- 在该文件夹找到 hight.png,
- 双击打开图片,我们先确认一下图片内容并没有什么异常
- 正如前文所说,我们这个实验部分讲的是图片高度值被修改引起的的隐写方式,所以我们010Editor
- 在010Editor运行PNG模板,这样方便于我们修改PNG图片的高度值
- 找到PNG图片高度值对应的地方,然后修改为一个较大的值,并重新计算,修改CRC校验值,并保存文件
- 打开保存后的图片,发现底部看到了之前被隐写的信息

复制代码

用010Editor打开图片,运行PNG模板
10 editor呢?因为这个16进制编辑器,有模版功能,当我们运行模版后,可以轻易的找到图片的各个数据块的位置以及内容。

10 editor这个16进制编辑器,有模版功能,当我们运行模版后,可以轻易的找到图片的各个数据块的位置以及内容。
找到PNG图片高度值所对应的位置,并修改为一个较大的值

我们找到IHDR数据块,并翻到struct IHDR Ihdr位置,修改height的值到一个较大的值,如从700修改到800。
使用CRC Calculator重新计算CRC校验值


输入参数,然后点击Calculator计算,得到CRC值
为什么要重新计算CRC校验值呢?防止图片被我们修改后,自身的CRC校验报错,导致图片不能正常打开。

修改相应的CRC校验值,为我们重新计算后数值

各位小伙伴可以思考一下: JPG图片是否也有这样的隐写形式呢?

如果感兴趣可以:了解JPG以及GIF等图片文件的格式。

 

第二部分:隐写信息以IDAT块加入图片

在背景知识中,我们提到了一个重要的概念就是图片的IDAT块是可以存在多个的,这导致了我们可以将隐写西信息以IDAT块的形似加入图片

复制代码

- 在实验机找到隐写术目录,打开图片隐写,打开图片隐写第二部分文件夹
- 在该文件夹找到 hidden.png,
- 双击打开图片,我们先确认一下图片内容并没有什么异常
- 使用pngcheck先对图片检测
- 在pngcheck的检测下,我们会发现异常信息,我们对异常的块进行提取
- 编写脚本,提取异常信息(关于脚本,你可以上网搜索,也可以自己写)

复制代码

 

我们使用命令:

pngcheck -v hidden.png

对图片的文件结构进行检测。

发现异常,并判断异常的原因
我们会发现,图片的的数据块形式是如下的
Type: IHDR
Size: 13
CRC : 5412913F

Pos : 33
Type: IDAT
Size: 10980
CRC : 98F96EEB

Pos : 11025
Type: IEND
Size: 0
CRC : AE426082

我们会惊讶的发现pos为11025的size居然为0,这是一块有问题的地方,我们可以怀疑,这一块是隐写的信息。

自己编写脚本代码(也可以去网上搜索):

复制代码

#!/usr/bin/python

from struct import unpack
from binascii import hexlify, unhexlify
import sys, zlib

# Returns [Position, Chunk Size, Chunk Type, Chunk Data, Chunk CRC]
def getChunk(buf, pos):
    a = []
    a.append(pos)
    size = unpack('!I', buf[pos:pos+4])[0]
    # Chunk Size
    a.append(buf[pos:pos+4])
    # Chunk Type
    a.append(buf[pos+4:pos+8])
    # Chunk Data
    a.append(buf[pos+8:pos+8+size])
    # Chunk CRC
    a.append(buf[pos+8+size:pos+12+size])
    return a

def printChunk(buf, pos):
    print 'Pos : '+str(pos)+''
    print 'Type: ' + str(buf[pos+4:pos+8])
    size = unpack('!I', buf[pos:pos+4])[0]
    print 'Size: ' + str(size)
    #print 'Cont: ' + str(hexlify(buf[pos+8:pos+8+size]))
    print 'CRC : ' + str(hexlify(buf[pos+size+8:pos+size+12]).upper())
    print

if len(sys.argv)!=2:
    print 'Usage: ./this Stegano_PNG'
    sys.exit(2)

buf = open(sys.argv[1]).read()
pos=0

print "PNG Signature: " + str(unpack('cccccccc', buf[pos:pos+8]))
pos+=8

chunks = []
for i in range(3):
    chunks.append(getChunk(buf, pos))
    printChunk(buf, pos)
    pos+=unpack('!I',chunks[i][1])[0]+12


decompressed = zlib.decompress(chunks[1][3])
# Decompressed data length = height x (width * 3 + 1)
print "Data length in PNG file : ", len(chunks[1][3])
print "Decompressed data length: ", len(decompressed)

height = unpack('!I',(chunks[0][3][4:8]))[0]
width = unpack('!I',(chunks[0][3][:4]))[0]
blocksize = width * 3 + 1
filterbits = ''
for i in range(0,len(decompressed),blocksize):
    bit = unpack('2401c', decompressed[i:i+blocksize])[0]
    if bit == '\x00': filterbits+='0'
    elif bit == '\x01': filterbits+='1'
    else:
        print 'Bit is not 0 or 1... Default is 0 - MAGIC!'
        sys.exit(3)

s = filterbits
endianess_filterbits = [filterbits[i:i+8][::-1] for i in xrange(0, len(filterbits), 8)]

flag = ''
for x in endianess_filterbits:
    if x=='00000000': break
    flag += unhexlify('%x' % int('0b'+str(x), 2))

print 'Flag: ' + flag

复制代码

最后得到答案:flag DrgnS{WhenYouGazeIntoThePNGThePNGAlsoGazezIntoYou}

 

 

题目.zip (0.414 MB) 下载附件

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值