HackBlue

Tools · Linux command line for security · 18 / 28

How to read auth.log and find failed SSH logins on Linux

Find failed and successful SSH logins in /var/log/auth.log or secure, count attempts by source and username, and tell guessing from a real compromise.

10 min read · practice only with authorization

Where the lines are

Debian and Ubuntu write authentication events to /var/log/auth.log. RHEL-family systems use /var/log/secure. Both are also in the journal under the ssh or sshd unit. The lines that matter say “Failed password for”, “Invalid user”, “Accepted password for”, “Accepted publickey for”, and “Connection closed by authenticating user”.

Each line includes the username tried and the source address and port, which is everything you need to count.

Counting attempts

Count failures per source to find guessing, and failures per username to see which accounts are targeted. Names like root, admin, test, ubuntu, and oracle dominate internet-wide guessing. A failure for a real employee username from an unusual country is more interesting than thousands for “admin”.

The most important query is the success list. An “Accepted” line from an address that also produced many failures is a likely compromise.

Snippet
sudo grep 'Failed password' /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head
sudo grep -E 'Invalid user|Failed password' /var/log/auth.log | grep -oP 'for (invalid user )?\K\S+' | sort | uniq -c | sort -rn | head
sudo grep 'Accepted' /var/log/auth.log

Lab: guessing followed by success

From your scanner VM, fail SSH login to the lab VM ten times with wrong passwords for a test user, then log in correctly. On the VM, run the three queries. Then write a one-liner that prints any source address with both more than five failures and at least one success.

That combined query is a simple but valuable detection. Port it to your log platform so it runs continuously.

Snippet
sudo awk '{for (i=1; i<NF; i++) if ($i=="from") ip=$(i+1)} /Failed password/{f[ip]++} /Accepted/{a[ip]++} END{for (ip in a) if (f[ip]>5) print ip, f[ip], "failures then success"}' /var/log/auth.log

Reduce the noise at the source

Disabling password authentication for SSH removes guessing as a threat almost entirely. Moving SSH off port 22 cuts log noise but does not add security on its own. Restricting SSH to a VPN or management network removes internet guessing completely.

After any confirmed compromise, check authorized_keys, cron, and systemd units for persistence, and rotate any credentials stored on the host.

Diagram

Three auth.log lines and what they say

Sample lines from a lab VM.

auth.logsshd

/var/log/auth.log

Nov  2 18:01:12 lab sshd[2211]: Failed password for invalid user admin from 203.0.113.9 port 51544 ssh2
Nov  2 18:01:40 lab sshd[2219]: Failed password for alice from 198.51.100.7 port 40112 ssh2
Nov  2 18:02:03 lab sshd[2224]: Accepted password for alice from 198.51.100.7 port 40130 ssh2
  • The first line is routine internet guessing against a name that does not exist.
  • The second and third are the same source failing and then succeeding for a real user.
  • That pair is the one to investigate.

Check yourself

1. Where are SSH authentication events logged on RHEL?

2. Which pattern most suggests a successful guessing attack?

3. Which change most reduces SSH password guessing risk?