Hello everyone, long time no see! Now begins a series of blog posts about bugs I found before and now on Android vendors, including memory corruption and logical bugs, reported and fixed via Pwn2Own or official bug channel.
This very first post is about the chain of bugs we used in the end of 2017 to get remote arbitrary application install via clicking malicious link on newest Galaxy S8 at that time, prepared for Mobile Pwn2Own, with a V8 bug to get initial code execution in sandbox and 5 logical bugs to finally get arbitrary application install, with demo video. All bugs were reported and assigned CVE-2018-10496, CVE-2018-10497, CVE-2018-10498, CVE-2018-10499, CVE-2018-10500, CVE-2018-9140. The detail of the V8 bug will be covered in another post.
(Chinese version here)
Bug 0: Pwning and Examining the browser’s renderer process
Using the first V8 bug (CVE-2018-10496, credit to Gengming Liu and Zhen Feng of KeenLab), we have get initial code execution in the Samsung Internet Browser isolated process. Isolated process is heavily restricted in android, both in SElinux context and traditional DAC permission.
Doing a quick check on the SELinux profile reveals Samsung doing a good job. No additional service attack surface revealed. The sandbox process is still limited to access very few services and IPCs, e.g. starting activity is prohibited.
For those who are interested in the Chrome browser sandbox architecture, you can refer to my CanSecWest presentation. Given Samsung did not open loophole for us to directly exploit from isolated context, we fall back to the good old ways to attack the browser IPC.
The Samsung Internet Browser has a quite different UI than Chrome but its core is still largely based on Chrome, so as the sandbox architecture. Looking over the past always gives us insight over future, which is quite true for ….
Bug 1: The Tokyo treasure: incomplete fix for CVE-2016-5197
Old readers will remember the good old Chrome IPC bug we used to pwn Pixel, as described here. Looking back into the fix…:
https://chromium.googlesource.com/chromium/src.git/+/abd993bfcdc18d41e5ea0f34312543bd6dae081e%5E%21/#F0
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 tries to fix the vulnerability by adding scheme check, restricting the string IPC accepts so that we cannot use this IPC to start arbitrary explicit activity anymore.
However, a crucial part is missing: intent resolution does not depend solely on scheme part. As long as the incoming argument contains component
keyword, which will be parsed first, we can still use this IPC to send an explicit intent – starting arbitrary exported activity. So trivially adding "scheme=geo" will bypass this fix. Samsung Internet Browser shares the same source so it’s also affected.
Of course due to the limitation of parseUri
, we can only craft an Intent with string arguments (no fancy parcelable possible). Now we need to find a privileged application with activity exported and accepts and happily opens malicious URL or execute malicious Javascript in it’s webview.[1] As long as we pwned the webview, we pwned the application.
This bug is also tracked by Google under b/804969. Since in an unrelated refactor Chrome removed this IPC completely, this issue does not affect newest Chrome but still affect all downstream browsers which shares this code. Samsung does not assign a particular CVE for this issue but assigned the whole chain CVE-2018-9140/SVE-2017-10747.
Bug 2: The Email loves EML with a … XSS
Searching through the privileged applications we find Samsung Email.
The exported com.samsung.android.email.ui.messageview.MessageFileView
activity accepts eml file. What’s an eml file? EML is a dump format of email and seems Samsung Email is kindly enough to provide rich-text support for EML files – by rendering it in a Webview.
Of course it immediately pops up questions for a security researcher, XSS, script injection, etc. In our case, it means code execution. In CVE-2015-7893 Natalie had pointed out a similar issue so checks were added, but far from enough. It still does not have sufficient input validation in the EML file except simple filtering for <script>
. We can just inject document.onload=blablaba
, and construct script element on the fly, to bypass the fix, and get arbitrary script execution.
This issue is assigned CVE-2018-10497.
Bug 3: … And file:/// crossdomain
Although we have had an exploit theory in step 2, bundling lots of javascript exploit in the EML file itself creates trouble in heap fengshui and ruins our success rate. Luckily the webview configuration in Email allows us to access file:/// from file domain (i.e. setAllowFileAccessFromFileUrls), which enables us to shift the exploit to a single js file and minimizing the EML file, largely improving stability. Bonus point: this vulnerability combined with Bug 2 alone already allows us to read Email’s private file.
This issue is assigned CVE-2018-10498.
So now the EML file becomes like:
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">--<br>Bill Jncjkqfuck<br>
</body>
--bcaec54eecc63acce604a3050f77--
By exploiting our V8 js bug bundled in the malicious EML again, we can get code execution in Email application, officially jumping out of sandbox. What is nice for us is that the Email application holds lots of precious application like capable of accessing photos, contacts, etc, which already meets Pwn2Own standard.
Given this attack surface, our sandbox-escaping exploit chain now contains the following steps:
- Force the browser to download the EML file with exploit code bundled. The download path is predictable like
/sdcard/Download/test.eml
and/sdcard/Download/exp.js
- In the compromised renderer process, craft an IPC with content
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
, calling up and exploiting the email application. - We now owns the Email process privilege
Bug 4: Go beyond the Galaxy (Apps) … but blocked?
To achieve the ultimate goal of installing arbitrary application, our next step is trying to pwn a process with INSTALL_PACKAGES
privilege. An obvious target is the Galaxy Apps, which is the app store for Samsung phones.
Digging into the APK file we find a promising Activity named com.samsung.android.sdk.ppmt.PpmtPopupActivity
, which directly accepts and opens URL in it’s webview from intent. However this obvious target is of course protected.
…protected from other process but not protected from inside.
This issue is assigned CVE-2018-10500.
Bug 5: Push SDK pushes vulnerability
On auditing the Samsung platform apps, the same component com.sec.android.app.samsungapps/com.samsung.android.sdk.ppmt.PpmtReceiver
and com.samsung.android.themestore/com.samsung.android.sdk.ppmt.PpmtReceiver
appears many times. Turns out it’s an SDK responsible for campaign message pushing and processing. In PpmtReceiver
‘s source code, we find the following interesting snippets:
//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;
//....
We can see it’s possible to start an activity with arbitrary arguments/components fully controlled by us, and Galaxy Apps
is one of the users of Ppmt push sdk, exposing the PpmtReceiver
. We use this vulnerability to indirectly start PpmtPopupActivity
, PpmtPopupActivity
will happily load any URL we passed in. Reusing the JS exploit, we again get a shell in Samsung Appstore, which has INSTALL_PACKAGE
permission, allowing us to install any rogue application. An interesting point is that the activity does not have any explicit UI pointing to it so I guess it’s some common SDK that forgot to be removed.
This issue is assigned CVE-2018-10499.
Chaining it altogether
Combining it all together we have the following figure:
So this is how we pwned the Galaxy S8. Demo video has been posted at https://www.youtube.com/watch?v=UXLWk2Ya_6Q&feature=youtu.be at that time. All issues have been fixed by vendor.
Due to the nature of this bug chain, we named it "Galaxy Leapfrogging" as each step of the chain is to find a new app to jump & pwn to gain additional privilege. All vulnerabilities have been tested on the newest Galaxy S8 at that time, samsung/dreamqltezc/dreamqltechn:7.0/NRD90M/G9500ZCU1AQF7:user/release-keys.
We would like to thank Samsung Mobile Security for their work on fixing these vulnerabilities, and I’d like to thank all former colleagues at KeenLab for our work together and the good old days.
Next
Following posts will be about other various security bugs I found on those Android vendors, stay tuned! My twitter: https://twitter.com/flanker_hqd
Note: Current status of isolated Webview
[1] Beginning with Android O, all apps by default runs their system webview in isolated context, which greatly stops "Leapfrogging". However, some apps are still running their own webview core like X5 and tbs in the same context, which still poses great risks and remains an attack surface
Pingback: Galaxy Leapfrogging: Pwning the Galaxy S8 - ZRaven Consulting