1. 程式人生 > >隱寫術總結

隱寫術總結

blank 影響 toolbar lba umt trac pow combine 開發

0x00 前言

之前還沒有見到drops上有關於隱寫術的總結,我之前對於隱寫術比較有興趣,感覺隱寫術比較的好玩。所以就打算總結總結一些隱寫術方面的東西。寫的時候,可能會有錯誤的地方,請不吝賜教,謝謝。

本篇章中用到的隱寫術的圖片,都打包在了這裏:隱寫術圖片,想去自己嘗試一遍的話可以去下載。

最開始接觸到隱寫術,是看到一種叫做圖種的東西,當時不懂,只說要另存為zip,然後解壓出來就可以了,當時覺得特別神奇,就像發現了新大陸,然後就嘗試了一下,發現可以用另存為zip的方式,用7z或者是winzip等工具打開,然後就可以看到福利了。

技術分享

後來才懂得了,先制作一個1.zip,把想要隱藏的東西放進去,再需要一張jpg圖片2.jpg,然後就可以執行一個命令 copy /b 2.jpg+1.zip output.jpg。就可以得到一張圖種,這是利用了copy命令,將兩個文件已二進制方式連接起來,生成output.jpg的新文件。而在jpg中,是有結束符的,16進制是FF D9,利用winhex可以看到正常的jpg結尾都是FF D9的,圖片查看器會忽視jpg結束符之後的內容,所以我們附加的zip,自然也就不會影響到圖像的正常顯示。

技術分享

這種類型的隱寫也是比較容易被發現的,如果發現是jpg圖片的話,觀察文件結束符之後的內容,查看是否附加的內容,正常圖片都會是FF D9結尾的。還有一種方式來發現就是利用binwalk這個工具,在kali下自帶的一個命令行工具。

技術分享

利用binwalk可以自動化的分析圖片中附加的其他的文件,其原理就是檢索匹配文件頭,常用的一些文件頭都可以被發現,然後利用偏移可以配合winhex或者是dd分割出隱藏的部分。

0x01 修改數據

上面說到的隱藏方式,是利用了增加數據的方式,把數據直接增加在了jpg後面。還有另一類隱藏的方法,就是利用了修改數據的方式來隱藏自己傳遞的信息。

一種常見的方式是利用LSB來進行隱寫,LSB也就是最低有效位 (Least Significant Bit)。原理就是圖片中的像數一般是由三種顏色組成,即三原色,由這三種原色可以組成其他各種顏色,例如在PNG圖片的儲存中,每個顏色會有8bit,LSB隱寫就是修改了像數中的最低的1bit,在人眼看來是看不出來區別的,也把信息隱藏起來了。譬如我們想把’A’隱藏進來的話,如下圖,就可以把A轉成16進制的0x61再轉成二進制的01100001,再修改為紅色通道的最低位為這些二進制串。

技術分享

技術分享

如果是要尋找這種LSB隱藏痕跡的話,有一個工具是個神器,可以來輔助我們進行分析。Stegsolve這個軟件的下載地址是

http://www.caesum.com/handbook/Stegsolve.jar

打開之後,使用Stegsolve——Analyse——Frame Browser這個可以瀏覽三個顏色通道中的每一位,可以在紅色通道的最低位,發現一個二維碼,然後可以掃描得到結果。

技術分享

再解一下qrcode,用在線的就可以http://tool.chinaz.com/qrcode/,得到了flag{AppLeU0},如果是隱寫的使用了ascii的話,可以使用Stegsolve——Analyse——Data Extract來查看ascii碼。

在這個過程中,我們要註意到,隱寫的載體是PNG的格式,如果是像之前的jpg圖片的話就是不行的,原因是jpg圖片對像數進行了有損的壓縮,你修改的信息可能會被壓縮的過程破壞。而PNG圖片雖然也有壓縮,但卻是無損的壓縮,這樣子可以保持你修改的信息得到正確的表達,不至於丟失。BMP的圖片也是一樣的,是沒有經過壓縮的,可以發現BMP圖片是特別的大的,因為BMP把所有的像數都按原樣儲存,沒有壓縮的過程。

0x02 隱寫與加密

我們先要區分一個概念,隱寫術和加解密的區別。其實說起來很簡單,加解密的話,就是會出現一些神秘的,可疑的字符串或者是數據之類的。而隱寫術的話,就是信息明明就在你的面前,你卻對他視而不見。隱寫術在CTF中出現時,常常會和加解密結合起來一起出現,或者是一些編碼方式一起出現,以提高題目的難度。

