The objective of this project is the deployment of an Android application which interacts with a remote Command & Control (C&C) server as a spyware. SMS Xombie also features a Raspberry Pi equipped with a Global System for Mobile (GSM) antenna for the sole purpose of receiving commands from a controller mobile phone. In short, the app package—considered as a unique “zombie” device—communicates with the server using HyperText Transfer Protocol (HTTP) GET to fetch commands through JavaScript Object Notation (JSON) and HTTP POST to send sensitive data such as SMS logs, contacts book or geographical position back to the server – which gets parsed from a Hypertext Preprocessor (PHP) script.
2. Android Package
To start off with, I tried keeping the spyware code in a portable fashion so it can be easily integrated with other projects. We begin by modifying the Android Manifest file to ensure app’s functionality.
2.1. Manifest
Since Android 9 Pie (API level 28), cleartext traffic (unencrypted HTTP) will be blocked by default. Considering that most of the C&C servers do not use a SSL/TLS certificate, we have to add a network security configuration file in res/xml to allow such traffic:
This resource can be referenced in AndroidManifest.xml by appending the android:networkSecurityConfig="@xml/network_security_config attribute in the <application> element. Furthermore, the configuration uses a <base-config> tag, meaning that any non-SSL domain/subdomain will work.
2.1.1. Permissions
We need to set up a couple of permissions to allow performing operations on the device operating system such as read SMS messages, contacts, calls, calendars, access geolocation using WiFi or GSM, and receive system boot signals:
2.1.2. Modules
The app itself contains the following two (2) modules:
Fetcher Service - performs key operations in the background and does not require user interaction;
Autostart Receiver - a component triggered by the boot completion event to invoke the above service.
These components are defined in this way:
2.2. Capabilities
Each capability has its own private method of returning an arraylist of gathered data. Furthermore, each function will have an extra check on permissions to begin with, since the end-user can revoke a specific permission at any given time; consequently, we avoid app crashes.
2.2.1. SMS Dump
If the device receives the smsDump task, and if granted the READ_SMS permission, it will initially query the local content://sms/ storage. A cursor will iterate through the list of SMS messages and we will populate an array list with a couple of message attributes (their unique ID, sender phone number, date sent, and message body):
2.2.2. Contact List Dump
On the other hand, if the device receives the contactsDump task (assuming the READ_CONTACTS permission is granted), we will use the ContactsContract database of contact-related information. The result should return all rows which have a valid registered phone number, along their unique ID and name of the associated person:
2.2.3. Call Logs Dump
Retrieving call log information requires the READ_CALL_LOG Manifest permission. Based on the placed call category, we send back the associated phone number along the date and time as well as call duration in seconds (if answered):
2.2.4. Geographical Location Fetch
Physical location (latitude and longitude) with the getGeoLocation tag can be either found using the WiFi network, or actual last stored location from the GPS itself. If there is no cached location values, it will force update the current position:
2.2.5. Application List Dump
This operation does not require any special permission and only lists user-installed apps since there are many system-installed packages that are not of interest:
2.2.6. Device Information Retrieval
Similarily to app list dump with respect to additional permissions, this method returns some hardware and software information on the device itself:
2.2.7. Calendar Entries Dump
This capability requires the READ_CALENDAR permission and returns a list of calendars available on the phone:
2.2.8. Service Termination
In case you want to remotely terminate the background service, you may use kill keyword as a kill switch:
2.3. Implementation
The backend Apache2 server hosts a PHP script which handles queries and processes data. For the sake of simplicity, the following script does not include any MySQL database, instead, we will save exfiltrated data in a simple text file:
To minimize manual code modifications in Android Studio, I have put the declaration of the C&C server at the res/values/strings.xml file:
2.3.1. Intercommunication
Initially, a device GUID is generated to uniquely identify a “zombie”. This ID is later used as a query parameter in its regular GET requests to the PHP end-point which returns JSON encoded data, hence, we will use the JsonObject() along HttpURLConnection to interact with the API. The response is handled by the onPostExecute() function if the connection was successful and there is a network connectivity as per the isConnected() boolean method.
To send the payloads, I used the Volley HTTP library which makes networking in Android apps easier. After an array list is returned from methods denoted in the capabilities section, the app will gzip compress payload data, as well as base64 and URL encode it to avoid making parsing a hassle:
2.3.2. Proof of Concept
To test the app’s functionality without having to restart the phone, I have added a button on the MainActivity which invokes the Fetcher service, or in other words, makes a simple HTTP request as shown below:
Upon receiving the smsDump command, Fetcher validates the SMS_READ permission and uses sendData() to trasmit the complete SMS logs to the PHP script as seen partially in below:
When it comes to spyware software, you typically want to build application components which perform long-running operations in background without a GUI at all. From an Android perspective, this is possible with services instead of activities:
This service is started from a system standpoint when another module invokes it by calling startService(). Once started, a service can run in the background indefinitely, even if the component that started it is destroyed. Usually, a started service performs a single operation and does not return a result to the caller. In our specific case, Fetcher is bound to a loop of operations until its AlarmManager is terminated.
3.2. Persistence
When the application gets installed and opened, it will register a receiver which will be invoked during Android boot time RECEIVE_BOOT_COMPLETED (after system services get fully loaded that is). The main function of this BroadcastReceiver is to schedule an AlarmManager to start the Fetcher service periodically, thus, making it persistent in the device:
R.string.milliseconds is referenced from res/values/strings.xml which defines the frequency of device requests from a time standpoint. As of Android 5.1, the minimum value is 60 seconds (60000 milliseconds). Consequently, a “zombie” will send a check-up HTTP request every minute until it receives a task/command.
However, please note that since Android 8 Oreo (API level 26) and above, there is a limitiation with respect to running background services due to malware apps abusing this function; the startService() method now throws an IllegalStateException. Apps are permitted to start background processes only under specific circumstances when placed on temporary whitelists for handling tasks visible to the user, such as receiving a broadcast (SMS/MMS meesages).
3.3. Obfuscation
If you use Android Studio 3.4 or Android Gradle plugin 3.4.0 and higher, then R8 is the default compiler that converts your project’s Java bytecode into the DEX format that runs on the Android platform. However, when you create a new project using Android Studio, obfuscation is not enabled by default due to the increased build time during code compilation. To enable shortening the name of classes and members (results in reduced DEX file sizes), the following should be added to the build.gradle file:
4. Project Architecture
The application itself is a part of a larger system - the Xombie Platform - that we are going to elaborate next. The idea is simple, using a simple SMS message over the GSM network, we are able to control multiple devices that run the APK through the C&C server. The implementation however, is complex due to the following process:
Implementation of a Rasberry Pi device with a GSM shield attached to fetch SMS messages from a controller mobile phone over the GSM network;
Build of an interconnection mechanism between the API and physical device;
The ability to distinguishably process incoming traffic from the other mobile devices and respond with the appropiate content of that device.
For the larger picture, the above procedure is illustrated in the following scheme:
A typical use case would consist of the following process as shown below:
The controller device sends a command through an SMS message to retrieve all of the mobile phones geographical location (getGeoLocation keyword). The GSM shield, which can operate in Quad 850/900/1800/1900 MHz frequency bands, uses a local SIM card to receive the message, forward the SMS content to the smsXlib library, which then queues the task to the hosting server. Considering the mobile devices sends HTTP requests periodically to check whether there is something to do, in this case, they would immediately send relevant latitude and longitude values as a POST request (given that the user has given the application location service permission).
5. Disclaimer
Disclaimer: Usage of this application for attacking targets without prior mutual consent is illegal. It is the end user’s responsibility to obey all applicable local, state and federal laws. I assume no liability and I am not responsible for any misuse or damage caused.