APK签名验证原理及Upgrade DoS漏洞剖析【转】

0x01 概述
本文讨论范围包括Android APK包签名验证原理,基于验证过程引起的Upgrade DoS漏洞的原理和重现方法,将按照基本概念,APK包组成及签名验证流程,Upgrade DoS剖析的顺序依次展开。望开发者能从中学习到一些思想,应用于平时的开发中,因本人才疏学浅,如有描述不准确的地方,欢迎大家提出指正。

0x02 基本概念消息摘要(Message Digest)
在通信过程中,为使接收方验证接受到的信息的完整性和真实性,使用散列函数等对传输的消息处理后的输出值,被称为该消息的消息摘要。一般情况下,不同的消息摘要是不一样的,除非该函数产生碰撞现象;另外无法从摘要逆向计算得到消息本身。

数字签名(Signature)
在通信过程中,为使接收方能对发送方进行身份验证,使用非对称公钥体制和消息摘要进行结合,发送方用私钥对摘要进行加密,接受方用公钥进行解密,然后对消息用同样的方式获取摘要。并与解密结果进行对比,便可达到身份认证(因为只有发送方拥有私钥)和消息鉴别的功能。

数字证书(Certificate)
数字证书是一个经数字签名的包含公开密钥拥有者信息以及公开密钥的文件。 证书包含的有效信息有:证书版本、证书序号、证书颁发机构、证书有效期、证书拥有者和拥有者公钥,以及证书颁发机构对该证书的签名。Android打包用的证书是自签名的X.509格式的证书。当使用某证书时,需要验证该证书的合法性:使用证书颁发者的公钥,然后对整个证书(除了证书数字签名以外)采用给定的证书签名算法计算,然后将计算结果同证书数字签名的解密结果进行对比,相同则可以证明该证书确实由证书颁发者颁发的合法证书;不同则说明已被篡改,证书不合法。可使用openssl pkcs7 -inform DER -in file_name -noout -print_certs -text命令查看证书具体内容。

0x03 APK包组成及签名验证流程
段落是文章中最基本的单位。内容上它具有一个相对完整的意思;在文章中,段具有换行的标。段是由句子或句群组成的,在文章中用于体现作者的思路发展或全篇文章的层次。有的段落只有一个句子,称为独句段,独句段一般是文章的开头段、结尾段、过渡段强调段等特殊的段落。多数段落包括不止一个句子或句群,叫多句段。

APK包组成
APK包可大体被分为两部分–应用源文件和META-INFO文件夹,其结构如下图所示:

应用源文件包括classes.dex、manifest.xml,res文件夹,assets文件夹和lib文件夹等;META-INFO文件夹包含MANIFEST.MF,CERT.SF(或者是xx.SF,xx是使用者证书的自定义别名,默认为CERT)和CERT.RSA(或者xx.DSA, 后缀名不同代表不同的签名算法,xx与SF对应,当使用多重证书签名时,每一个.SF文件必须有一个.RSA/.DSA文件与之对应)文件。
其中MANIFEST.MF,以SHA-1 + BASE64编码的形式存储着除META-INFO文件夹外所有源文件的摘要值,如图所示:


其次CERT.SF,以SHA-1 + BASE64编码的形式存储着MANIFEST.MF以及MANIFEST.MF各子项的摘要值,如图所示:最后是CERT.RSA,存储着用私钥对CERT.SF的数字签名、签名算法、公钥、证书所有者,颁发机构等信息,如图所示:

签名验证原理
当安装应用时,系统会计算源文件的摘要值的BASE64编码并与MANIFEST.MF中对应的值进行比较,如果不同则说明被篡改,安装失败。
然后计算MANIFEST.MF以及其包含的子项的摘要的BASE64编码值并与CERT.SF中相对应的项比较,如果不同则说明被篡改,安装失败。
最后验证证书的有效性,获取CERST.SF的签名值并与经证书保存公钥解密的CERT.SF.Signature的值进行比较,如果整个过程出现异常,则安装失败。
签名验证的源码位于frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java,可以从该类开始跟踪。

0x04 Upgrade DoS漏洞剖析
漏洞剖析
众所周知,在应用升级过程中,新应用的签名信息必须与已装应用的签名完全一样,而且新应用的版本号不能低于已装应用,不然的话,应用升级过程就会失败。另外二次打包的应用因其其签名信息不同不能够升级替换掉已装应用 。
但是依据上述签名验证机制,删除APK中除META-INFO之外的其他文件后,因满足APK中存在的文件在MANIFEST.MF中的摘要值存在并正确,故验证能通过,APK依然能成功安装(新版的系统已修复该漏洞)。但是应用无法正常使用,会遭成本地DoS攻击。也就是说, 源文件存在则其摘要必须存在于MANIFEST.MF中,但是不代表MANIFEST.MF中存在的项在源文件中相应的存在。MANIFEST.MF中的摘要值提供了防止Android源文件的增、改操作的功能,但并不能保护源文件的删操作。
另外在所测试的Android系统(nexus 5 android 4.4)中,APK存储路径 / system /app (系统应用),/system/priv-app(系统应用)其目录可以被访问,目录下的APK提供了读权限给任意的用户,不需要root,如图所示:/system/app/


/system/priv-app/

APK存储路径 /data/app (用户应用) 其目录虽然普通用户不可以被访问,目录下的APK提供了读权限给任意的用户,不需要root,如图所示:
访问目录失败
/data/app/下的APK提供了读权限给任意用户

这样的话可以读取本地所有已安装应用的APK 源文件,然后用JarEntry进行恶意删除源文件操作,调用系统自带的应用升级过程Activity,将修改后的APK重新安装回去覆盖掉原始应用,假如设备已经root了,则可以使用“pm install”命令进行静默安装 , 造成本地大规模的 拒绝服务攻击,如能配合诸如一些像应用的更新漏洞,将可以给攻击者提供一个很好的攻击途径,方便攻击者攻击用户的设备。在通信过程中,为使接收方验证接受到的信息的完整性和真实性,使用散列函数等对传输的消息处理后的输出值,被称为该消息的消息摘要。一般情况下,不同的消息修的摘要是不一样的,除非该函数产生碰撞现象;另外无法从摘要逆向计算得到消息本身。

此条目发表在未分类, 经验技术分类目录。将固定链接加入收藏夹。