Unit 7: Logins, MFA and tokens · Lesson 7 of 7 · 24 min

Case file: reused passwords at scale

Read a night of login attempts, see why a per-account limit never fired, and pick the defences that would have stopped it.

case file

23andMe credential stuffing

23andMe · 2023

From April to September 2023 an attacker reused passwords leaked in other breaches to sign in to 23andMe accounts, then used a relatives feature to scrape data on about 6.9 million people. The UK ICO later fined the company, citing no mandatory MFA and weak protection against reused credentials.

What went wrong

Password-only logins with no mandatory MFA or effective credential stuffing defences, plus a feature that let one account see data about many others, and weak monitoring.

What would have stopped it

  • Mandatory MFA for accounts that hold sensitive data.
  • Breached password checks, rate limits across many accounts and bot detection.
  • Extra verification before access to or download of highly sensitive data.

What defenders could have seen

  • Spikes in failed logins across many accounts from many addresses.
  • Successful logins on accounts whose passwords appear in breach data.

sourcesico.org.uken.wikipedia.org

mission

You are
The analyst reviewing a strange night of sign-ins.
Situation
Overnight on 13 October the shop's login log filled with failures. The shop locks an account after five failures in a minute, and no lock ever fired.
Goal
Measure the attack, find which accounts were broken into and explain why the limit missed it.
Hand in
Affected accounts, the reason for the miss and the controls to add.

Brute force versus credential stuffing

  1. Brute forceMany passwords against one account. A per-account limit stops it.
  2. Credential stuffingOne or two leaked passwords against many accounts, from many addresses. A per-account limit never trips.
01

Measure the night

learner@web-lab
wc -l < cases/logins/login-attempts.log
300
grep -c 'result=fail' cases/logins/login-attempts.log
261
grep 'result=fail' cases/logins/login-attempts.log | grep -o 'ip=[0-9.]*' | sort -u | wc -l
91
grep 'result=fail' cases/logins/login-attempts.log | grep -o 'user=[a-z0-9]*' | sort -u | wc -l
175

you should see 261 failures spread over 91 addresses and 175 accounts. That shape is stuffing, not guessing.

02

Why the limit never fired

learner@web-lab
grep 'result=fail' cases/logins/login-attempts.log | grep -o 'user=[a-z0-9]*' | sort | uniq -c | sort -rn | head -n 1
      2 user=user180

you should see No account failed more than twice. A five-failure lock was never going to trigger.

03

Which sign-ins succeeded from outside?

Staff sign in from 10.x addresses. Successes from elsewhere during the attack are the ones to check.

learner@web-lab
grep 'result=ok' cases/logins/login-attempts.log | grep -v 'ip=10\.' | wc -l
9
grep 'result=ok' cases/logins/login-attempts.log | grep -v 'ip=10\.' | head -n 3
2026-10-13T01:00:22Z ip=198.51.100.134 user=user002 result=ok
2026-10-13T01:01:37Z ip=203.0.113.10 user=user009 result=ok
2026-10-13T01:02:02Z ip=203.0.113.18 user=user011 result=ok

you should see Nine outside sign-ins succeeded.

04

Match against breach data

The shop subscribes to a breach notification feed listing customer accounts whose passwords appeared in other companies' leaks.

learner@web-lab
grep 'result=ok' cases/logins/login-attempts.log | grep -v 'ip=10\.' | grep -o 'user=[a-z0-9]*' > stuffed.txt; grep -cxFf cases/logins/breached-accounts.txt stuffed.txt
9

you should see All nine are on the breached list. A breached password check at sign-in or reset would have blocked every one.

defender tip Force a reset for those nine, end their sessions and check what they accessed. Then add MFA, a breached password check and limits by address and across accounts.

What a defender takes away

  1. 1Credential stuffing looks like many accounts and many addresses, a few tries each.
  2. 2Per-account lockouts do not stop it; limits across accounts and breached password checks do.
  3. 3MFA makes a reused password useless on its own.

Questions

0 of 3 solved

Answer each one from what you find on your lab machine.