- 对本书的赞誉
- 前言
- 基础篇
- 第 1 章 Android 中锁屏密码加密算法分析
- 第 2 章 Android 中 NDK 开发
- 第 3 章 Android 中开发与逆向常用命令总结
- 第 4 章 so 文件格式解析
- 第 5 章 AndroidManifest.xml 文件格式解析
- 第 6 章 resource.arsc 文件格式解析
- 第 7 章 dex 文件格式解析
- 防护篇
- 第 8 章 Android 应用安全防护的基本策略
- 第 9 章 Android 中常用权限分析
- 第 10 章 Android 中的 run-as 命令
- 第 11 章 Android 中的 allowBackup 属性
- 第 12 章 Android 中的签名机制
- 第 13 章 Android 应用加固原理
- 第 14 章 Android 中的 so 加固原理
- 工具篇
- 第 15 章 Android 逆向分析基础
- 第 16 章 反编译神器 apktool 和 Jadx
- 第 17 章 Hook 神器 Xposed
- 第 18 章 脱壳神器 ZjDroid
- 第 19 章 Native 层 Hook 神器 Cydia Substrate
- 操作篇
- 第 20 章 静态方式逆向应用
- 第 21 章 动态调试 smali 源码
- 第 22 章 IDA 工具调试 so 源码
- 第 23 章 逆向加固应用
- 第 24 章 逆向应用经典案例分析
- 第 25 章 Android 中常见漏洞分析
- 第 26 章 文件加密病毒 Wannacry 样本分析
25.1 解压文件漏洞分析
25.1.1 漏洞场景
Android 开发过程中会有很多场景中使用到解压缩文件,比如动态加载,可能需要下载 apk/zip 文件,然后在本地做解压工作。还有一些资源在本地占用 apk 包的大小,就也打包成 zip 放到服务端,使用的时候再去服务端下载,本地做解压工作。在 Android 中解压 zip 文件,使用的是 ZipInputStream 和 ZipEntry 类,代码如下所示:
代码看上去很简单,但是这段代码中存在一个问题,就是 zipEntry.getName 方法,这个方法返回的是 zip 文件中的子文件名称,按照正常逻辑,解压这个子文件到本地都是直接用相同的名字即可,但是这里解压 zip 文件存在一个漏洞:zip 文件中的子文件名格式没有格式要求,也就是可以包含特殊字符。但是在 PC 系统中文件名是有限制的,比如 Windows 中,如图 25-1 所示。在 Linux 中,如图 25-2 所示。
图 25-1 Windows 中文件命名限制
图 25-2 Linux 中文件命名限制
这些系统中是不允许文件名包含一些特殊字符的,而在 ZipInputStream/ZipOutput-Stream 类却是可以的。
也就是说使用 ZipOutputStream 类进行压缩文件,可以对文件名不做任何限制,压缩代码也简单:
只用 ZipEntry 类做单个文件压缩:
这里的 ZipEntry 可以指定随意的名称,而这个名称就是文件在 zip 文件中的文件名。那么如果 zip 包被人恶意的拦截,然后进行修改,这里可以使用 ZipInputStream/ZipOutputStream 类,写一个简单的小程序,就可以把恶意文件写入到 zip 中。
25.1.2 漏洞原因分析
因为文件名没有限制,所以攻击者可以把恶意文件名称命名为:../../../../data/data/xxx.xxx.x/hacker.dex,因为 Android 是基于 Linux 系统的,在 Linux 系统中../符号代表是回到上层目录,那么这里可以多写几个这个符号,这样就会回到 Android 系统的根目录,然后进入当前应用的沙盒目录下写一个文件了。当然这里只能写入本应用中,而不能写入其他应用。
存在的风险:比如现在知道了一个应用的沙盒数据的详细信息,一些隐私数据存放在 SharedPreferences.xml 中,或者有动态加载机制,需要加载的 dex 文件存放在一个目录中,这时可以利用这个漏洞,把几个恶意文件,命名改成../../../../data/data/xxx.xxx.xxx/shared_pref/info.xml,或者是../../../../data/data/xxx.xxx.xxx/dexfile/dynamic.dex。
这样在使用 ZipEntry 进行解压文件的时候,因为直接使用了 ZipEntry.getName 方法或者文件名,然后直接释放解压到本地了,所以就相当于替换了本应用的沙盒数据,这也是利用了 App 本身的权限来写入沙盒数据。
25.1.3 漏洞案例分析
上面分析完了漏洞,下面就用一个简单的例子来看看问题吧,从上面的分析知道,在本地系统中命名这样特殊格式的文件,在进行压缩成 zip 文件是不行的,因为系统不支持这种命名格式,所以这里需要写一个小程序,把这个特殊的文件名的文件压缩成 zip,便于测试,然后再进行解压,如下所示:
先进行压缩文件,方便测试,产生一个 demo.zip 文件,然后再进行解压验证漏洞问题,这里验证问题的重点是:
这里把 zip 中需要解压的文件名前加上前缀:../../../data/data/cn.wjdiankong.androidzipleakdemo/这样解压之后的目录就在本应用的沙盒中了,注意../这样的符号不要太多,只要能回到根目录就可以了。
这里为了方便,直接使用 echo 命令,写入 aaa 内容到 demo.txt 文件中,然后点击压缩,再次查看,多了 demo.zip 文件:
这里就把 zip 中的恶意文件 demo.txt 释放到应用的沙盒中了,如果这个文件是 dex 或者其他文件,替换原来应用的一些重要文件,那么后果会很严重。
25.1.4 漏洞修复
上面了解到了漏洞产生的主要原因,由于 ZipEntry 在进行文件压缩时名称没有做任何限制,而在 Android 系统中../这种特殊符号代表的是回到上层目录,又因为这个解压工作在本应用中,可以借助 App 的自身权限,把恶意文件名改成:../../../data/data/...,即可在解压的时候把文件解压到了应用的沙盒中。
其实问题在于最后一步解压,因为不会去修改解压之后的文件名,默认都是直接解压即可。那么修复这个漏洞问题很简单了,有很多种方式,核心就是不要让有特殊字符,比如:../的文件成功解压,或者解压到本地文件名称不能包含这种特殊字符,代码如下:
上面分析了现在应用很多都有从服务端下载 zip 文件,然后在本地进行解压的功能,在解压的过程中默认不会去进行文件名的操作,所以就存在一些特殊字符的文件名被释放到了本地,从而产生安全问题。这里有一个前提,就是需要下载的 zip 文件被攻击者拦截到了,并且替换了。那么如果在下载的过程中就做一层安全其实也是可以的,比如使用 HTTPS 协议,然后再结合文件的 MD5 比对功能,就可以防止 zip 包被人拦截替换了。本地也就不会存在这样的风险了。
现在 Android 中动态加载技术和插件化开发已经很普遍了,但是在下载这个阶段一定要做好防护工作。如果你的项目现在正好有解压 zip 的功能,请尽快去审查一下项目中解压有没有做防护,没有的话就尽快加上吧!
25.1.5 漏洞总结
本章前面介绍了一个不起眼的漏洞,但是隐藏着很严重的问题,这个漏洞主要是因为如下几点综合产生的:
·ZipEntry 对压缩文件名没有特殊要求。
·在 Android 系统中../特殊字符代表着回到上级目录。
·借助本应用的权限,把数据写入沙盒中。
关于这个漏洞的修复,Google 一直没有做,只是在 API 中做了提醒:
可以看到 Google 对该方法给出了一个安全提示,提示开发者如果该方法的返回值中包含有“../”跳转符,需要特别注意不要将文件写到了目标文件夹之外。如果不对“../”跳转符做过滤,就有可能遍历目录,在解压 zip 文件时以本 App 的权限覆盖任意文件。
项目下载:http://download.csdn.net/detail/jiangwei0910410003/9594958
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论