從0開始學雜項 第三期:隱寫分析(2) PNG圖片隱寫

天翔RT發表於2023-04-01

Misc 學習(三) - 隱寫分析:PNG 圖片隱寫

在上一期,我主要講了講自己對於隱寫分析資訊蒐集直接附加的一些淺薄理解,這一期我們繼續對隱寫分析的學習,開始講隱寫分析最喜歡考的一項——圖片隱寫,我們首先學習的是圖片隱寫中最基礎的 PNG 圖片隱寫。(此文並非教學,我只是在這裡記下我的筆記、我的心得、我的體會,請辯證看待、理性思考,不要全都當成真理)

圖片隱寫的方式有很多種。廣義上,只要透過某種方式將資訊隱藏到圖片中而難以透過普通方式發現,就可以稱為圖片隱寫。由於我太菜,本系列只對一些常見的圖片隱寫方式進行簡單介紹,其它進階技巧請大家自行嘗試。

一. PNG 檔案結構

一個 PNG 檔案格式為:

檔案頭(89 50 4E 47 0D 0A 1A 0A) + 資料塊 + 資料塊 + 資料塊…… + 檔案尾(00 00 00 00 49 45 4E 44 AE 42 60 82)

PNG 定義了兩種型別的資料塊,一種是稱為關鍵資料塊,這是標準的資料塊,另一種叫做輔助資料塊,這是可選的資料塊。關鍵資料塊定義了4個標準資料塊,每個 PNG 檔案都必須包含它們。

每個資料塊都有著統一的結構,由 4 個部分組成:

其中CRC域中的值是對資料塊型別碼和資料進行計算得到的,CRC具體演算法定義在ISO 3309和ITU-T V.42中,其值按CRC碼生成多項式進行計算
我們可以用 pngcheck 去檢視PNG檔案資料塊資訊。 PS:結構什麼的看看就行,最好能掌握,掌握不了也沒關係,我們可以做中學

IHDR(檔案頭資料塊)

第一塊是檔案頭資料塊IHDR),它由第11——32位元組組成(從0開始),包含有 PNG 檔案中儲存的影像資料的基本資訊,資料從第 16位元組開始,有13個位元組,其前8位元組分別用4個位元組規定了圖片的寬和高(十六進位制,以畫素為單位)。

IDAT(影像資料塊)

它儲存實際的資料,在資料流中可包含多個連續順序影像資料塊。它採用 LZ77 演算法的派生演算法進行壓縮,可以用 zlib 解壓縮。

二. IHDR 篡改圖片寬高

IHDR 的前8位元組規定了圖片的寬和高,我們可以用十六進位檔案編輯器更改它們以使得這張圖片顯示不完整,從而達到隱藏資訊的目的。此時它的圖片資料並沒有變,在Windows圖片檢視器中超過規定的圖片寬高的部分只是不顯示了。

細心的同學會發現在 Kali Linux 中是打不開這張圖片的,會提示 IHDR CRC error,這是因為在每個資料塊的最後4位元組都有CRC(迴圈冗餘檢測)用來檢測是否有錯誤和被篡改。聰明的同學自然就想到是不是可以用CRC反推圖片原來的寬和高,答案是肯定的,我們可以利用 python 指令碼反推圖片原寬高,然後用十六進位制編輯器開啟圖片修改圖片寬高得到原圖片。

#使用 python [指令碼檔名] [圖片檔名]
import zlib
import struct
import sys

filename = sys.argv[1]
with open(filename, 'rb') as f:
    all_b = f.read()
    crc32key = int(all_b[29:33].hex(),16)
    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)
            if crc32result == crc32key:
                print("寬為:",end="")
                print(width)
                print("高為:",end="")
                print(height)
                exit(0)

三. LSB 隱寫

PNG 檔案中的影像像數一般是由 RGB 三原色(紅綠藍)組成(有的圖片還包含A通道表示透明度),每一種顏色佔用8位,取值範圍為0x00至0xFF。LSB 隱寫就是修改 RGB 顏色分量的最低二進位制位(LSB),它修改了每個像數顏色的最低的1 bit,而人類的眼睛不會注意到這前後的變化,這樣每個畫素可以攜帶3位元的資訊。

如果是要尋找這種 LSB 隱藏痕跡的話,有一個工具 Stegsolve 是個神器,可以來輔助我們進行分析。透過下方的按鈕觀察每個通道的資訊,我們可以捕捉異常點,抓住 LSB 隱寫的蛛絲馬跡(這玩意兒很難說,一般就是一看就感覺奇怪的n行或n列顏色塊),進而利用 Stegsolve --> Analyse --> Data Extract 功能指定通道進行提取。

對於PNG和BMP檔案中的 LSB 等常見的隱寫方式,我們也可以使用 **zsteg **工具直接進行自動化的識別和提取。

四. IDAT 隱寫

IDAT 塊只有當上一個塊充滿(正常length最大65524)時,才會繼續一個新的塊。程式讀取影像的時候也會在第一個未滿的塊停止(查了下W3C標準,其實是PNG圖片在壓縮的時候會在最後一個塊的標記位標明這是最後一個資料塊)。所以如果某一塊沒有滿但後面卻還有 IDAT 塊則說明後面的塊是“假”的。

