Loading
0xC0Lesson 13 of 13

Capstone: investigate a breach

Work through real-looking logs like a security analyst: find the scanner, the stolen account and the stolen data.

35 min 5-question quiz 2 code exercises
By the end of this lesson you can
  • Separate background noise (scanners) from a targeted attack
  • Reconstruct how an account was taken over
  • Measure what data left, and recommend fixes

Monday, 9:12. The support team reports that a customer list is being sold online. Your job: work out what happened from the web and sign-in logs, using everything from this track.

Investigations follow a rhythm: form a hypothesis, test it against the evidence, write down what you found - with timestamps. Start broad (who was active?), then narrow down (which activity was malicious?).

Step 1 - the noise. Every public server is constantly probed by automated scanners looking for leaked files (/.env, /.git/config) and common admin pages. They’re worth blocking, but usually aren’t the story. Your first exercise flags them so you can set them aside.

Step 2 - the story. Look for an account that was taken over: a run of failed sign-ins followed by a success from the same address. Then follow that address: what did it download?

group_by_ip.py
from collections import Counter
requests = ["192.0.2.66 /.env", "198.51.100.20 /cart", "192.0.2.66 /.git/config"]
print(Counter(line.split()[0] for line in requests).most_common(1))
Output
[('192.0.2.66', 2)]

Key takeaways

  • Filter background noise before hunting for the real attack.

  • Failures followed by a success from one address is a classic account-takeover signal.

  • Follow the attacker’s address forward in time to measure impact.

Lesson quiz

5 questions · pass with 4 correct · up to 50 XP

Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.

Practice: write Python

Write Python in the editor and run it against sample inputs. Python runs locally in your browser using a WebAssembly runtime.

Exercise 1

Step 1: flag the scanners

+25 XP

Each line is SECONDS IP METHOD PATH STATUS. Count, per IP, requests to the probe paths /.env, /.git/config, /wp-login.php, /phpmyadmin, /admin, and responses with status 404.

An IP is a scanner if it made 3 or more probe requests or got 5 or more 404s. Print IP: P probes, N not found for each scanner, sorted by IP.

  • Two scanners and a customer
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Exercise 2

Step 2: report the account takeover

+25 XP

Each line is either SECONDS IP LOGIN USER fail|success or SECONDS IP GET PATH STATUS BYTES, in time order.

An account is compromised when a login succeeds from an IP that had 3 or more earlier failed logins for that same user. For each compromise, print:

compromised: USER from IP at t=SECONDS (after N failures)
first seen: t=FIRST_TIME_THIS_IP_APPEARS
exported: B bytes in K requests

where the export counts that IP’s later requests whose path starts with /export and whose status is 200. If there’s no compromise, print no compromise found.

  • The breach
  • A forgetful user, not an attack
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Questions about this lesson

Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.

Loading posts…

Did you like the lesson? 😆👍
Consider a donation to support our work: