Inspiration

I built a forensics game for an earlier hackathon and got hooked on how real attacks show up in server logs. Every SSH break-in leaves a trail in /var/log/auth.log, but it's thousands of near-identical lines that no human reads. I wanted to turn that wall of text into the actual story of what an attacker did.

What it does

You drop in a raw SSH auth.log and Killchain reconstructs the attack as a timeline. It groups events by attacker IP and walks the kill chain: scanning, brute force, the login that finally worked, sudo to root, and any backdoor account they created. It scores each attacker from 0 to 100, tags every step with its MITRE ATT&CK technique, and writes a plain-English summary like "198.51.100.7 ran 70 failed logins, broke in as admin, escalated to root, and created the user backup1."

How I built it (and how I used Python)

Everything is the Python standard library. No pip installs, no frameworks.

  • re turns each log line into a structured event.
  • Six detectors find the behaviors: brute force, username enumeration, breach, privilege escalation, persistence, and scanning. The brute-force detector uses a sliding window with collections.deque.
  • A correlator groups findings per attacker and scores how far they got. I used enum.IntEnum so "how deep did they reach" is just max().
  • http.server runs a drag-and-drop web app and renders a self-contained HTML report with no external files.
  • A scenario generator builds six different randomized attacks so I can test the engine on something new every run.

I wrote 17 unittest tests covering the parser, every detector, and a round-trip where the generator makes a known attack and the pipeline has to recover it exactly.

Challenges I ran into

The hardest one: sudo and useradd lines have no source IP. They're local actions, so I couldn't link privilege escalation or a new backdoor account to the attacker by address. I solved it by tying those events back to the breach using the username, host, and time window. That one join is what turns a pile of log lines into a single attacker's story.

A smaller bug: sshd logs an invalid login twice, once as "Invalid user" and once as "Failed password," so my brute-force counts were doubled until I counted only one of them.

And making the demo safe: a random attack generator could roll a scenario the detectors miss, which would show "attack detected, zero findings" in front of a judge. I fixed the structure of every scenario and only randomized the surface (IPs, usernames, timing), then wrote a test that every attack type still detects correctly across 60 random seeds.

What I learned

How syslog actually formats SSH events, how to write real detection rules instead of just grepping, sliding-window detection, and that the interesting part of forensics is correlation, not pattern matching. I also learned that Python removed the cgi module in 3.13, which is why I send file uploads as raw text instead of form data.

What's next

IPv6 support, more detectors (off-hours logins, impossible travel), and correlating several log sources into one timeline.

Built With

Share this project:

Updates