It got in fifty-seven times.
Then it typed uname -s -m, read the answer, and hung up.
That is the entire operation. One hundred and one addresses, nine hundred and ninety-seven sessions, four months, still running โ and in all of it, two distinct commands and a single downloaded file.
This is what an inventory looks like when you catch it mid-count.
The shape of the thing
| HASSH | 98f63c4d9c87edbd97ed4747fa031019 |
|---|---|
| Client | SSH-2.0-Go |
| Addresses | 101 โ 81 Chinese |
| Sessions | 997, 2026-03-24 โ present |
| Successful logins | 57 |
| Distinct commands executed | 2 |
| Downloads | 1 |
The hosting is not what you would expect. No bulletproof providers, no Seychelles shells. ChinaNet (17 addresses), Baidu (14), China Unicom (12), Volcano Engine โ ByteDance's cloud (8), China Mobile, Huawei Cloud. Mainstream commercial infrastructure, rented like anyone else rents it.
And the two commands:
44ร uname -s -m
11ร uname -a
uname -s -m returns the kernel name and the machine hardware. Two values. It is precisely, and only, what you need in order to decide which binary to send.
It never opens a shell
Nine hundred and ninety-seven sessions. Terminal geometry is NULL on every single one.
No pseudo-terminal was ever requested. The client is not opening a session and typing into it โ it is exec'ing one command down the channel and closing. That is a decision made in code, not a habit of a person.
The timing agrees. Three hundred and ninety-six of the 997 sessions complete between 2.0 and 2.9 seconds, another sixty between 1.2 and 1.9. Nearly half of all activity inside a 1.7-second envelope: connect, authenticate, exec, read, close.
It does not sleep. Every hour of the day is occupied, peak-to-trough only 4.6ร.
Except once
On 2026-03-29 at 08:01 UTC, an address in ChinaNet โ RDAP registrant Xianghong Cao, a private individual rather than a company โ authenticated as root/12345.
Success. Then:
duration: 182.5 seconds
commands: 0
downloads: 0
Three minutes. Nothing typed. Disconnect.
Every session over ten seconds in the entire corpus โ nineteen of them โ falls in March. None since. Whatever was waiting for instructions in March stopped waiting, and the survey settled into its 2.4-second rhythm.
That reads like a handler stage that was removed. It could equally be an early timeout that was later tuned away. Both fit; the evidence does not separate them.
The trap: four fingerprints, one library
The corpus holds four Go SSH fingerprints. A previous dossier, TI-2026-057C, lists three of them as separate known public tools.
They are not separate tools. Compare the algorithm strings:
ours 98f63c4d : curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,โฆ
โฆ,diffie-hellman-group14-sha256,โฆ
16443846 : mlkem768x25519-sha256,curve25519-sha256,curve25519-sha256@libssh.org,โฆ
0.940 similarity. The only divergence is at character zero, where the other prepends mlkem768x25519-sha256 โ post-quantum ML-KEM, which entered Go's x/crypto/ssh in Go 1.24.
Everything after that byte is identical. These are the same client compiled on either side of a Go release.
The full ladder, oldest to newest:
| HASSH | addresses | tell |
|---|---|---|
2aec6b44 | 27 | lacks plain curve25519-sha256 |
e54ef3ec | 50 | still offers dh-group1-sha1 |
98f63c4d | 101 | dh-group14-sha256, no ML-KEM |
16443846 | 505 | + ML-KEM (Go โฅ1.24) |
683 addresses. All reporting SSH-2.0-Go. All that a shared HASSH proves here is shared compiler.
What actually identifies the operator
The wordlist. And it does not travel with the library.
Cross-tabulate the distinctive passwords across all four builds, by distinct source address:
| password | 98f63c4d | 2aec6b44 | e54ef3ec | 16443846 |
|---|---|---|---|---|
h3c.com! | 38 | 0 | 0 | 0 |
5nWt3P-fF4WosQm5O | 36 | 0 | 0 | 0 |
---fuck_you---- | 31 | 0 | 0 | 0 |
Pai=3.1415 | 28 | 0 | 0 | 0 |
Tcdn@2007 | 26 | 0 | 0 | 0 |
stfu_and_be_quite | 20 | 0 | 0 | 0 |
------fuck------ | 10 | 0 | 0 | 0 |
Zero. Across five hundred and eighty-two other addresses running the same library, not one of these strings appears.
The HASSH is the library. The wordlist is the operator.
Anyone can go build the same import. Nobody else wrote this list.
The list is a changelog
Two entries make this legible.
root/5nWt3P-fF4WosQm5O โ 41 attempts, 38 addresses, 24 active days. root/h3c.com! โ 40 attempts, 38 addresses, 24 active days.
Near-identical source lists. Near-identical day-by-day timelines. Attempts barely exceeding address count.
Which means no node ever repeats an entry. Each walks the whole list once per visit.
And that has a consequence worth more than this case: the first time a password appears in your logs is the date it was added to the attacker's wordlist. Ordinary credential telemetry becomes a change log for someone else's tooling.
Applied here, filtering to entries with the fleet's signature, 199 entries recover:
2026-03-21 5 entries 123456, letmein, password1, test3, welcome
2026-03-22 2 entries centos, soporte
2026-03-24 4 entries 123123, 12345, 1234567, qwerty
2026-03-25 145 ENTRIES โ bulk import
2026-03-26 6 entries ---fuck_you----, Tcdn@2007, passw0rd โฆ
2026-03-27 3 entries
2026-03-28 1 entry RPM
2026-03-29 17 entries stfu_and_be_quite, 2glehe5t24th1issZs,
Unis2020@_, aDm8H%MdA, opnsense, Master@2026 โฆ
2026-03-30 6 entries
2026-03-31 10 entries Admin@huawei, Samsung123, abcd2026, node2024
A tool being commissioned. Prove the pipeline with five throwaway strings. Import a 145-entry commodity list. Then spend a week adding what the commodity list lacks.
stfu_and_be_quite arrives on the 29th โ four days after the bulk load, in the curation window. That is why it is exclusive, and why it is the single best tracking string in the set: the misspelling of quiet is preserved, and it will not arise independently.
What the curation is for
The added entries are not more passwords. They are a hardware manifest:
h3c.com! H3C โ Chinese enterprise networking
Unis2020@_ UNIS / Unisplendour โ H3C's parent
Admin@huawei Huawei
Tcdn@2007 CDN appliance
opnsense firewall
Samsung123 Samsung
raspberryraspberry993311 Raspberry Pi
jenkins123 CI/CD
Plus four strings that are not guesses at all โ 5nWt3P-fF4WosQm5O, 2glehe5t24th1issZs, !QAZ2wsx3edc4rfv, tesTtest123a. Those are secrets lifted from firmware or vendor documentation by someone who went and looked.
The commodity half of the list hunts anything. The curated half hunts Chinese-market enterprise networking gear, edge appliances, firewalls and build infrastructure.
Read alongside the uname behaviour, the operation resolves: survey a specific hardware population, record what instruction set each one runs, deliver nothing yet.
Steelmanning the boring explanation
The comfortable reading is that this is a broken botnet. It logs in, fails to deploy, and leaves โ a payload stage that never worked.
It survives some scrutiny. The March sessions that hung for three minutes and did nothing genuinely look like a client waiting for something that never answered. Sixty-eight percent of the fleet's successful logins produced a uname and no follow-up, which is exactly what a half-finished dropper does.
But three things resist it.
The behaviour got tighter, not looser. A broken tool degrades or stops. This one dropped its long sessions after March and compressed into a uniform 2.4-second exec. Somebody removed a stage deliberately.
The wordlist kept being maintained after the payload stage vanished. Year-stamped entries run to 2026. You do not curate a target manifest for a tool you have given up on.
It is at its widest right now. March 94 sessions, April 427 โ but 369 of those from a single looping host โ May 2, June 30, July 444 across 72 addresses. The fleet is nearly four times April's true breadth. That is not decay.
Inventory taken and not yet used is not a failure. It is a stock-take.
The negative that matters most
Ask the relationship graph about a core member of this fleet โ 222.244.170.211, threat score 100 โ and it returns forty relations across two types: three shared_otx_pulse, and thirty-seven shared_abuse_email, all sharing anti-spam@chinatelecom.cn.
That is the abuse mailbox for an entire national carrier. It identifies nothing.
There is no shared_hassh edge. There is no shared_credential edge. Both relationships are demonstrably true in the source tables.
An investigation that queried only the graph would conclude these 101 addresses were unrelated hosts that happen to share a national abuse contact.
That is not a hypothetical. It is the conclusion this investigation reached on its first pass, and it stood until the source tables were checked directly. entity_links is a derived index built by a linker with thresholds. Its silence is evidence about the linker, not about the world.
What to take from it
Three artefacts were offered as identity here, and all three were wrong:
- the announcing ASN โ mainstream Chinese cloud, shared with millions
- the client fingerprint โ shared with 582 addresses running other operations
- the entity graph โ silent, because nobody drew the edge
What survived was a list of strings somebody typed, maintained, and never shared.
The operator is not identifiable by tooling, because the tooling is go build. It is identifiable because on the 29th of March somebody sat down, added seventeen entries to a file, and one of them was a joke about being quiet โ spelled wrong.
That misspelling has now been observed on twenty addresses across four months and zero addresses running any other build. It is the most durable thing about them.