作者:Flanker
公眾號:Galaxy Leapfrogging 蓋樂世蛙跳 Pwning the Galaxy S8

在最近的一系列文章中,我會介紹這些年以來通過Pwn2Own和官方渠道所報告的在各種Android廠商設備中發現的各種CVE,包括通過fuzz和代碼審計發現的各式各樣的內存破壞漏洞和邏輯漏洞。第一篇文章將會介紹在2017年末我們用來遠程攻破Galaxy S8并安裝應用的利用鏈,一個V8漏洞來獲取最開始的沙箱內代碼執行,和五個邏輯漏洞來最終實現沙箱逃逸和提權來安裝任意應用,demo視頻可以在這里看到。

所有的漏洞均已經報告并以CVE-2018-10496,CVE-2018-10497,CVE-2018-10498,CVE-2018-10499,CVE-2018-10500來標示。本文將主要介紹整個利用鏈,V8漏洞將在另外的文章中介紹。

Bug 0: Pwning and Examining the browser’s renderer process

通過第一個V8漏洞(CVE-2018-10496,credit to Gengming Liu and Zhen Feng),我們現在獲得了在三星瀏覽器renderer沙箱的代碼執行。眾所周知這是一個isolated process。Isolated process是安卓中權限最低的進程,被傳統的DAC權限和SELinux context policy所嚴格限制。 sbrowser processes 那么在S8上相應的policy會不會有問題?通過反編譯S8的SELinux policy,我們很遺憾地發現三星在這塊還是做了不錯的工作,相比于原版Android沒有增加任何的額外allow policy。也就是說isolated進程仍然只能訪問很少量的service和IPC,更別提啟動activity之類的了。 SELinux access vectors 對于想從頭了解三星瀏覽器(或者說Chrome瀏覽器)沙箱架構的讀者朋友,可以參考我之前在CanSecWest上的PPT,相應內容在此就不再贅述。鑒于看起來三星并沒有對isolated process增加額外的供給面,我們還是需要用old-fashion的辦法 – 審計瀏覽器IPC。三星瀏覽器雖然在界面上和Chrome看起來大相徑庭,但本質上還是Chromium內核,對應的沙箱架構也和Chrome一致。 前事不忘后事之師。說到IPC漏洞,我們就會想到當年東京文體兩開花中日合拍的…

Bug 1: 東京遺珠: CVE-2016-5197修復不完全可被繞過

老讀者們應該都還記得之前東京我們用來攻破Pixel的CVE-2016-5197,具體內容可以在這里看到。回顧當年Google給出的補丁

