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) 下載附件

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章