During my research, i took a look at Kies. Kies is "Samsung's iTunes" which enable sync, update and backup of media/contacts/… between the device and a computer, but also system upgrades.

The Kies application can be found at /system/app/Kies.apk. The executable code is located under the same directory but as an .odex file (/system/app/Kies.odex), which is an optimized version of the original .dex file.

In order to analyse this application, you need to deodex (get a .dex file from an .odex file) the application to use tools like dex2jar on it. This can be achieved like this:

$ adb pull /system/app/Kies.odex $ adb pull /system/framework $ java -jar baksmali.jar -x Kies.odex -d framework/ -o Kies $ java -jar smali.jar Kies -o Kies.dex

After that, you can decompile the .dex normaly using tools like dex2jar:

$ ./dex2jar.sh Kies.dex

Analysing the AndroidManifest.xml file of the application reveals the following informations:

As we can see, the application has the INSTALL_PACKAGES permission and exports the kies_receiver component which is a BroadcastReceiver handling the following actions:

android.intent.action.UMS_CONNECTED

com.intent.action.KIES_APP_START

com.intent.action.KIES_APP_STOP

com.intent.action.KIES_GET_LOCK_STATUS

com.intent.action.KIES_MAKE_BACKUP_APK

com.intent.action.KIES_MAKE_BACKUP_LIST

com.intent.action.KIES_REQUEST_BACKUP_SPACE

com.intent.action.KIES_REQUEST_RESTORE_FINISH

com.intent.action.KIES_SET_RESTORE_STATUS

com.intent.action.KIES_START_RESTORE_APK

com.intent.action.SVC_IF_PGM

The com.intent.action.KIES_START_RESTORE_APK suggests the installation of an APK in order to restore it, which is our goal. The source code of the function shows that each action is matched and the right function is called based on the used action.

package com . sec . android . Kies ; import android . content . BroadcastReceiver ; import android . content . ComponentName ; import android . content . Context ; import android . content . Intent ; import android . util . Log ; public class kies_receiver extends BroadcastReceiver { private void StartKiesService ( Context paramContext ) { Intent localIntent1 = new Intent (); Intent localIntent2 = localIntent1 . setClassName ( "com.sec.android.Kies" , "com.sec.android.Kies.kies_start" ); ComponentName localComponentName = paramContext . startService ( localIntent1 ); } private void StartKiesService ( Context paramContext , byte [] paramArrayOfByte1 , byte [] paramArrayOfByte2 ) { Intent localIntent1 = new Intent (); Intent localIntent2 = localIntent1 . putExtra ( "head" , paramArrayOfByte1 ); Intent localIntent3 = localIntent1 . putExtra ( "body" , paramArrayOfByte2 ); Intent localIntent4 = localIntent1 . setClassName ( "com.sec.android.Kies" , "com.sec.android.Kies.kies_start" ); ComponentName localComponentName = paramContext . startService ( localIntent1 ); } public void onReceive ( Context paramContext , Intent paramIntent ) { ... if ( paramIntent . getAction (). toString (). equals ( "com.intent.action.KIES_START_RESTORE_APK" )) { kies_start . m_nKiesActionEvent = 15 ; int i3 = Log . w ( "KIES_START" , "KIES_ACTION_EVENT_SZ_START_RESTORE_APK" ); byte [] arrayOfByte11 = new byte [ 6 ]; byte [] arrayOfByte12 = paramIntent . getByteArrayExtra ( "head" ); byte [] arrayOfByte13 = paramIntent . getByteArrayExtra ( "body" ); byte [] arrayOfByte14 = new byte [ arrayOfByte13 . length ]; int i4 = arrayOfByte13 . length ; System . arraycopy ( arrayOfByte13 , 0 , arrayOfByte14 , 0 , i4 ); StartKiesService ( paramContext , arrayOfByte12 , arrayOfByte14 ); return ; } ... } }

When an intent with com.intent.action.KIES_START_RESTORE_APK is received by kies_receiver, it sets the m_nKiesActionEvent member of kies_start component to 15, gets the head and body extras and calls StartKiesService.

StartKiesService() start kies_start service with head and body extras in his intent. Via the Context.startService() call, the onCreate() method of kies_start is called. It calls the select_action() method, which will select the right method to be called based on m_nKiesActionEvent set previously by kies_receiver. In our case, m_nKiesActionEvent is set to 15 and select_action() will call process_action_event_start_restore_apk().

Inside process_action_event_start_restore_apk(), AppRestore.packageNameCheck("/sdcard/restore/","/data/app/") is called. This function takes the files present in /sdcard/restore directory, and for each of them which have .apk as extension, checks if it’s not already present in /data/app -- that would mean that the application is already installed and doesn't need to be restored.

When a file present in /sdcard/restore is already installed on the device, it seems to make packageNameCheck return and nothing happens. Otherwise, the APK files present in /sdcard/restore will be installed via PackageManager.installPackage() method.

Oh wait, to successfuly exploit this vulnerability we have to possess the WRITE_EXTERNAL_STORAGE permission. Because we need to be able to write the APK of our choice inside /sdcard/restore and delete files already present in order to escape the case having an APK already installed on the device.