用一個ctf的題目作為例子吧,iscc2014中有一個題目,給了一個名為 此為gif圖片.gif的文件,打開發現了報錯。有的時候,會需要我們去修復圖片,這對我們對於圖片的文件結構要有了解。找到gif的文件格式,然後對照這個破損的文件。Gif的圖片格式文檔可以查看這個鏈接,http://dev.gameres.com/Program/Visual/Other/GIFDoc.htm

技術分享

用winhex打開,我們會發現他和普通的GIF圖片不一樣,頭部缺少了東西,在對比一些文檔,會發現是少了GIF8。

技術分享

我們手動修復一下,增加GIF8。

技術分享

然後瀏覽圖片後會發現,有個PASSWORD一閃而過,gif和別的圖片最大的區別就是gif是動態圖,它是可以由多幀組成的可以順序播放的,有的題就是把播放的時間弄得特別慢,幾乎就不會動的,所以我們可以用工具一幀一幀的觀察圖片。Stegsolve就帶有這種功能。

Stegsolve——Analyse——Frame Brower就可以看到是有8幀的圖片,有點重疊不太好觀察,也可以用Namo_GIF_gr這個工具。得到了PASSWORD is Y2F0Y2hfdGhlX2R5bmFtaWNfZmxhZ19pc19xdW10ZV9zaW1wbGU=。很明顯,這個時候PASSWORD是經過的編碼的,我們可以看到字符範圍是0-9a-Z結尾還有=,所以判斷是base64編碼,解碼得到了catch_the_dynamic_flag_is_qumte_simple。這個就是和編碼方式結合,傳遞一些可疑的數據,隱寫術常常會與加解密或編碼結合在一起,對一些常見的編碼和加密方法也要了解,得到密文的字符範圍和長度能發現這是什麽加密或者是編碼。

0x03 載體

數據在隱藏的時候,我們常常是需要先分析是數據隱藏在哪裏,也就是他在利用是什麽做載體,之後才可以進一步的分析是加密或編碼的。這也就是說我們要對一個圖片的格式要有了解,才能知道哪些地方是可疑的,哪些是可以隱藏起信息的,會有冗余的成分在。舉個例子吧,比如給了一個jpg的圖片。除了我們之前說到的隱藏在結束符之後的信息,jpg圖片還可以把信息隱藏的exif的部分。exif的信息是jpg的頭部插入了數碼照片的信息,比如是用什麽相機拍攝的。這些信息我們也是可以控制的,用查看屬性的方式可以修改一部分的信息,還可以用exif編輯器來進行編輯。Power_exif這個可以用來編輯。

技術分享

可以看到flag{AppLeU0},就是需要了解隱藏信息的地方,隱寫術有的時候難,就是難在了一張圖片有太多的地方可以隱藏信息了,有的時候根本連隱藏的載體都找不到,在你的眼裏他就是一張正常的圖片。

0x04 編程輔助

有一些情況下,我們也是沒有現成的工具來完成的,可以自己寫一些簡單的程序來輔助我們進行分析,或者是加解密。比如sctf的misc400的題目,就需要用到一些簡單的編程。題目給出了一個png圖片,需要我們找到有SCTF{}標誌的flag。

這個題需要我們對於png圖片的格式有一些了解,先用stegsolve查看一下,其他的LSB之類的並沒有發現什麽問題,然後看了一下結構發現,有一些異常的IDAT塊。IDAT是png圖片中儲存圖像像數數據的塊。Png圖片格式的擴展閱讀可以看看這篇

http://www.cnblogs.com/fengyv/archive/2006/04/30/2423964.html

技術分享

可以用pngcheck來輔助我們觀察,可以看得更加清晰。pngcheck.exe -v sctf.png

技術分享

可以看到,正常的塊的length是在65524的時候就滿了,而倒數第二個IDAT塊長度是45027,最後一個長度是138,很明顯最後一個IDAT塊是有問題的,因為他本來應該並入到倒數第二個未滿的塊裏。

技術分享

