SSH · attack traffic
1234 login attempts in 41 hours: who really knocks on an exposed SSH port
2026-07-19 · HardStacked · 7 min read
Here is a box nobody is supposed to know about. A fresh IP from a cloud provider, no DNS
record, no link pointing at it, nothing published anywhere. One of our ordinary test machines,
online for a few days. We pulled its SSH logs on July 20, 2026, covering roughly 41 hours,
and counted what had been knocking.
1234 login attempts, every one on an account that does not exist. 93 distinct IP addresses.
132 different usernames. Activity at every single hour of the day. This is not a honeypot
study with bait: the box authenticates by key only, and our own connections are excluded
from every count below. It is just the ambient noise of the internet, measured.
$ sudo journalctl -u ssh | grep -c 'Invalid user'
1234 ← about 41 hours online. Every one on an account that does not exist.
1. Nobody knew this server existed. It got found anyway
The 93 addresses spread across 61 distinct /16 networks, about 1.5 addresses per
network. That dispersion is a signature: this is not one attacker retrying from home, it is
a botnet distributed across the world, each member probing a slice of the address space.
Geolocation puts the addresses behind the login attempts in ten countries across four
continents. The most insistent one, registered in Iran, knocked 373 times
on its own; China, Romania, the United States and
Bulgaria fill out the top five. And that map shows where the infected machines
sit, not where their operator does.
Nothing « leaked » the server. There was nothing to leak. The IPv4
space is small enough to be swept industrially, and these crews sweep all of it, all the
time. Your address is in the space, so your address is on the list. That is the entire
targeting logic.
The habit
Treat any machine with a public IP as discovered. Not published, not shared, not in DNS:
none of that is a defense, because none of it is how they find you. Obscurity can reduce
noise; it cannot be a layer you count on.
2. The username bestiary: 132 names, four kinds of prey
The most interesting artifact in the logs is the list of usernames tried. 132 distinct
names in 41 hours, and they read like an inventory of everything that connects to the
internet:
$ sudo journalctl -u ssh | grep -oP 'Invalid user \K\S+' | sort | uniq -c | sort -rn | head
410 admin
229 user
125 user2
118 debian
23 test
22 administrator
16 support
14 guest
12 postgres
12 ansible
Sort the full list into families and the botnet's shopping list appears:
- Servers and services:
postgres, mysql,
oracle, apache, ftpuser. Service accounts that
should never accept a login in the first place.
- The DevOps chain:
ansible, deploy, dev,
developer. This one deserves a pause: an ansible or
deploy account is rarely a curiosity, it is the account that holds keys to
every other machine. Twelve tries on ansible, ten on deploy,
on a box that has neither.
- Factory-default gear:
ubnt (Ubiquiti), AdminGPON and
telecomadmin (fiber boxes), cusadmin (cable modems),
huawei. These are not server accounts at all: they are the built-in logins
of routers, optical terminals and cameras.
- Single-board computers:
pi, orangepi. More on that
below.
The habit
Read that list as the exact set of names not to be. The account you expose over SSH
should not be in anyone's dictionary, and service accounts (postgres,
www-data…) should have no usable shell and no SSH access at all. An
AllowUsers line in sshd_config turns the whole bestiary into
instant rejections.
3. Yes, they are hunting Raspberry Pis too
Seven tries on pi, five on orangepi, six on ubnt,
five on AdminGPON. The same crew that probes for PostgreSQL servers also probes
for your fiber modem and your Raspberry Pi, in the same pass, with the same tooling. They are
not looking for « a Linux server »: they rake everything that has an
address, using the default account names things ship with.
For years the default on a Raspberry Pi was the pi account with a well-known
password, and every botnet dictionary still remembers it. If a Pi at home is port-forwarded
so you can reach it remotely, it receives this exact traffic, with a thinner security margin
than a server: no one watches a Pi's logs.
The habit
A Pi reachable from outside follows server rules: no pi account, key-only
auth, updates applied. If you want to know where yours stands, our open-source
audit-pi reads the machine and tells
you, free, in one run.
4. It never stops. Ever
819 invalid-user attempts the first full day, 402 the next. And spread out, not in
bursts: every single hour of the day saw activity, with the quietest hour still
logging around seven attempts. There is no calm window, no time zone where the botnet
sleeps, no pattern you could schedule around.
On top of the login attempts, more than a thousand connections opened and closed without
ever trying an account. That is the quieter part of the machinery: banner grabs and version
scans, the inventory pass that decides which doors are worth pushing on later.
The habit
Accept the noise as the baseline and watch the other line instead:
$ sudo journalctl -u ssh | grep 'Accepted'
← every line here must be you. This is the grep that matters.
A thousand Invalid user lines are Tuesday. One Accepted you do
not recognize is an incident.
5. The most beautiful zero in the log
One counter stayed at zero through all of it:
$ sudo journalctl -u ssh | grep -c 'Failed password'
0 ← 1234 attempts, and not one password was ever evaluated.
The box runs PasswordAuthentication no. With key-only auth, sshd rejects
these clients before a password is ever exchanged: the guessing engine, the dictionaries,
the retries, all of it hits a door with no keyhole. The same 41 hours against a
password-enabled box would have produced more than a thousand Failed password lines,
each one a real guess against your real password policy.
One honest limit of this data: sshd never logs which passwords were tried, on any
configuration. Capturing those takes a deliberate honeypot such as Cowrie, which is a
different experiment, for another article.
The habit
PasswordAuthentication no, after testing your key from a second terminal
with the current session still open. Done in the wrong order, this is lock-out classic
number one; we wrote up the five classic SSH lock-outs and
the habits that make them survivable.
Four habits for an internet-facing port
- Key-only authentication, tested before you close the door. It is the
difference between a thousand real password guesses and the zero above.
- No dictionary names exposed. The bestiary is the list of what not to be.
AllowUsers with one non-obvious account name rejects the whole
inventory.
- Watch
Accepted, not Invalid user. The noise is the
baseline; the exception is the signal.
- Obscurity is not a layer. This box had no DNS, no links, an IP never written
anywhere. 93 addresses found it regardless.
What this noise is telling you
Everything above is a count from one machine's journal, July 18 to 20, 2026. Your logs
will differ in volume, never in nature: the traffic is automatic, indiscriminate and
permanent, because it costs the operators nothing and occasionally pays. The question a
server owner has to answer is not « will I get probed ». You are
being probed right now. The question is whether the configuration holds on the night nobody
is watching the logs.
The deeper lesson
The defenses that silenced this whole dataset, key-only auth, no guessable accounts, a
hardened SSH block, are exactly the changes people postpone, because touching
sshd_config on a remote box feels like sawing the branch you sit on.
That fear is what HardVps removes: it applies the complete
SSH hardening block as one reviewed change, captures every original file first, and
verifies any restore byte-exact by SHA-256. You get the door that produced our zero,
with the way back guaranteed.
See what HardVps does →
On a Raspberry Pi? Start free with
audit-pi, our open-source security audit.