Michael Jesse CranksonAll labs

Lab 01

SSH attack logs

Hunting SSH attacks in real server logs with SQL.

I took about four hours of real SSH logs from a server under attack, loaded them into a database, and used SQL to answer the questions a security analyst would ask: who attacked, what they tried, how fast, whether anyone got in, and when it peaked.

Lab files on GitHub

The data

2,000 lines of real OpenSSH server logs from the Loghub collection, a public log dataset published for research. It covers one server on 10 December, from 06:55 to 11:04.

Findings

  1. One IP did over half the damage.

    There were 519 failed password attempts from 23 different IPs. 286 of them came from a single address, 183.62.140.253.

  2. Root was the main target, inside a wider dictionary attack.

    Attackers tried 62 different usernames (admin, support, oracle, test, guest and so on), but 370 of the 519 failures (about 71%) were guesses at root, the account with full control of the server. Most of the other names don't exist on this server, so those guesses could never work. root does exist, which is what made it the real risk.

  3. It was brute force: automated, and fast.

    Grouping failures per IP per minute showed 183.62.140.253 hitting up to 30 failed passwords a minute. All 286 of its attempts landed in about ten minutes (10:54 to 11:04), roughly one guess every two seconds. No person types that fast, so this was a tool.

  4. Nobody broke in.

    There was exactly one successful login: user fztu from 119.137.62.142 at 09:32. That IP had no failed attempts at all. It got the password right first time, stayed about 13 minutes, and disconnected normally. That looks like a legitimate user, not a cracked account, and none of the attacking IPs ever got in.

    Caveat: a stolen password (as opposed to a guessed one) would look exactly the same, so in a real investigation I'd confirm with the user or check the IP against known locations before closing it.

  5. The attack was getting worse when the log ended.

    The attacks came in waves from different IPs through the morning. The 11:00 hour looks similar to 10:00, but the log stops at 11:04, so those 146 failures happened in under five minutes. The attack was at full speed when the record ends.

    Failed password attempts, by hour
    1. 106:00
    2. 4407:00
    3. 2408:00
    4. 13309:00
    5. 17110:00
    6. 14611:00

    The log ends at 11:04.

    SELECT strftime('%H', ts) AS hour,
           COUNT(*) AS failures
    FROM ssh_logs
    WHERE event_type = 'failed_password'
    GROUP BY hour
    ORDER BY hour;

Data note. The server sometimes collapses repeated lines into one ("message repeated 5 times"). Counting rows gives 519 failures; adding up the repeats gives 527. Small here, but on a busy server, counting rows instead of events would undercount an attack.

What would have stopped this

What I learned