22 Nov, 2011

Kindle Fire Security, Part II- ADB, DropBox Manager

by Ken Johnson

Another day, another short post detailing some other interesting things about the Kindle Fire. After only a day on the market, it was already rooted.  Here’s a link to how it’s done:  http://forum.xda-developers.com/showthread.php?t=1348830

So, the two highlights of this post: 

Aside from the fact that the Fire shipped with KNOWN exploits present (as many devices sadly do), something else caught my attention through it all: ADB is enabled by default, and users have no way to disable it through the UI. Unlike other Android devices that at least force users to make a conscious decision to leave it enabled at all times, the Fire opts you in. For anyone that’s not familiar with ADB, it stands for the Android Debug Bridge.  It’s used for debugging, testing, and poking around on a device.  Anyone that can follow the steps within the XDA Developers link, pretty much has access to everything on your device. Even with a locked device. You lose your device = the bad guys win.

Besides everything our apps store and transmit about us, what lurks on the Kindle Fire? Well, let’s fast forward to having a rooted device. This lets us navigate the entire filesystem, including app data directories and other directories only intended for privileged users. Here is the output of running ‘ls -l’ on the / directory:

$ su

su

ls -l

ls -l

dr-x—— root     root              2011-11-17 14:10 config

drwxrwx— system   system            2011-11-20 21:02 dropbox

drwxrwx— system   cache             1969-12-31 19:00 cache

lrwxrwxrwx root     root              2011-11-17 14:10 sdcard -> /mnt/sdcard

drwxr-xr-x root     root              2011-11-17 14:10 acct

drwxrwxr-x root     system            2011-11-17 14:10 mnt

lrwxrwxrwx root     root              2011-11-17 14:10 vendor -> /system/vendor

lrwxrwxrwx root     root              2011-11-17 14:10 d -> /sys/kernel/debug

lrwxrwxrwx root     root              2011-11-17 14:10 etc -> /system/etc

-rw-r–r– root     root         4203 1969-12-31 19:00 ueventd.rc

-rw-r–r– root     root          840 1969-12-31 19:00 ueventd.omap4430.rc

-rw-r–r– root     root            0 1969-12-31 19:00 ueventd.goldfish.rc

drwxr-xr-x root     root              2011-11-15 17:24 system

drwxr-xr-x root     root              2011-11-17 14:10 sys

drwxr-x— root     root              1969-12-31 19:00 sbin

dr-xr-xr-x root     root              1969-12-31 19:00 proc

-rwxr-x— root     root        14943 1969-12-31 19:00 init.rc

-rwxr-x— root     root        11357 1969-12-31 19:00 init.omap4430.rc

-rwxr-x— root     root         1677 1969-12-31 19:00 init.goldfish.rc

-rwxr-x— root     root        90116 1969-12-31 19:00 init

-rw-r–r– root     root          118 1969-12-31 19:00 default.prop

drwxrwx–x system   system            2011-11-20 20:41 data

drwx—— root     root              2011-11-05 00:17 root

drwxr-xr-x root     root              2011-11-17 14:15 dev

Hmm, the /dropbox directory seems interesting. Before you get all excited and think that this is some type of Dropbox integration, this isn’t it.  This directory is used for DropBoxManager (android.os.DropBoxManager) files, which are generally used for system-wide verbose log storage. Here is what it contains:

cd dropbox

cd dropbox

ls -l

ls -l

drwxrwx— system   cache             2011-11-17 10:11 recovery

-rw——- system   system      50619 2011-11-20 21:02 data_app_crash@1321840952

079.txt.gz

-rw——- system   system      57759 2011-11-20 20:41 system_app_anr@1321839667

379.txt.gz

Of interest in particular (to me, anyway) are the data_app_crash* files.  Whenever an app crashes, a file is written with the errors causing the crash as well as stack traces.  This can include sensitive information in some cases. 

Within the /system/app directory, there is a package called com.amazon.dcp.apk. This application performs metric collection, handles OTA messages, and more. It also interacts directly with files located in the /dropbox directory. It monitors the DropBox service to determine when new entries have been created. This is part of Amazon’s metrics and analysis framework. If you want to call it a backdoor, then go for it. This will be a topic within a future post.

To be fair, the DropBoxManager is widely used on other devices as well. Additionally, lots of juicy stuff does get logged to the global logs on other devices too. But it certainly worth examining as many developers may be unaware of the fact that even though they are not explicitly logging events, additional channels exist for unintended data leakage. 

To examine the com.amazon.dcp application a bit deeper, we need to decompile it.  There are many resources on the web that detail how to do this.  Here are a few:

