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


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文件中包含“../”的字符串,该方法返回值里面会原样返回。如果在这里没有进行防护,继续解压缩操作,就会将解压文件创建到其他目录中。

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

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

解压操作时的日志:

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

2.2 风险示例

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

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

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

这里分析下此漏洞产生的原因是: 
1、主题文件其实是一个ZIP压缩包,从服务器下载后进行解压,但是解压时没有过滤getName()返回的字符串中是否有“../”:

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

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

应用使用的是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目录的权限:


3、JPCERT修复方案的研究

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

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

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

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

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

读到的hosts文件内容:

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


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

1 对重要的ZIP压缩包文件进行数字签名校验,校验通过才进行解压。 
2 检查Zip压缩包中使用ZipEntry.getName()获取的文件名中是否包含”../”或者”..”,检查”../”的时候不必进行URI Decode(以防通过URI编码”..%2F”来进行绕过),测试发现ZipEntry.getName()对于Zip包中有“..%2F”的文件路径不会进行处理。 
3 在应用上线前使用阿里聚安全的安全扫描服务,尽早发现应用的安全风险。

阿里聚安全扫描器建议修复方案: 
在使用java.util.zip包中ZipInputStream类的进行解压操作时,进行检查,示例如下:

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


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应用安全开发之浅谈加密算法的坑

作者:伊樵、呆狐、舟海@阿里聚安全,更多安全技术文章,请访问阿里聚安全博客


阿里聚安全由阿里巴巴移动安全部出品,面向企业和开发者提供企业安全解决方案,全面覆盖移动安全、数据风控、内容安全、实人认证等维度,并在业界率先提出“以业务为中心的安全”,赋能生态,与行业共享阿里巴巴集团多年沉淀的专业安全能力。

时间: 2024-09-13 02:34:43

Android安全开发之ZIP文件目录遍历的相关文章

Android安全开发之Provider组件安全

Android安全开发之Provider组件安全 作者:伊樵.呆狐@阿里聚安全 一.Content Provider组件简介 Content Provider组件是Android应用的重要组件之一,管理对数据的访问,主要用于不同的应用程序之间实现数据共享的功能.Content Provider的数据源不止包括SQLite数据库,还可以是文件数据.通过将数据储存层和应用层分离,Content Provider为各种数据源提供了一个通用的接口. 创建一个自己的Content Provider需要继承

Android编程开发之Spinner控件用法实例分析_Android

本文实例讲述了Android编程开发之Spinner控件用法.分享给大家供大家参考,具体如下: 下拉列表 Spinner,Spinner是一个每次只能选择所有项的一个项的控件.它的项来自于与之相关联的适配器中. Spinner的使用,可以极大提高用户的体验性.当需要用户选择的时候,可以提供一个下拉列表将所有可选的项列出来.供用户选择. 一.使用数组作为数据源 布局文件: <RelativeLayout xmlns:android="http://schemas.android.com/ap

Android编程开发之Spinner组件用法_Android

本文实例讲述了Android编程开发之Spinner组件用法.分享给大家供大家参考,具体如下: Spinner组件组要用显示一个下拉列表,在使用中需要用到适配器Adapter,下面是一个该组件的使用示例 首先是布局文件main.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res

Android编程开发之TextView文字显示和修改方法(附TextView属性介绍)_Android

本文实例讲述了Android编程开发之TextView文字显示和修改方法.分享给大家供大家参考,具体如下: 一. 新建一个Activity 和 Layout 首先在layout文件夹中新建一个activity_main.xml,在新建工程的时候一般默认会新建此xml文件,修改其代码如下: activity_main.xml 代码 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" x

Android编程开发之在Canvas中利用Path绘制基本图形(圆形,矩形,椭圆,三角形等)_Android

本文实例讲述了Android编程开发之在Canvas中利用Path绘制基本图形的方法.分享给大家供大家参考,具体如下: 在Android中绘制基本的集合图形,本程序就是自定义一个View组件,程序重写该View组件的onDraw(Canvase)方法,然后在该Canvas上绘制大量的基本的集合图形. 直接上代码: 1.自定义的View组件代码: package com.infy.configuration; import android.content.Context; import andro

Android编程开发之TextView控件用法(2种方法)_Android

本文实例讲述了Android编程开发之TextView控件用法.分享给大家供大家参考,具体如下: 这里我们会讲讲常用控件的使用. 在今后的大多数章节里面也是一样的,我们会具体的说说某些控件的用法.因为只要把这些控件组合在一起它们就是一个应用了. 好吧我们直接看看这个控件怎么用. 细心的同学会发现,其实这个控件的内容是定义在values文件夹里面的strings.xml中的. 那么我们只需要给它加一段代码: 复制代码 代码如下: <string name="test">Wel

Android编程开发之TextView单击链接弹出Activity的方法_Android

本文实例讲述了Android编程开发之TextView单击链接弹出Activity的方法.分享给大家供大家参考,具体如下: 话不多说直接上码: 核心源码: package com.example.textview4; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.text.SpannableString; import android.tex

Android编程开发之NotiFication用法详解_Android

本文实例讲述了Android编程开发之NotiFication用法.分享给大家供大家参考,具体如下: notification就是通知的意思,安卓中指通知栏,一般用在电话,短信,邮件,闹钟铃声,在手机的状态栏上就会出现一个小图标,提示用户处理这个快讯,这时手从上方滑动状态栏就可以展开并处理这个快讯. 在帮助文档中,是这么说的, notification类表示一个持久的通知,将提交给用户使用NotificationManager.已添加的Notification.Builder,使其更容易构建通知

Android编程开发之RadioGroup用法实例_Android

本文实例讲述了Android编程开发之RadioGroup用法.分享给大家供大家参考,具体如下: RadioGroup 有时候比较有用.主要特征是给用户提供多选一机制. MainActivity.java package com.example.lesson16_radio; import android.app.Activity; import android.os.Bundle; import android.widget.RadioButton; import android.widget