天天看点

Android安全开发之ZIP文件目录遍历

1、zip文件目录遍历简介

因为zip压缩包文件中允许存在“../”的字符串,攻击者可以利用多个“../”在解压时改变zip包中某个文件的存放位置,覆盖掉应用原有的文件。如果被覆盖掉的文件是动态链接so、dex或者odex文件,轻则产生本地拒绝服务漏洞,影响应用的可用性,重则可能造成任意代码执行漏洞,危害用户的设备安全和信息安全。比如近段时间发现的“寄生兽”漏洞、海豚浏览器远程命令执行漏洞、三星默认输入法远程代码执行漏洞等都与zip文件目录遍历有关。

阿里聚安全的应用漏洞扫描服务,可以检测出应用的zip文件目录遍历风险。另外我们发现日本计算机应急响应小组(jpcert)给出的修复方案存在缺陷。如果使用不当(它提供的示例文档就使用错误),可能起不到防止zip文件目录遍历的作用,并且国内有修复方案参考了此方案。

2、漏洞原理和风险示例

2.1 漏洞原理

在linux/unix系统中“../”代表的是向上级目录跳转,有些程序在当前工作目录中处理到诸如用“../../../../../../../../../../../etc/hosts”表示的文件,会跳转出当前工作目录,跳转到到其他目录中。

java代码在解压zip文件时,会使用到zipentry类的getname()方法,如果zip文件中包含“../”的字符串,该方法返回值里面原样返回,如果没有过滤掉getname()返回值中的“../”字符串,继续解压缩操作,就会在其他目录中创建解压的文件。

如我们构造的zip文件中有如下文件:

Android安全开发之ZIP文件目录遍历

  进行解压的代码如下,没有对getname进行过滤:

Android安全开发之ZIP文件目录遍历

  解压操作时的日志:

Android安全开发之ZIP文件目录遍历

此zip文件存放在sd卡中,想让解压出来的所有文件也存在sd卡中,但是a_poc.txt文件却存在了应用的数据目录中:

Android安全开发之ZIP文件目录遍历

  2.2 风险示例

以海豚浏览器远程代码执行漏洞为例。

海豚浏览器的主题设置中允许用户通过网络下载新的主题进行更换,主题文件其实是一个zip压缩文件。通过中间人攻击的方法可以替换掉这个zip文件。替换后的zip文件中有重新编译过的libdolphin.so。此so文件重写了jni_onload()函数:

Android安全开发之ZIP文件目录遍历

此so文件以“../../../../../../../../../../data/data/mobi.mgeek.tunnybrowser/files/libdolphin.so”的形式存在恶意zip文件中。海豚浏览器解压恶意zip文件后,重新的libdolphin.so就会覆盖掉原有的so文件,重新运行海豚浏览器会弹出toast提示框:

Android安全开发之ZIP文件目录遍历

  能弹出toast说明也就可以执行其他代码。

这里分析下此漏洞产生的原因是:

1、主题文件其实是一个zip压缩包,从服务器下载后进行解压,但是解压时没有过滤getname()返回的字符串中是否有“../”:

Android安全开发之ZIP文件目录遍历

2、动态链接库文件libdolphin.so,并没有放在应用数据的lib目录下,而是放在了files目录中:

Android安全开发之ZIP文件目录遍历

加载使用的地方是com.dolphin.browser.search.redirect包中的searchredirector:

Android安全开发之ZIP文件目录遍历

应用使用的是system.load()来加载libdolphin.so而非system.loadlibrary(),在android中,system.loadlibrary()是从应用的lib目录中加载.so文件,而system.load()是用某个.so文件的绝对路径加载,这个.so文件可以不在应用的lib目录中,可以在sd卡中,或者在应用的files目录中,只要应用有读的权限目录中即可。

在files目录中,应用具有写入权限,通过网络中间人攻击,同时利用zip文件目录遍历漏洞,替换掉文件libdolphin.so,达到远程命令执行的目的。

应用的lib目录是软链接到了/data/app-lib/应用目录,如果libdolphin.so文件在lib目录下就不会被覆盖了,第三方应用在执行时没有写入/data/app-lib目录的权限:

Android安全开发之ZIP文件目录遍历

  3、jpcert修复方案的研究

在研究中我们发现jpcert提供的修复方案存在缺陷。它是利用java的file类提供的getcanonicalpath()方法过滤掉zipentry.getname()返回的字符串中所包含的“../”,然后检查这个字符串是否是以要解压到的目标目录字符串为开头,如果是,返回getcanonicalpath()获取到的字符串,如果不是,则抛出异常:

Android安全开发之ZIP文件目录遍历

但是在jpcert给出的示例代码中,对validatefilename()的调用对于app来说不会达到防止任意目录遍历的目的:

Android安全开发之ZIP文件目录遍历

其使用“.”,作为要解压到的目的目录,“.”表示当前目录,经测试app进程的当前工作目录是根目录“/”:

Android安全开发之ZIP文件目录遍历
Android安全开发之ZIP文件目录遍历

  查看进程状态,得到的app进程的当前工作目录cwd是链接到了根目录:

Android安全开发之ZIP文件目录遍历

如下的demo,如果采用jpcert示例中validatefilename(entry.genname(), “.”)的调用方式,还是会产生目录遍历读到系统配置文件:

Android安全开发之ZIP文件目录遍历

  读到的hosts文件内容:

Android安全开发之ZIP文件目录遍历

正确的调用validatefilename()形式是传入的要解压到的目的目录不要用“.”,而是指定一个绝对路径。

4、阿里聚安全对开发者建议

1 对重要的zip压缩包文件进行数字签名校验,校验通过才进行解压。

2 检查zip压缩包中使用zipentry.getname()获取的文件名中是否包含”../”或者”..”,检查”../”的时候不必进行uri decode(以防通过uri编码”..%2f”来进行绕过),测试发现zipentry.getname()对于zip包中有“..%2f”的文件路径不会进行处理。

3 在应用上线前使用阿里聚安全的安全扫描服务,尽早发现应用的安全风险。

阿里聚安全扫描器建议修复方案:

在使用java.util.zip包中zipinputstream类的进行解压操作时,进行检查,示例如下:

Android安全开发之ZIP文件目录遍历

也可以使用java.util.zip包中的zipfile类,直接读取zip包中的所有entries,然后检查getname()的返回值是否包含“../”:

Android安全开发之ZIP文件目录遍历

  5、参考

[1] https://www.jpcert.or.jp/present/2014/20140910android-sc.pdf

[2] 《海豚浏览器与水星浏览器远程代码执行漏洞详解》http://drops.wooyun.org/mobile/8293

[3] 《影响数千万app的安卓app“寄生兽”漏洞技术分析》http://drops.wooyun.org/mobile/6910

[4] 《三星默认输入法远程代码执行》http://drops.wooyun.org/papers/6632

[5] http://www.oracle.com/technetwork/articles/java/compress-1565076.html

[6] http://stackoverflow.com/questions/1099300/whats-the-difference-between-getpath-getabsolutepath-and-getcanonicalpath

[7] http://stackoverflow.com/questions/7016391/difference-between-system-load-and-system-loadlibrary-in-java

6、android安全开发系列

android安全开发之provider组件安全

android安全开发之浅谈密钥硬编码

android安全开发之浅谈网页打开app

android安全开发之浅谈加密算法的坑

本文转自d1net(转载)

继续阅读