Monday, December 14, 2015

Attacking Bound Services on Android

Many times when exploring a new Android device, I encounter exported Services that expose a Binder interface, known as "bound Services".  Unlike an unbound Service, we can't just use the `am` command to interact with the Service; rather, we'll need to actually create an Android application.  Creating a client to connect to a bound Service can be tricky even with the Service's source code, and without it can be even more confusing. There are plenty of blogs and tutorials that talk about creating bound Services, but I couldn't find any focus on interacting with bound Services from an attacker's perspective (no source).

In this post I'll create an application that exposes a bound Service, show you how to find and interpret bound Services in an application's disassembled Smali code, and present a tool to automate AIDL reconstruction.  This post will not be an in depth description of bound Services.

Creating the Bound Service in Java

First, we'll create an application, "com.jakev.boundserver" that defines our exported bound Service. This bound Service will support a single method, called "exec()", that accepts a command as a String, and executes it, and returns the output (please do not actually add this to your applications). The source code for this project (and APK) can be downloaded from the links at the end of this post.

We'll create the bound Service in 3 steps:
  • Declaring the new component in the "AndroidManifest.xml"
  • Creating the Android Interface Definition Language ("AIDL") interface
  • Creating a new Service class and implementing the "onBind()" method

In our AndroidManifest.xml we declare a new exported Service, ".ITestService":



Next, we create our AIDL interface, called "com.jakev.boundserver.aidl.TestInterface".  As described above, our "exec()" method will accept a single String argument, and return a String value:


Last, we create our Service class "com.jakev.boudserver.ITestService.java".  We need to implement the "onBind()" method, and return an instance to our "TestInterface" interface created above:


In order to interact with this Service, we'll need to create an application and include the AIDL file above.  As a developer, we'd probably distribute a JAR library that contains the AIDL file "TestInterface.aidl" and other supporting classes so that others can develop applications to interface with our new Service. As an attacker, we will likely not have this luxury.

Exploring the Service APK

Let's assume we find the "com.jakev.boundserver" application installed on a device, and stumble on this exported ".ITestService" Service.  We don't have the source code for the application; we just have the APK.  Let's pull the application and unpack it with `apktool`:


As a first step, let's look our ".ITestService" Service class, found at "smali/com/jakev/boundserver/ITestService.smali".  The "onBind()" method is pretty straightforward, and we can see that the Service is instantiating an inner class, "ITestService$1", and returning it.  This is due to the way we called the "new TestInterface.Stub() { }" above.


Opening "smali/com/jakev/boundserver/ITestService$1.smali" shows that the class is implementing a class "com.jakev.boundserver.aidl.TestInterface$Stub", which we have not looked at yet.  In the virtual methods section we see the actual implementation of the "exec()" method.  As a reverse engineer, you'd likely start with this method for determining the capabilities of the "exec()" method.


Next, let's look at what happened to our AIDL file.  There are now 3 different classes, called "TestInterface.smali", "TestInterface$Stub.smali", and "TestInterface$Stub$Proxy.smali", shown below.


Android Studio was nice enough to generate these for us when we built our application. There are plenty of papers that talk about the exact role of each of these, so I wont spend a lot of time talking about that.  The key takeaways here are:

  • The "TestInterface" class will always implement the "android.os.IInterface" class. It contains an abstract definition of each of the Binder methods.
  • The "TestInterface$Stub" class will always implement the "android.os.Binder" class, and contains the Binder transaction identifiers stored as fields.  The naming convention looks like "TRANSACTION_{methodName}".  These are the same ID fields used when calling services with the `service` command-line utility.
  • The "TestInterface$Stub$Proxy" class doesn't implement or extend any class, but contains the return type and parameter information for each Binder method.
You can use the following searches for if you're looking at a new application and want to enumerate Binder interfaces and their method implementation:

Finding any AIDL classes:
grep -r "super.*IInterface" ./smali

Finding implementation of AIDL:
grep -r "super.*${AIDL class from above}" ./smali

With these pieces of information, we can reconstruct the AIDL, and include this in our client application. You can do this manually, or you can use a tool I've created called 'GenerateAIDL.jar' that uses the DexLib2 library to parse an application's DEX code and outputs AIDL files that you can quickly add to your Service client.


If we open this file, we should see a AIDL interface similar to the one we created above:


Keep in mind this is just a trivial example.  There likely will be more than one method (and possibly some imported libraries) in a real-world example.

Attacking Bound Services

Now we're going to use the AIDL we just generated above to create a client application, "com.jakev.serverclient" that interacts with the ".ITestService".  I've tried to make this project as generic as possible, so it can be reused with ease.

The first step is to actually create/import our AIDL.  We want to add the AIDL we generated above to the proper folder, being mindful of the package name:


Next, we'll modify the "MainActivty" class I've created as a template.  First, add the AIDL above as an import, and add an object of this class called "service":


Next, change the class name of the Intent created in the "initService()" method, to the service you're interacting with:


Finally, we modify the "onServiceConnect()" method of our local "ServiceConnection" class to actually interact with the bound Service.  In this example, we're calling the "exec()" method, and supplying the "id" command, then recording this value in the Android logs.


If we build, install, and run our client application, we should see the output of the `id` command in the logs:


Conclusions

Given the correct permissions, an attacker can interact with bound Services just like other components.  It is important to inventory your application and confirm that the components that are exported are the ones you actually want exported.  For any component that performs sensitive actions (such as executing commands!!), make sure you apply the correct permissions.

Resources

  • http://stackoverflow.com/questions/15330233/remote-service-with-aidl-file-serviceconnection-never-called
  • http://developer.android.com/reference/android/content/ServiceConnection.html
  • http://developer.android.com/guide/components/bound-services.html
  • http://developer.android.com/guide/components/aidl.html
  • https://newcircle.com/s/post/48/implementing_remote_interface_using_aidl

Downloads