安全圈 | 专注于最新网络信息安全讯息新闻

首页

android 9patch圖片解析堆溢出漏洞分析(cve

作者 gigliotti 时间 2020-02-24
all

【前言】

     日前穀歌公開了一個今年1月份更新的漏洞。這個漏洞修復了一個存在於Android 5.1版本以下圖片渲染的問題,可以查看相關連結。

     9patch是Android上特有的一種圖片格式,就是在普通的png圖片的基礎了新增了一些點數的邊框,使之具有可隨意拉伸、縮放的功能。

【9patch檔案格式概述】

           前面說到9patch檔案是一種特殊png圖片,我們先來看下png檔案結構。

           在png檔案的起始處是一個被稱為signature的東西,即檔案簽名,很多人把它叫做檔案頭,長度為8個位元組,這8個字元的值是固定的。

     在signature之後是一個chunk塊序列,每個chunk塊的大小都是不定的,裡面存儲著影像數據,chunk塊的結構如下:

      偽代碼描述如下:

           在chunk的起始處是chunk長度,被定義為4位元組大端整數。這個chunk長度僅僅是chunkdata的長度,不包括自身、type和crc的長度,囙此整個chunk塊的長度還需要加上這三個域的大小。之後一個4位元組的字元序列,只能由英文字元組成,表示chunk塊的類型。隨後chunk數據部分,長度由開始的length指定,當length為0時這個域可以不存在。最後是整個塊的CRC校驗碼。再往後?就是下一個chunk塊了啊。

           下麵說下本文的主角9patch檔案。它是包含類型為”npTc”在chunk的png檔案。看下google官方的定義(已過濾不相關的若干程式碼):

     來看一個普通的9patch檔案

     這個9patch檔案的npTc塊位於第一個IHDR塊之後,chunk長度為0x20,data域的值都為0,圖中指出了numXDivs、numYDivs和numColors的位置,依次可以推出其他數據域的值。

【漏洞分析】

           (懶得看的話直接跳到最後看結論)。

      在5.1版本上加載一張盡心構造的9patch圖片,就會導致行程Crash,如下圖所示。

           看錯誤是引用了不合法的地址,看google的補丁吧:

補丁一共有兩處:

1.     chunk塊中numXDivs、numYDivs、numColors三個變數的定義改成了無符號型

2.     npTc塊的peek函數中的斷言改成了判斷不等再返回

numXDivs、numYDivs、numColors這三個變數什麼要改成無符號型,為什麼不能是負的,如果是負的會怎麼樣,帶著問題再分析,看看哪裡用到了這三個值。

          從這裡可以看出xDivsOffset是Res_png_9patch結構的長度,這是一個常數,一般來說是0x20。yDivsOffset的值在此基礎上新增大小為numXDivs的int數組的長度,colorsOffset的值在yDivsOffset的基礎上新增大小為numYDivs的int數組的長度。再回溯:

           而yDivsOffset和colorsOffset以决定了yDivs和colors兩個數組的地址,那只要精心構造numXDivs、numYDivs就可以在一定範圍內訪問其他任意的記憶體,,看來剛才報的引用非法地址應該就是這裡了。

           還有一處引用了numXDivs、numYDivs、numColors的地方。

      再看看調用serializedSize的地方:

           這裡用serializedSize()的返回值和length進行比較,而numXDivs、numYDivs、numColors可以為負,影響了serializedSize正常的計算,觸發斷言,中斷程式。

【總結】

           分析了這麼多,來總結漏洞成因。

     Res_png_9patch結構中定義了numXDivs、numYDivs、numColors的類型為有符號數,當它們得到負值時會影響yDivsOffset、colorsOffset和serializedSize的取值,從而導致堆溢出,現象就是數組越界。

     

將之前檔案中的numXDivs、numYDivs、numColors三比特其中某一比特修改為負數(即大於0x80)即可驗證此漏洞。

【檢測方案】

           掌握這個漏洞的細節以後要防就很容易了,只要遍歷png檔案的所有chunk塊,針對其中的npTc塊進行檢測,判斷numXDivs、numYDivs、numColors是否為負,只要其中有一個為負則可判定為惡意檔案,相關檢測代碼如下: