One of the most commonly exploited ways to escalate privileges from within a local context is to abuse discrepancies and inadequacies in the way filesystem permissions—or access rights—are set up in an operating system. There are countless instances of vulnerabilities and privilege escalation attack methods that abuse file permissions, be it the setuid
flag on a globally executable vulnerable binary, such as su
or symlink
, or the race condition attack on a file that is globally readable and written to by a superuser-owned application; for example, pulse audio CVE-2009-1894.
Being able to clearly identify any potential entry points presented by the filesystem is a good place to start defining the Android native attack surface. The walkthrough in this section details a few methods you can use to find dangerous or potential files that possibly enable exploitation while interacting with the device through an ADB shell.
Seeing that the following tutorial is focused on detailing ways to find files with inadequate or discrepant permissions, a fundamental skill you require in order to understand why certain commands are executed would be to understand how Linux- or Unix-based operating systems define file permissions. A quick side note: it's common in some Linux circles to talk about file and directory permissions as access rights; here, these terms will be used interchangeably.
Linux- or Unix-based operating systems' file permissions are defined in terms of the following:
o
) of the file that don't fall into the other user categoriesu
)g
)Categorizing users in this way allows mutual exclusivity, enabling a user to fine-tune who has access to the file. This means specification of access rights can be done with respect to the file and every likely user.
For each collection of users (group, other users, and the owner), five attributes of access control are defined, namely:
Each of these are defined in terms of either mnemonics—using abbreviations—or as the literal bitwise values encoded in octal format. For first timers, this may be a confusing description, which is why this section includes a small table that defines the values, both in binary and octal (numbers in base 8).
Why base 8? Well, because base 8 in binary allows space for three bits, each one describing the Boolean value of each of the attributes; 1
for on (or true) and 0
for off (or false):
Description |
Binary value |
Decimal value |
---|---|---|
Read |
100 |
4 |
Write |
010 |
2 |
Execute |
001 |
1 |
These are combined by adding the binary values. Here is a table that describes that:
Description |
Read |
Write |
Execute | |||
---|---|---|---|---|---|---|
Read |
100 |
4 |
110 |
6 |
101 |
5 |
Write |
010 |
2 |
011 |
3 | ||
Execute |
001 |
1 |
These are specified for each collection of users; this means the permission has one bit for each user as well, seeing that there are three collections, namely the file owner, the group, and other users—commonly referred to as "the world". The permission bits also include an extra bit for the definition of setuid
, setguid
, and the
sticky bit.
The sticky bit is an access right that allows only the owner of a file or directory to delete or rename a file or directory. When specified, it appears as a T
symbol in the access right bits displayed by the ls
command.
The structure looks as follows:
Owner |
Group |
Other | ||||||
---|---|---|---|---|---|---|---|---|
r |
w |
x |
r |
w |
x |
r |
w |
x |
That's pretty much it as far as the basics of file access rights go; if you've followed the previous paragraphs carefully, you should have enough to spot the most fundamental flaws when it comes to Android's native access rights.
In order to properly appreciate the discrepancies that vendors add to device builds, you will need to know a little bit about what the "default" or standard Android filesystem looks like in terms of its structure and access permissions setup.
Here's the summary of the default or standard filesystem folders and their purposes according to the Linux filesystem hierarchy standard and the init.rc
scripts on Jelly Bean. References for the init.rc
scripts of other platforms are given in the See also section of the next tutorial Inspecting System Configurations.
Please keep in mind that the vendor builds of the devices may differ; take these to be the most basic, untouched filesystem layouts and purposes. Often, vendors also make mistakes in their usage of some of these file paths and go against their intended purpose, so keep an eye on the purpose of these folders and the default access rights.
This section doesn't go into full detail with the filesystem layout; however, there are some good sources on the semantics, layout, and conventions for Android and Linux filesystems in the See also section.
Let's look at how to hunt for interesting file- or directory-based targets on an Android system. The following walkthrough assumes you have ADB shell permission on the device being assessed.
In order to use the commands mentioned in the following example, you will need to be able to either install the find
binary or Busybox for Android; the instructions for installation can be found at http://www.busybox.net/ and in the Setting up Busybox section of the Automated native Android fuzzing recipe at the end of this chapter.
To search for files with respect to their access rights, you can find a list of readable files by executing the following command in your ADB shell; firstly, for world readable, this command does the trick:
find [path-to-search] –perm 0444 –exec ls –al {} ;
See the following screenshot for the sample output:
The previous screenshot—and the subsequent ones in this section—were taken from a rooted Samsung Galaxy S3. Here the command-line instruction included a redirect to /dev/null
in order to omit the erroneous output caused by permission denial.
Just a little caveat for non-Linux/Unix users
/dev/null
acts like a sort of "blackhole" for output, allowing Linux/Unix users to use it as a place to put output they are not interesting in seeing. As an added benefit, it also returns a value to let you know whether the write operation succeeded.
Moving on, if you're looking for world writable files, you can find them using the following arguments:
find [path-to-search] –perm 0222 –exec ls –al {} ;
See the following screenshot for the sample output:
And for files that have executable permission set for all users:
find [path-to-search] –perm 0111 –exec ls –al {} ;
You aren't explicitly required to use the octal format; the find
command also understands the popular shorthands for user collections and permissions.
For instance, to find files readable to everyone outside of the owner's group, you specify permissions this way:
find [path-to-search] –perm a=r –exec ls –al {} ;
See the following screenshot for the sample output:
The previous specifications will ensure only exact matches; this means files returned must have only the bits specified. If you're looking for files with at least the specified bits set and any of the other bits—which you will probably be doing most of the time—you can specify the permissions by including a -
symbol as a prefix as in the preceding example. For the octal mode, this will work as follows:
find [path-to-search] –perm -444 –exec ls –al {} ;
See the following screenshot for the sample output:
This will at least match files that have read bits set for all user collections, which means the 445, 566, 777, and so on permission bits will be matched. And the 344, 424, 222, and so on would not be matched.
A couple of really useful access right patterns you would probably be interested in looking for include finding executable files with setuid
:
find [path-to-search] –perm -4111 –exec ls –al {} ;
See the following screenshot for the sample output:
In the previous screenshot, we see that the su
binary was found using the preceding command. If you ever find this binary on an Android device, it's always a strong indication that the device has been rooted.
You can also find files with setguid
and execute permissions for all:
find [path-to-search] –perm -2111 –exec ls –al {} ;
See the following screenshot for the sample output:
The find
command also allows you to specify users as part of the search criteria; for instance:
find [path-to-search] –user 0 –exec ls –al {} ;
find [path-to-search] –user 1000 –exec ls –al {} ;
find [path-to-search] –group 0 –exec ls –al {} ;
You may want to get an idea of how much each user—or rather, application—on your Android system has access to, and to do this you may want to build a list of user IDs—or, more importantly, UIDs for applications. The easiest way to do this is to dump the access rights for the files in the /data/data
directory since it contains the data for most of the apps installed on the Android device. However, in order to access this list from an ADB shell, you'll need access to the root or system account or any account that has equivalent permissions; this is easy to obtain on an emulator—it's granted automatically. Alternatively, if you so choose, you could fire off a couple of searches to the XDA developers site to look for a method to root your phone. The XDA developer's site is available at http://www.xda-developers.com/.
There are both good and bad things about rooting your phone; in this case, it allows you to inspect the filesystem and access rights in more detail. However, on the other hand, if access to root privileges are not managed properly, it can expose your phone to a number of very devastating attacks! So be stingy with your root permissions and only temporarily root phones when they need to be rooted.
Moving on, if you list all of the files in the /data/data
directory, you should see the following; this is taken from a Samsung Galaxy S3:
You may notice the odd naming convention for each app, namely u[number]_a[number]
, which means to say u[profile number]
for the user profile the app is installed on—since some Android versions support multiple user profiles, namely everything from Jelly Bean and later—and a[number]
, which is the application ID.
You can use the application ID to construct the actual system user ID (UID) for the app by adding this number to 10000
; for instance, for the Mozilla installation that has a username of u0_a170
, the corresponding UID will be 10170
. To find all of the files that have this UID as its owner, you would then execute this command:
find /data/data/ -user 10170 –exec ls –al {} ; 2> /dev/null
See the following screenshot for the sample output:
You can find other usernames by checking out the Android_filesystem_config.h
file referenced in the See also section of this recipe.
A command that can make the output of the find
command a little more useful is stat
. This command displays properties of the file and allows you to specify the format in which you'd like these details to be displayed. The stat
command has a myriad of features and makes hunting for incorrectly "permissioned" files a much more informative experience than just calling ls –al
via the find –exec
command.
You can use stat
with find
as follows:
find . –perm [permission mode] –exec stat –c "[format]" {} ;
For instance, if you'd like to display the following:
%A
: The access rights in human-readable format%u
: The user ID of the file owner%g
: The group ID of the file owner%f
: The file mode in raw hex%N
: The quoted file name with dereference if it's a symbolic linkYou can do so by executing the following command:
find . –perm [permission] –exec stat –c "%A %u %g %f %N" {} ;
This command produces output as follows—here the example uses -0666
as an example permission mode:
Android_filesystem_config.h
file in the Android Git Repository at https://android.googlesource.com/platform/system/core/+/android-4.4.2_r1/include/private/android_filesystem_config.h3.149.243.18