我們用winhex把這一部分異常的IDAT塊給扣出來。然後就是要研究研究這個塊是什麽情況,發現了載體之後就是要想辦法找出他的規律。觀察那一部分的數據,可以看到是16進制的78 9C開頭的,百度一下分析是zlib壓縮的標誌。在png的百度百科裏也可以查到PNG的IDAT是使用從LZ77派生的無損數據壓縮算法,可以用zlib解壓。那麽就嘗試用zlib來解一下這段數據。Zlib的擴展閱讀http://zlib.net/

我們使用python來編程,先把那段數據處理一下,保存成16進制的。

技術分享

得到16進制的以方便python處理,前面的4字節是長度 然後是標誌位IDAT 然後開始是數據,直到 D9 CF A5 A8是crc32校驗位。 所以實際的數據是:

789C5D91011280400802BF04FFFF5C75294B5537738A21A27D1E49CFD17DB3937A92E7E603880A6D485100901FB0410153350DE83112EA2D51C54CE2E585B15A2FC78E8872F51C6FC1881882F93D372DEF78E665B0C36C529622A0A45588138833A170A2071DDCD18219DB8C0D465D8B6989719645ED9C11C36AE3ABDAEFCFC0ACF023E77C17C7897667

然後用python來寫zlib解壓

技術分享
#! /usr/bin/env python
import zlib
import binascii
IDAT = "789C5D91011280400802BF04FFFF5C75294B5537738A21A27D1E49CFD17DB3937A92E7E603880A6D485100901FB0410153350DE83112EA2D51C54CE2E585B15A2FC78E8872F51C6FC1881882F93D372DEF78E665B0C36C529622A0A45588138833A170A2071DDCD18219DB8C0D465D8B6989719645ED9C11C36AE3ABDAEFCFC0ACF023E77C17C7897667".decode(hex)
#print IDAT
result = binascii.hexlify(zlib.decompress(IDAT))
print result
 
#print result.decode(‘hex‘)
技術分享

發現解出來了一些3031的字符串,30和31是hex的 0和1的編碼,再解一次hex得到一串625長度的01字符串。

技術分享
1111111000100001101111111100000101110010110100000110111010100000000010111011011101001000000001011101101110101110110100101110110000010101011011010000011111111010101010101111111000000001011101110000000011010011000001010011101101111010101001000011100000000000101000000001001001101000100111001111011100111100001110111110001100101000110011100001010100011010001111010110000010100010110000011011101100100001110011100100001011111110100000000110101001000111101111111011100001101011011100000100001100110001111010111010001101001111100001011101011000111010011100101110100100111011011000110000010110001101000110001111111011010110111011011
技術分享

得到的01 串的長度是625,除以8 除以7 都無法整除,也就是說沒法直接轉換成ascii碼。

技術分享

然後發現625 = 25*25,剛好是個正方形的形狀,那麽嘗試一下 把這些01 組成一個正方形 看看是什麽,可以用python的PIL編程可以很方便的畫圖,在kali自帶就可以有,win的環境需要安裝PIL的第三方庫。

技術分享
#!/usr/bin/env python
import Image
MAX = 25
pic = Image.new("RGB",(MAX, MAX))
str = "1111111000100001101111111100000101110010110100000110111010100000000010111011011101001000000001011101101110101110110100101110110000010101011011010000011111111010101010101111111000000001011101110000000011010011000001010011101101111010101001000011100000000000101000000001001001101000100111001111011100111100001110111110001100101000110011100001010100011010001111010110000010100010110000011011101100100001110011100100001011111110100000000110101001000111101111111011100001101011011100000100001100110001111010111010001101001111100001011101011000111010011100101110100100111011011000110000010110001101000110001111111011010110111011011"
i=0
for y in range (0,MAX):
    for x in range (0,MAX):
        if(str[i] == 1):
            pic.putpixel([x,y],(0, 0, 0))
        else:
            pic.putpixel([x,y],(255,255,255))
        i = i+1
 
pic.show()
pic.save("flag.png")
技術分享

發現是一個二維碼 可以編碼來畫出 0代表了是白色 而1代表了黑色,然後可能會需要旋轉來調整一下,才能掃描出來。處理一下得到了一個二維碼。然後掃描得到了flag。

技術分享

技術分享

SCTF{(121.518549,25.040854)},成功得到了flag。

在有的情況下,是沒法用現成的工具來處理的,所以就要我們用編程來設法解決。Python的PIL是個好東西。批量處理圖片的時候可能會需要它。

0x05 雙圖

