The inspiration for a framework such as Mercury originated from having to manually create custom applications for each entry point identified during a security assessment of an Android application. This process is often iterative and time consuming as each step may require the app to be amended, recompiled, uploaded and tested again. After a number of these iterations, the need for Mercury quickly became clear. The search for a tool that provides such dynamic analysis capability on Android did not yield any satisfactory results. After some further investigation into a suitable structure, it was decided to create a modular framework with a familiar look and feel that can be easily extended.
What is Mercury?
Mercury is a framework that provides a platform for effective vulnerability hunting and exploitation on Android. It provides a collection of tools to do so from a single console with a familiar look and feel and allows for easy expansion due to the modular architecture. Mercury includes a number of commands that automate discovery and interaction with exposed Android application features, a process that often requires a selection of custom scripts.
Even though some features of the framework allow for automated discovery of certain classes of vulnerabilities, it is not a vulnerability scanner. In order to effectively use Mercury in an assessment, a user will still be required to understand the Android security model. An additional aim of the Mercury framework is to provide simplified interfaces between external tools and modules to enable future expansion.
Mercury will allow for the sharing of proof-of-concept exploits and new tools to better assess an Android application or device.
How does Mercury work?
Mercury operates in two parts: the client component which is executed on the user’s computer and the server which is installed on an Android device or emulator. Communications between the client and server take place using a defined XML structure that works on requests and responses. A typical connection from client to server takes place as follows:
- Client connects to the server on a TCP port and a single request is made
- The connection is kept open until a single response from the server is received
- Once a full response has been received by the client it closes the connection
The Mercury server component installed on the Android device only requires a single permission, the INTERNET permission, to be granted. This ensures that the server require as little privileges as possible when performing its tasks. The INTERNET permission is required so that the application can communicate with the client software using socket connections.
One of the biggest aims of this project was to build a framework instead of a fixed tool so that it is extensible and new plug-in modules can easily be created by someone other than the original developer. The way that the Mercury server and client handle new modules was designed for ease of extension, which will be discussed in the following sections.
The server maintains a set of commands that perform a once-off function on the device and return a result to the client. These commands make up the component that interacts with the target application or feature of Android that the user is testing. They are well-defined in the Commands.java source file of the server application on the Android device or emulator. A new server command that provides new functionality to the client can be created on the server by adding a new CommandWrapper object to the list of already known server commands. The implementation details of the CommandWrapper class will not be discussed as part of this paper, but a brief overview of its structure will be presented below.
A command on the Mercury server contains the following attributes:
- Section: describes which logical section the command falls under. For example, if a command interacts with content providers it should be placed under the provider section.
- Function: describes the name of the command. These names have been chosen to be as descriptive as possible without being too long. Normally, if the predominant function of the command is an already defined SDK function, then it will bear resemblance to that function’s name. For instance, a command which was created to read from a content provider was named query. This is because the SDK’s getContentResolver().query() method does the majority of the work in that function. This ensures consistency between the naming conventions of the Android SDK and Mercury.
- Executor: is an interface that contains the code for the implementation of the new command.
By following the above structure, it was possible to keep the server commands separate from the implementation details of the rest of the Mercury server.
The Mercury client framework is written in Python and opens itself up for customisation and extension. Users are able to write custom client modules that use any of the server commands defined on the server, as explained in the previous section. Various server commands can be used to perform actions on the server or get relevant information that can be used to achieve the intended goal of the module developer.
On the client, by adding a module that has some defined attributes, it can immediately be used by the Mercury framework. These modules are placed in their relevant location in the client source folder. For example, when writing a script that allows the user to display different pieces of information about the Android device, it could be placed in modules/information/deviceinfo.py. This structure allows the grouping of different related modules into the same folder.
If a server command that is needed by a client module does not exist, it can be trivially added using the outline discussed in the previous section. Once the command is added to the server, the server source can be recompiled and the command becomes available to the client.
This structure allows users to write proof-of-concept exploits for vulnerabilities using a range of pre-defined server commands, effectively removing the need for custom-purpose application writing, compilation, uploading and testing, as well as multiple iterations of these steps. The amount of time taken creating small applications to perform once-off tests could be better spent.
Why create a framework like Mercury?
Mercury was created to meet the need for a consolidated testing framework for Android. Many custom scripts and tools are available on the internet to ease the process of performing static analysis and these efforts are often being duplicated.
It is also important to note that any task that can be performed inside Mercury can also be performed from within any application with the INTERNET permission. This means that if vulnerabilities are found and a proof-of-concept can be successfully executed using Mercury, the vulnerability is potentially high-impact. This is because a malicious application could exploit the same vulnerability from an unprivileged context and pose a security threat.
Dynamic analysis using Mercury
A testing methodology used for static analysis of Android applications or devices could be applied when using Mercury as a testing toolkit. It also allows the auditor to go a step further and interact with the discovered application entry points without any further preparation.
To get an idea of the general attack surface of an application, the packages→attacksurface command can be used. This command examines the general security considerations of an application with regards to the exporting of IPC endpoints and other atypical security concerns that Android introduces. It checks the following:
- Number of activities exported
- Number of services exported
- Number of broadcast receivers exported
- Number of content providers exported
- If the application uses a shared user-id
- If the application is marked as debuggable
According to the exported entry points found, the auditor can then use the appropriate section of Mercury and issue info -f packageName to find further information about the exported application attribute at hand. It is accepted that on occasion, the package would have to be downloaded and the source code examined in order to fully understand and effectively interact with an exported IPC endpoint of an application. However, using the
dynamic method, it could provide a quick way to find relevant attack vectors.
Some features which are essential for auditing a target application or device using Mercury are detailed below.
- Activity: Find information about exported activities. Get the launch intent that can be used to launch an application. Find applications that match the given intent. Start an application using the given intent.
- Broadcast: Find information about exported broadcast receivers. Send a broadcast using the given intent.
- Provider: Find information about exported content providers. Find the columns of a content provider. Search for content URI’s in the given package. Perform SQL-like tasks such as querying, deleting, inserting and updating contents of the given content provider.
- Service: Find information about exported services. Start and stop services using the given intent.
- Debuggable: Find information about debuggable applications on the device. Exploit debuggable applications by using Mercury to execute selected code within the context of the debuggable application.
- Packages: Find information about the installed packages on the device. Find the attack surface of a given package. Check which applications share a user-id.
- Tools: Upload and download files to and from the Android device. Get information about a specified file and search through different intents that can be sent to the IPC endpoints.
- Shell: Access two different classes of shells on the Android device. This allows access to the underlying Linux system from within the context of Mercury.
- Modules: Allow the user to list currently available modules. Get information about these modules. Execute user-created modules.