我們可以用 pngcheck -v [檔名] 去檢視PNG檔案資料塊資訊,然後利用 python zlib 解壓多餘IDAT塊的內容,此時注意剔除長度資料塊型別及末尾的CRC校驗值

import zlib
import binascii
IDAT = " ".decode('hex')	#雙引號中填IDAT資料
result = binascii.hexlify(zlib.decompress(IDAT))
print(result)

例題

找了半天沒找齊合適的例題,自己寫了一個,大家湊合做

例題連結:https://pan.baidu.com/s/15xDrjIPRX06ygRxhPZiA8Q 提取碼:6666

大家可以自己先嚐試一下,一共有4個flag(有兩個flag1,我打錯了),如果有困難再去看下面的題解。

題解

日常先開啟編輯器看一下,沒發現明顯問題。列舉一波,先試試 LSB 隱寫,開啟 Stegsolve,檢視不同軌道,發現在Red/Green/Blue plane 0的上方均有明顯隱寫痕跡(那一條奇怪的黑白碼)。

開啟 Stegsolve --> Analyse --> Data Extract ,選中那三個有痕跡的軌道,先點 Preview,確實有PNG檔案藏在裡面,點選 Sava Bin 儲存檔案為 1.png。( Stegsolve 具體怎麼用可能有緣寫~,現在就這樣用也差不多)

開啟 1.png,是個二維碼,用 QR Reserch 掃描得到 Flag1。

還剩下3個 flag,把圖片扔到 Kali Linux 裡,發現圖片無法檢視,說明 IHDR 被篡改,用上面的指令碼爆破 IHDR 得到寬高。

用 Winhex 開啟,找到 IHDR 中的寬高,更改一下(上面的“\x00”代表一個位元組,第四個是符號是因為他剛好屬於可列印位元組,把它打到右邊就行),儲存,確定更新。

開啟圖片,看到 flag1(其實是 flag3 ,打錯了)。

還有兩個 flag,我們把更改過的圖片扔到 Kali Linux 裡,驚奇地發現(真的很驚奇,以前沒見過沒這種情況)還是沒有預覽,但是在圖片檢視器裡可以正常顯示,在火狐瀏覽器中無法顯示卻不報錯,用 binwalk 分析一下,有個 zlib 檔案,只能說很正常,沒啥問題,再用 pngcheck 檢查一下,發現異常,第二個 IDAT 塊只有9895的長度,在沒有滿的情況一般來說是不會出現下一個塊的,說明最後一個塊是“假塊”(那個 CRC ERROR 請忽略,只是我出題時懶得算CRC而已,真正做題是不會給你留這個 bug 的)。

我們重新用 Winhex 開啟圖片,搜尋“IDAT”找到最後一個 IDAT 塊,把裡面的資料(只要資料,不要長度位、“IDAT”和那4位 CRC )複製到新檔案裡(CRC 是我瞎寫的,所以上面會報錯),儲存成1.txt(沒錯,為了偷懶我壓根沒壓縮成 zlib,你用 binwalk 是分離不出來的)。

得到一串奇葩文字,搜尋得知這是與佛論禪加密

開啟線上解密工具,解密得到 flag4。

最後還剩一個 flag,還記得我們掃出 flag1 的那個二維碼嗎?我們用 binwalk -e 掃描提取,發現能檢測到 zip 尾,但是提取不出來。。。改用 foremost 提取,得到一個 zip 檔案,開啟看到裡面有一個名字亂碼的文字檔案(無語),開啟又是一堆迷惑程式碼。

這回是符號所以不太好搜尋,只能靠經驗得知這是 Brainfuck 程式碼,利用線上解密工具“Brainfuck to text”解密得到 flag2。

順便說一下為什麼“我們剛才用 binwalk -e 掃描提取,發現能檢測到 zip 尾,但是卻提取不出來”,用 WinHex 開啟,發現在PNG檔案尾與ZIP檔案尾之間有“髒東西”,導致 binwalk 找不到檔案頭提取失敗。(說實話,這個地方還能再出個 flag,我上一期說的兩個同型別檔案 夾在一塊也是這種情況,如果你們遇到類似的情況也要注意看一下頭尾之間有沒有藏資訊)

補充題:[BUUCTF] Flag (不是很明顯,需要仔細看)


本期就先說到這裡,主要講了講隱寫分析中的 PNG 圖片隱寫,寫的不太好的地方還請包涵並提出您寶貴的建議,我們下期再見。(順便說一下,我發現在Winhex 裡,“貼上”是插入,“寫入”是覆蓋後面的)

參考資料

[1] CTF WIKI:https://ctf-wiki.org/misc/introduction/

[2] GAMERES:https://dev.gameres.com/Program/Visual/Other/PNGFormat.htm

[3] W3C 規範:https://www.w3.org/TR/2003/REC-PNG-20031110/

以上內容僅供參考,水平不高,大佬見笑。


作者:CHTXRT

出處:https://www.cnblogs.com/chtxrt/

本文使用「CC BY-ND 4.0」創作共享協議,轉載請在文章明顯位置註明作者及出處。

相關文章