The fingerprint that gives it all away
The first sign that this campaign is different is the client_version field of the SSH handshake. This identifier is set by the client on connect — it's the "client signature" the server sees before any authentication. In legitimate traffic, you'd see a mix of OpenSSH_9.x, PuTTY_Release_X.XX, paramiko and the like.
In our honeypot, over the three days of observation, 99.5% of the connections presented exactly the same identifier:
SSH-2.0-Go — 26,225 connections out of 26,353 total (99.5%)
This identifier corresponds to Go's native SSH library (golang.org/x/crypto/ssh). It is not an SSH client for human use. It's the footprint of a scanner or custom bot written in Go.
The remaining 359 legitimate clients: paramiko 2.12 (44), PuTTY 0.83 (44), paramiko 5.0 (21), libssh2 (9).
Load distribution across IPs
The 53 IPs don't act independently. The distribution of attempts per IP reveals a campaign architecture with differentiated roles:
| IP | Attempts | Observed pattern |
|---|---|---|
| 45.148.[REDACTED].183 | 5.173 | High frequency, small dictionary (51 unique creds) |
| 2.57.[REDACTED].177 | 4.403 | High frequency, small dictionary (37 unique creds) |
| 45.148.[REDACTED].240 | 3.402 | High frequency, medium dictionary (101 unique creds) |
| 83.168.[REDACTED].99 | 1.524 | Medium frequency, broad dictionary (379 unique creds) |
| 91.92.[REDACTED].61 | 1.522 | Medium frequency, broad dictionary (761 unique creds) |
| 192.109.[REDACTED].78 | 1.520 | Medium frequency |
| 92.118.[REDACTED].62 | 1.407 | Medium frequency |
| 195.178.[REDACTED].30 | 1.365 | Medium frequency |
The tactical read: the top three IPs act as "battering rams" — they try the most likely credentials (123456, solana, root/sol) at maximum speed. The medium-frequency IPs do a broader sweep of the credential space. Classic botnet division of labor.
Exec sessions: 996 attempts without opening a shell
Part of the campaign uses SSH's exec channel instead of the interactive shell channel. This lets commands be run directly without opening a terminal session — faster and potentially harder to detect for tools that only log interactive shells.
996 exec attempts blocked by the honeypot. The most frequent exec commands are identical to the GPU hunter pattern: uname -s -v -n -r -m, lspci | grep VGA, uptime -p.
Using exec instead of shell is consistent with a scanner that only needs to detect whether the machine has a GPU — it doesn't need a full interactive session.
Why the Go client matters
Legitimate SSH clients —OpenSSH, PuTTY, WinSCP— are tools designed for human use. Go's SSH library is exactly the opposite: a low-level API that lets you write programmatic SSH clients with full control over the handshake, the channels and error handling.
Using golang.org/x/crypto/ssh directly has concrete implications for the attacker:
- High concurrency: Go handles goroutines natively. A Go scanner can open thousands of simultaneous connections with minimal overhead.
- Identifier control: the
client_versionfield is configurable. If they don't change it, it's because they don't care or don't know it's a visible indicator. - Portability: a statically compiled Go binary runs on any Linux without dependencies. Easy to distribute across the botnet.
What to add to your blocklist
The IPs observed in this campaign during the analysis period. Any IP-based blocklist is short-lived — attackers rotate infrastructure — but it can buy time.
Data collected for cybersecurity research purposes. All information comes from unsolicited activity recorded on our own infrastructure.
honeypot CipherSentry · 2026-06-11 a 2026-06-13