Android uncovers master-key 漏洞分析

wyzsk發表於2020-08-19
作者: livers · 2013/07/11 12:38

0x00 背景


Bluebox的CTO Jeff Forristal在其官⽅方blog爆出一個漏洞叫做UNCOVERING ANDROID MASTER KEY,大致是不篡改簽名修改android程式碼。

Link:http://bluebox.com/corporate-blog/bluebox-uncovers-android-master-key/

blog:關於細節並沒有講太多,只有discrepancies in how Android applications are cryptographically verified & installed(安卓應⽤用簽名驗證和安裝的不⼀一致)essentially allowing a malicious author to trick Android into believing the app is unchanged even if it has been(讓andriod系統本⾝身認為應⽤用沒有修改)這兩條重要的資訊。

剩下就是放出來一張更改基帶字串的圖:

enter image description here

具體細節7月底的blackhat放出。

沒多少天7月8號國外已經有人放出poc來。微博上看到rayh4c說已經搞定。就分析了一下。

0x01 分析


POC還沒出來之前,先是看了下android的簽名機制和安裝機制。

簽名機制: 用簡單的話來講就是android把app應用的所有檔案都做了sha1(不可逆)簽名,並對這簽名用RSA(非對稱加密演算法)的私鑰進行了加密,客戶端安裝驗證時用公鑰進行解密。

從邏輯上看,這簽名機制對完整性和唯一性的校驗是完全沒問題的。主流的很多加密都類似這樣。

安裝機制:

安裝機制則較為複雜。

1.系統應用安裝――開機時完成,沒有安裝介面
2.網路下載應用安裝――透過market應用完成,沒有安裝介面
3.ADB⼯工具安裝――沒有安裝介面。
4.第三⽅方應用安裝――透過SD卡⾥裡的APK⽂檔案安裝,有安裝介面,由packageinstaller.apk應⽤用處理安裝及解除安裝過程的介面。

安裝過程:複製APK安裝包到data/app目錄下,解壓並掃描安裝包,把dex⽂檔案(Dalvik位元組碼) 儲存到dalvik-cache目錄,並data/data目錄下建立對應的應⽤用資料目錄。

到這裡看出在安裝機制上的問題可能性比較大。

回頭看⽼老外的POC:https://gist.github.com/poliva/36b0795ab79ad6f14fd8

enter image description here

在linux執⾏行了一遍,出現錯誤。可能是apk的原因。

索性把這poc移植到windows下,先是⽤用apktool 把要更改的apk給反編譯出來到一個目錄apk_test

然後⼜又把apk_test打包成⼀一個新的apk

把原先的apk解壓出來apk_old

把apk_old所有⽂檔案以zip壓縮的⽅方式加⼊入新的apk中。我本機以weibo.apk為例:

enter image description here

可見兩者大小發生了變化,apktool在反編譯過程不可避免的出現差異。並且重編譯的apk不含有簽名檔案。

按照poc的做法我用批處理匯出目錄的檔名到1.txt修改了poc.py

import zipfile
import sys
f=open('1.txt','r')
line=f.readline()
test=[]
while line:
    test1=line.replace("\n","")
    test.append(test1)
    if not line:
        break
    line=f.readline()
f.close()
z = zipfile.ZipFile("livers.apk", "a")
for i in range(0,len(test)):
    print test[i]
    z.write(str(test[i]))
z.close()

enter image description here

差不多增大了一倍,放在手機上安裝了一下,成功安裝。檢視了下:

enter image description here

出現了多對同名檔案。CRC校驗不同,檢視了一下,基本上是兩個位元組便產生不同。

enter image description here

這裡我又測試了只新增簽名檔案,或者dex檔案等,均不能透過驗證。

可證明其在scan list掃描目錄或者複製檔案時候對同名檔案處理不當。

0x02 驗證


證明是否可以進行更改原始碼,並能使用原生簽名。我把apk圖示進行了更改。

順便講下一般的反編譯修改:

1. apktool或者其他工具進行反編譯包含smalijava位元組碼彙編和xml圖片檔案。 
2. apkzip解壓。
3. 反編譯dex成java檔案。
4. 查詢對應修改的smali檔案或者xml(一般廣告連結)
5. Apktool打包成apk檔案
6. 用autosign進行簽名。
這裡沒有進行簽名直接借用原來的簽名。

enter image description here

enter image description here

0x03 查詢根源


我這裡下載的android 2.2的原始碼,查詢到獲取簽名資訊安裝位於frameworks\base\core\java\android\content\pm\PackageParser.java這個檔案,public boolean collectCertificates(Package pkg, int flags)private Certificate[] loadCertificates(JarFile jarFile, JarEntry je, byte[] readBuffer)這個方法是用來獲取簽名資訊的。

 Enumeration entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry je = (JarEntry)entries.nextElement();
                if (je.isDirectory()) continue;
                if (je.getName().startsWith("META-INF/")) continue;
                Certificate[] localCerts = loadCertificates(jarFile, je,
                        readBuffer);
            。。。。。。
                } else {
                    // Ensure all certificates match.
                    for (int i=0; i<certs.length; i++) {
                        boolean found = false;
                        for (int j=0; j<localCerts.length; j++) {
                            if (certs[i] != null &&
                                    certs[i].equals(localCerts[j])) {
                                found = true;
                                break;
                            }
                        }
                      。。。。。

前面透過黑盒方式,大致推斷出安裝機制就是把重新命名檔案同時處理了,沒有覆蓋而是:

if (certs[i] != null &&certs[i].equals(localCerts[j])) {
    found = true;
    break;
} 

兩個重名檔案都做了驗證,只要有一個透過驗證,就返回驗證透過。

0x04 後繼


我android研究不多,大多以前玩逆向的底子。大家可以多討論。 歡迎大家留言探討~!

======================================================================================================

7月11日21點更新:

沒看到看雪上已經討論的熱火朝天,讀下來來源於看雪的zmworm的原理分析應該是更準確的。

原理簡述



由於ZIP格式允許存在兩個或以上完全相同的路徑,而安卓系統沒有考慮這種場景。

在該情況下,android包管理器校驗簽名取的是最後一個檔案的hash,而執行APK載入的dex檔案卻是zip的第一個dex檔案。



包管理器驗證簽名驗的是最後一個(名字相同情況下)檔案。

1. 解析zip的所有Entry,結果存到HashMap(key為路徑,value為Entry)。

enter image description here

2. 由於HashMap.put在相同key的情況下,會把value更新,導致上述的HashMap在相同路徑下,儲存的一定是最後一個檔案的Entry。

enter image description here


系統載入dex檔案,載入的是第一個dex。

 



1. 查詢dex的Entry用的是dexZipFindEntry。


enter image description here

2. dexZipFindEntry的實現是隻要match就返回,所以返回的都是第一個檔案。

enter image description here

Zip 可以包含兩個同名檔案或者路徑,而其自身的unzip 預設方式是後一個覆蓋前一個。

HashMap.put 的寫法應該檔案也直接覆蓋(hash表的衝突處理不當果真出大問題)才算是算是符合zip 的標準。

就是載入dex的方式則是先載入第一個,這樣確實資訊不一致。

而我之前黑盒測出來認為android 預設把兩個都載入在簽名驗證順序上出現問題的,未分析到上一層的類。

看雪上也是討論很多帖子得到準確的原理分析,大家共同討論,集思廣益。Hack it, know it too.

持續跟新中。

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章