作者:
路人甲
·
2015/10/22 10:21
前言:zip
壓縮格式應用廣泛,各個平臺都有使用,Windows
平臺使用來壓縮檔案,Android
平臺使用來作為apk
檔案的格式。由於zip
檔案格式比較複雜,在解析zip
檔案格式時,如果處理不當,可能導致一些有意思的邏輯漏洞,本篇文章將挑選有意思的漏洞進行解析。
一、副檔名欺騙漏洞
很早之前,國外安全研究人員爆料Winrar 4.x版本存在副檔名欺騙漏洞,駭客可以透過該漏洞誘騙受害者執行惡意程式。該漏洞的主要原理是:Winrar
在檔案預覽和解壓縮顯示檔名使用的是不同結構體的欄位導致的。
1.1 zip格式檔案的結構
在瞭解漏洞的原理前,先熟悉下zip格式的檔案結構。
如果一個壓縮包檔案裡有多個檔案,可以認為每個檔案都是被單獨壓縮,然後再拼成一起。
一個 ZIP
檔案由三個部分組成:壓縮原始檔資料區+壓縮原始檔目錄區+壓縮原始檔目錄結束標誌,如下圖:
1)檔案頭(壓縮原始檔目錄區)在檔案末尾,即圖1中的File Header
,記錄了索引段的偏移、大小等等。
2)資料段(壓縮原始檔資料區)在檔案開頭,即圖1中的Local Header
,記錄了資料的一些基本資訊,可以用來跟File Header
中記錄的資料進行比較,保證資料的完整性。
3)Local Header
還包含了檔案被壓縮之後的儲存區,即圖1中的Data
區域。
4)圖2和圖3為Local Header
(圖2中的ZIPFILERECORD
)和File Header
(圖3中的ZIPDIRENTRY
)的資料對比,兩者資料是一致的。
1.2 漏洞產生原因
Winrar
在檔案預覽的時候使用的是ZIPDIRENTRY
下面的deFileName
欄位來顯示檔名,解壓縮的時候使用的是ZIPFILERECORD
下面的frFileName
欄位來顯示檔名。如果將deFileName
欄位副檔名改成jpg
、gif
等圖片的副檔名,可以欺騙使用者執行惡意程式。
Winrar
檔案預覽示意圖:
使用者看到的是jpg
圖片,開啟的確實exe
檔案,真坑啊!
Winrar
解壓縮檔案示意圖:
解壓縮之後顯示的exe
,兩處顯示的不一樣。
二、Android Master Key漏洞
之前,國外安全研究人員爆出第三個Android Master Key漏洞,該漏洞的主要原理是:android
在解析Zip
包時,沒有校驗ZipEntry
和Header
中的FileNameLength
是否一致。
2.1 zip檔案格式的結構
在瞭解漏洞的原理前,還是先熟悉下zip
格式的檔案結構。
如果一個壓縮包檔案裡有多個檔案,可以認為每個檔案都是被單獨壓縮,然後再拼成一起。
一個 ZIP
檔案由三個部分組成:壓縮原始檔資料區+壓縮原始檔目錄區+壓縮原始檔目錄結束標誌,如圖1所示:
1)檔案頭(壓縮原始檔目錄區)在檔案末尾,即圖1中的File Header
,記錄了索引段的偏移、大小等等。
2)資料段(壓縮原始檔資料區)在檔案開頭,即圖1中的Local Header
,記錄了資料的一些基本資訊,可以用來跟File Header
中記錄的資料進行比較,保證資料的完整性。
3)Local Header
還包含了檔案被壓縮之後的儲存區,即圖1中的Data
區域。
4)圖2和圖3為Local Header
(圖2中的ZIPFILERECORD
)和File Header
(圖3中的ZIPDIRENTRY
)的資料對比,兩者資料是一致的。
2.2 漏洞產生原因
先來看一下是如何定位到Local Header
中的Data
資料:
off64_t dataOffset = localHdrOffset +
kLFHLen +
get2LE(lfhBuf + kLFHNameLen) +
Data
的偏移是透過Header
的起始偏移+Header
的大小(固定值)+Extra data
的大小+檔名的大小,如下圖
回頭看一下,java
在獲取Data
偏移的處理,在讀取Extra data
的長度的時候,它已經預存了檔名在FileHeader
中的長度。
// We don't know the entry data's start position.
// All we have is the position of the entry's local
// header. At position 28 we find the length of the
// extra data. In some cases this length differs
// from the one coming in the central header.
RAFStream rafstrm = new RAFStream(raf,
entry.mLocalHeaderRelOffset + 28);
DataInputStream is = new DataInputStream(rafstrm);
int localExtraLenOrWhatever =
漏洞就在這裡產生了,如果Local Header
中的FileNameLength
被設成一個大數,並且FileName
的資料包含原來的資料,File Header
中的FileNameLength
長度不變,那麼底層C++
執行和上層Java
執行就是不一樣的流程。
C++ Header 64k Name Data
+--------> +----------------------> +---------->
length=64k classes.dex dex\035\A... dex\035\B...
+--------> +---------> +---------->
如上面所示,底層C++
的執行會讀取64k的FileName
長度,而Java
層由於是讀取File Header
中的資料,FileName
的長度依舊是11,於是Java
層校驗簽名透過,底層執行會執行惡意程式碼。
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!