還有一種情況是比較特殊的,有的時候會給出兩張圖片,或者是需要你去尋找原來的圖片來進行對比尋找隱藏的信息。這個一般是因為一張圖片給出來的隱藏信息太過於隱蔽,無法找不到具體的位置,具體的信息。這個時候就要用到一些對比的技巧來查找了。比如ISG2014的misc200就是用到的這種給出了兩張圖的。有的情況下,第二張圖是需要你自己去找到的。

我們來看isg2014-misc200的題,題目給了一張png圖片,png的圖片,就怕裏面插個什麽rar之類的,所以先用linux下的binwalk命令跑一跑。

技術分享

跑一跑,發現了有兩個PNG圖片,binwalk會給出偏移,確定了偏移是0x1D55DC之後,用winhex把圖片扣出來,保存成2.png。原來的圖final.png刪除後面那的一部分,保存成1.png。肉眼查看了一下,發現兩張圖片沒有太大的區別,我們用軟件來幫助我們區分他。

技術分享

用linux下的命令可以進行對比,生成一個有差異的圖片diff.png。compare 1.png 2.png diff.png 觀察一下發現了左下角有異常,png圖片像數保存是從左到右,從下往上排列的。

技術分享

發現了左下的第二條像素有異常,對比一下1.png 2.png發現了2.png有問題 那麽我們可以用神器stegsolve來輔助,stegsolve——Analyse——Image Combiner對比兩個文件。查看Sub或Xor,可以發現左下角,第二條像數條是有異常的,有紅色的出現。

技術分享

把1.png和2.png進行一下sub方法 把結果保存成solved.bmp。

然後把2.png保存成2.bmp 24位位圖的格式,這個是因為png圖片經過了壓縮,不好直接對比每個字節,而bmp圖片是沒有壓縮的,直接保存各個像數點的數據。

這個題還有一個坑點就是偏移的問題 png圖片的掃描是從左向右,從下往上來的。而坑的是這個圖的信息隱藏並沒有在一開頭的像數,而是是第二行像數,所以就需要利用bmp的優勢,儲存無壓縮,方便尋找到偏移,從而找到信息隱藏的地方。利用winhex打開,黑色的像數的在bmp中的hex的00保存的,那麽我們就尋找不是00的地方。在偏移0x1110的地方可以發現

技術分享  

有不是00的字節,一開始還以為這些就是flag的信息了,後來才發現是因為兩個圖片sub影響到了效果,真正的信息是隱藏在2.png中的,所以打開由2.png轉換的2.bmp來對,通過之前diff得到的偏移,尋找到0x1110的地方,直到0x1330結束,這是隱藏的信息。

技術分享

技術分享

只保留00 01,這個是因為RGB的關系,只隱藏在R通道裏面了,其他通道都是圖片的正常像數信息,過濾掉就可以了。

00010000010000010001000100000101000100000001010100010101010001010001000000010001000001010001000000010101000001010001000101000001000100010101010100010001000001010001010100010000000100000001000100010100000101010000010100010000000101000101010000000101000000000001010000010101000100010000010000000101000100000001010100000000000100000100000000010101010000010001010101010001

觀察一下可以發現,而奇數位都是0,是多余的,把這些去除掉。直接把00 替換成0,01替換成1就可以了。

0100100101010011010001110111101101000101001101000111001101011001010111110101001101110100010001010110011100110100011011100011000001100111010100100011010001110000010010000111100101111101

得到了這個之後,可以發現他的長度是184,是8的倍數,把他轉換成ascii碼就可以了。可以使用JPK工具來進行轉換,工具的下載的鏈接是www.wechall.net/applet/JPK_406.jar。

對比2.bmp可以發現隱藏了一些00 01這些信息,把這一部分扣出來。

技術分享

JPK——binary——binary to ascii

技術分享

就得到了flag,ISG{E4sY_StEg4n0gR4pHy}

這種就是利用的兩張圖片對比來尋找差異,從而找到信息隱藏的地方,這樣子出題往往是因為一張圖片能提供的信息太少。

0x06 後記

這個總結其實還是缺很多的,因為隱寫術能寫的東西太多了,比如jpg的冗余信息的壓縮也可以隱藏進信息,還有其他的多媒體文件也可以進行隱寫,例如音頻文件,視頻文件等等,有很多東西可以研究。一開始是覺得隱寫術特別的有趣才接觸到的,就像是在藏寶尋寶一樣,特別好玩,希望你們也可以感受到這種快樂。

隱寫術總結