http://thomascannon.net/projects/android-reversing/

http://jack-mannino.blogspot.com/2010/09/reversing-android-apps-101.html

The latest version of Agnitio has the decompilation steps automated, but uses JAD for decompilation rather than JD-GUI:  http://www.securityninja.co.uk/application-security/agnitio-security-code-review-tool-v2-1-released/  

Additionally, the Android Reversing Toolset is a distro that contains all of the tools mentioned in the blog posts above.   http://threatpost.com/en_us/blogs/android-reverse-engineering-toolset-debuts-110111

We aren’t going to post the source code to Amazon’s applications here, since cease-and-desist letters are no fun. Decompiling it using the resources listed above is EASY.

Every time an application crashes, Amazon dumps the stack trace and other information to a crash file within the /dropbox directory via the DropBox service. The files follow the format of data_app_crash@<time_in_milliseconds>.txt.gz. I’ve observed these files existing for several days without being cleared.  

So the worst part about this: the DropBox service doesn’t support granular per-app permissions for retrieving crash log entries. You merely need the READ_LOGS permission, and any arbitrary application can retrieve the contents of each crash that’s entered into the DropBox. Often, we tell developers that they are safe as long as they aren’t logging sensitive information to the GLOBAL logs. What we leave out is that information such as crash logs (that aren’t globally logged) may be inadvertently leaked out via other unexpected channels.     

To connect to the DropBox service used on the Kindle Fire, we can create a new DropBoxManager and get an entry with the following snippet of code:

DropBoxManager mDropBoxMan = ((DropBoxManager) context

                                   .getSystemService(“dropbox”));

DropBoxManager.Entry localEntry = mDropBoxMan.getNextEntry(null, 0);

With access to the DropBoxManager, we can list entries.  With the entry we just retrieved, we can retrieve the body of the message with the following:

InputStream inStream = localEntry.getInputStream();

BufferedReader reader = new BufferedReader(

                              new InputStreamReader(inStream));

String line = ““;

String logData = ““;

while ((line = reader.readLine()) != null) {

          logData += line;

  }

  

If we want to iterate through every entry within the DropBoxManager, we need to get the time in milliseconds of the last entry, and pass that into our next request. The easiest way to do this is to wrap the code above within a do-while block:

DropBoxManager mDropBoxMan = ((DropBoxManager) context

                                   .getSystemService(“dropbox”));

DropBoxManager.Entry localEntry = mDropBoxMan.getNextEntry(null, 0);

do {

     try {

          InputStream inStream = localEntry.getInputStream();

          BufferedReader reader = new BufferedReader(

                                        new InputStreamReader(inStream));

          String line = ““;

          String logData = ““;

          while ((line = reader.readLine()) != null) {

                    logData += line + “\n”;

          }

     } catch (IOException e) {

     }      //do something with the data here

} while ((localEntry = mDropBoxMan.getNextEntry(null,

               localEntry.getTimeMillis())) != null);

A malicious application on the Kindle Fire with just the READ_LOGS permission and INTERNET, can intentionally crash other applications, retrieve the logs, and exfiltrate them. How? Easy: explicit Intents with malformed or unexpected data sets. There are many ways to interact with other components, but this one is easy to illustrate. Any application can instantiate the Activity of another application provided it is either exported or has at least one Intent Filter in place. If there are permissions required to start a specific Activity, then that application would also need that permission to start it. By calling a specific Activity and sending it unexpected data or while in an unexpected state, in some scenarios it may be possible to intentionally dump information of interest to the crash logs. Also, applications do crash on their own. A malicious app has access to any and all crash logs.

We can call a package named com.nvisium.crashdummy with an Activity class called CrashActivity. The resulting Activity would crash as a resulting of a missing value within the Bundle passed within the Intent. The code for this is below:

ComponentName toLaunch  = new  ComponentName(

               “com.nvisium.crashdummy” ,

               “com.nvisium.crashdummy.CrashActivity”);

Intent intent  = new  Intent(“android.intent.action.VIEW”);

Bundle bundle  = new  Bundle();

bundle . putString(“userName” ,“superman”);

intent . setComponent(toLaunch);

intent . setFlags(Intent . FLAG_ACTIVITY_NEW_TASK);

getApplication().startActivity(intent);

Combining the ability to crash other apps on demand with the ability to instantly retrieve that data, this is a serious problem in my opinion. 

As Stewey would say,  http://www.youtube.com/watch?v=yaXHUk8Jh0c

Stay tuned for Part III, coming soon.