public class ContentViewClient {
 public void onStartContentIntent(Context context, String intentUrl, boolean isMainFrame) {
 //...
@@ -144,6 +148,14 @@
         // Perform generic parsing of the URI to turn it into an Intent.
         try {
             intent = Intent.parseUri(intentUrl, Intent.URI_INTENT_SCHEME);
+
+            String scheme = intent.getScheme();
+            if (!scheme.equals(GEO_SCHEME) && !scheme.equals(TEL_SCHEME)
+                    && !scheme.equals(MAILTO_SCHEME)) {
+                Log.w(TAG, "Invalid scheme for URI %s", intentUrl);
+                return;
+            }
+
//...
        try {
            context.startActivity(intent);
        } catch (ActivityNotFoundException ex) {
            Log.w(TAG, "No application can handle %s", intentUrl);
        }
    }

Google的修復是對該IPC接受的intent string做了檢查,只有特定scheme的intent才能通過,意圖是只允許geo://,tel://和mailto://等隱式intent,從而禁止再傳遞顯式string來啟動activity。 然而這個修復漏掉了關鍵的部分:intent解析并不是只依賴于scheme部分,component參數的優先級遠高于scheme解析。我們只要在之前的攻擊payload頭部添加”scheme=geo”,同時依然保持component,即可既繞過這個check,又繼續在renderer沙箱中通過這個IPC啟動任意activity,繼續利用這個漏洞。如之前所述,三星瀏覽器是chromium內核,那么也包含相同的漏洞代碼。 Jumping from renderer sandbox 當然受到parseUri參數的限制,我們構造出的intent只能含有string和其他基本類型參數,不能包含一些fancy的parcelable,這對后續攻擊面選擇提出了要求。這個activity需要能滿足如下條件

  • 導出并會在webview中加載或執行攻擊者通過intent指定的url或javascript
  • 接受基本參數類型,對parcelable沒有強制檢查

只要我們能在App的webview中執行任意代碼,我們就獲得了這個應用的權限。 [注1]

這個漏洞在報告后,Google分配了issue 804969。幸運的是,Chrome在這個漏洞被報告前的一次無關的代碼refactor中,把這個IPC整個全部去掉了… 故Chrome官方認為此問題已經不存在了,但是所有下游的Chromium內核瀏覽器都仍然受影響。一個奇葩的操作是三星并沒有為這個漏洞單獨分配CVE,而是在各個bug單獨的CVE之外,又分配了CVE-2018-9140/SVE-2017-10747給整個利用鏈。

Bug 2: The Email loves EML with a … XSS

在檢索所有權限較高的應用過程中,我們發現了Samsung Email和它所導出的一個有趣的Activity。 Email activity 導出的com.samsung.android.email.ui.messageview.MessageFileView會在intent參數中接收并解析EML文件。什么是EML文件?EML文件是一個電子郵件導出格式,Samsung Email對EML文件提供了非常完善的富文本支持 – 完善到直接用Webview來加載和渲染。這當然立即勾起了一個安全研究員的興趣:這是否意味著接下來有XSS、腳本注入,以及對于我們的場景,代碼執行的可能性。 Project Zero的Natalie在CVE-2015-7893中報告了一個類似的漏洞,在此之后三星增加了一些檢查。然而就像所有的漏洞修復第一次經常可能修不完一樣,這個檢查做的非常粗糙,粗糙到是對<script>關鍵字的匹配。我們只需通過img src document.onload=blablaba并動態引入script即可繞過,從而導致XSS。 這個漏洞被分配了CVE-2018-10497。

Bug 3: … 以及 file:/// 跨域

雖然在Bug 2中我們證實了這個XSS確實存在,但通過這個XSS引入js exploit并獲得代碼執行權限(shell)還有一些問題。典型的是EML文件本身如果太大,將會影響WebView的堆布局,進而導致堆風水的成功率降低。但是Email應用并沒有讓我們失望,它開啟了setAllowFileAccessFromFileUrls,這意味著我們可以將js exploit拆分到單獨的文件中,通過script src的方式引用,進而盡可能縮小EML文件的體積來提高V8漏洞的成功率。 一個小tip:Bug2和Bug3組合在一起,已經可以任意讀取Email的私有文件了。 這個漏洞被分配了CVE-2018-10498 所以我們現在構造如下所示的樣例攻擊EML文件:

MIME-Version: 1.0
Received: by 10.220.191.194 with HTTP; Wed, 11 May 2011 12:27:12 -0700 (PDT)
Date: Wed, 11 May 2011 13:27:12 -0600
Delivered-To: jncjkq@gmail.com
Message-ID: <BANLkTi=JCQO1h3ET-pT_PLEHejhSSYxTZw@mail.jncjkq.com>
Subject: Test
From: Bill Jncjkq <jncjkq@gmail.com>
To: bookmarks@jncjkq.net
Content-Type: multipart/mixed; boundary=bcaec54eecc63acce904a3050f79
--bcaec54eecc63acce604a3050f77
Content-Type: text/html; charset=ISO-8859-1
<body onload=console.log("wtf");document.body.appendChild(document.createElement('script')).src='file:///sdcard/Download/exp.js'>
<br clear="all">--
Bill Jncjkqfuck

</body>
--bcaec54eecc63acce604a3050f77—

通過在EML中捆綁V8 exploit并通過intent使Email打開,我們可以成功在Email進程中執行代碼獲得其權限,從而正式跳出renderer進程的isolate沙箱。Email應用本身具備讀取相片、通訊錄的權限故到這里我們已經滿足了Pwn2Own的初步要求。截至目前,我們的攻擊鏈步驟如下:

  1. 通過http header頭attachment的方式強迫瀏覽器將含有攻擊代碼的EML文件和js文件下載。在安卓上,下載路徑固定于例如/sdcard/Download/test.eml/sdcard/Download/test.js中。
  2. 在獲得renderer進程權限后,構造并調用brokerer IPCstartContentIntent,傳入參數為intent:#Intent;scheme=geo;package=com.samsung.android.email.provider;component=com.samsung.android.email.provider/com.samsung.android.email.ui.messageview.MessageFileView;type=application/eml;S.AbsolutePath=/sdcard/Download/test.eml;end,從而喚起并exploit Email應用的webview
  3. 成功獲取Email應用進程權限

Bug 4: Go beyond the Galaxy (Apps) … but blocked?

以上結果雖然能滿足Pwn2Own的初步要求,但是我們的終極目標是要能夠任意安裝應用,而Email顯然沒有這個權限。我們的下一步就是需要找到一個具有INSTALL_PACKAGES權限的進程或應用來作為目標。顯而易見,Galaxy Apps(三星應用商店)是一個目標。這個應用中有一個非常有潛力的Activitycom.samsung.android.sdk.ppmt.PpmtPopupActivity,非常直接地接收intent傳入的url參數,沒有對來源做任何校驗就在webview中打開。 不過天上不會掉餡餅,顯然這個Activity被保護了 – 不導出。 … 但只是對外保護,不是對內保護

Bug 5: Push SDK pushes vulnerability

在審計三星平臺其他App的過程中,我們發現同樣的component com.sec.android.app.samsungapps/com.samsung.android.sdk.ppmt.PpmtReceivercom.samsung.android.themestore/com.samsung.android.sdk.ppmt.PpmtReceiver出現在了多個應用,包括Galaxy Apps中。通過分析其功能我們認為這應該是一個私有push SDK,用于一些廣告、活動通知相關的推送。這些receiver都是導出的,在PpmtReceiver的相關代碼中,我們發現了如下有意思的代碼片段:

//The Ppmt receiver seems responsible for push message, and under certain intent configuration, it routes to path 
    private void a(Context arg5, Intent arg6, String arg7) {
        if("card_click".equals(arg7)) {
            CardActionLauncher.onCardClick(arg5, arg6);
            return;
        }
//in onCardClick, it reaches CardActionLauncher, 
    private static boolean a(Context arg2, String arg3, CardAction arg4) {
        boolean v0;
        if("app".equals(arg4.mType)) {
            v0 = CardActionLauncher.b(arg2, arg3, arg4);
        }
//If the CardAction.mType is "intent", we finally reaches the following snippet:
private static boolean d(Context arg5, String arg6, CardAction arg7) {
        boolean v0 = false;
        if(TextUtils.isEmpty(arg7.mPackageName)) {
            Slog.w(CardActionLauncher.a, "[" + arg6 + "] fail to launch intent. pkg null");
            return v0;
        }
        Intent v1 = new Intent();
        v1.setPackage(arg7.mPackageName);
        if(!TextUtils.isEmpty(arg7.mData)) {
            v1.setData(Uri.parse(arg7.mData));
            v1.setAction("android.intent.action.VIEW");
        }
        if(!TextUtils.isEmpty(arg7.mAction)) {
            v1.setAction(arg7.mAction);
        }
        if(!TextUtils.isEmpty(arg7.mClassName)) {
            v1.setComponent(new ComponentName(arg7.mPackageName, arg7.mClassName));
        }
        if(arg7.mExtra != null && !arg7.mExtra.isEmpty()) {
            v1.putExtras(arg7.mExtra);
        }
        CardActionLauncher.a(v1, arg6);
        try {
            switch(arg7.mComponent) {
                case 1: {
                    int v2 = 268435456;
        try {
            v1.setFlags(v2);
            arg5.startActivity(v1);
            goto label_78;
    //….

通過這段代碼,我們可以通過發送broadcast以任意參數指定任意Activity啟動,當然包括Galaxy Apps內部未導出的Activity。我們通過這個漏洞來間接啟動之前提到的PpmtPopupActivity,進而加載含有JS exploit的攻擊頁面,從而獲得Galaxy Apps的權限(shell),利用它的INSTALL_PACKAGES權限來安裝任意應用。一個有意思的地方是,這個Activity本身并沒有直接的UI指向它,所以猜測這能是一個廢棄的SDK,但忘記被去掉了。 這個漏洞被分配了CVE-2018-10499.

Chaining it altogether

Whole escape chain 這就是我們攻破Galaxy S8的完整利用鏈。所有的漏洞均已在當時及時報告給了廠商并得到了修復。鑒于這個漏洞利用鏈每一步都是在尋找更高權限的進程或應用來作為跳板進行攻擊的特點,我們將它命名為”Galaxy Leapfrogging” (蓋樂世蛙跳)。完成攻破的Galaxy S8為當時的最新版本samsung/dreamqltezc/dreamqltechn:7.0/NRD90M/G9500ZCU1AQF7:user/release-keys.

在此感謝Samsung Mobile Security在修復漏洞中作出的工作,和騰訊科恩實驗室以及科恩實驗室的前同事們。 接下來還會有其他各大Android Vendor的各式CVE writeup,請保持關注。Weibo: flanker_017 .

注1: isolated webview的當前狀態

從Android O開始,所有的應用在缺省狀態下均在isolated context運行webview,也就意味著攻破了webview不再意味著直接獲取應用的權限,從而極大地阻止了我們的蛙跳戰術。但部分用戶量非常大的App(在此不直接點名),使用了自己編譯的webview或第三方通用瀏覽服務提供的webview,例如X5/tbs和ucwebcore,而截至目前這些webview即使在最新版本Android上面仍然沒有啟用isolated限制,也意味著他們仍然是蛙跳戰術巨大而明顯的目標。


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1050/