practice · level 2

Password Hash Cracker

Dictionary attacks, crack rates, and why argon2id exists.

200 XP

Password Hash Cracker

Storing passwords incorrectly is one of the most durable ways to catastrophically harm your users. Not because hackers are clever, but because the math is unforgiving: a leaked database of fast-hashed passwords can be fully reversed in hours. This level makes you the attacker so you understand exactly what the math means.

Analogy

Imagine a burglar standing in front of a door, holding a janitor's ring of ten million keys. There's no cleverness involved — they simply try each key in the lock, one after another, and move on the instant a key doesn't fit. If the lock pops open after a millisecond per attempt, the whole ring is exhausted in a few hours. If the lock is the sticky, rusted kind that takes a full second to reject a wrong key, the same ring takes a hundred thirty years. That per-try delay is the entire point of a slow password hash: every jingle of the key ring is wasted attacker time, and the difference between fast hashing (MD5) and slow hashing (argon2id) is the difference between a completed break-in and a bored, defeated thief.

The dictionary attack

A dictionary attack is straightforward. You have a list of candidate passwords — a wordlist. For each word:

  1. Hash it with the same algorithm and parameters as the stored digest.
  2. Compare the result to the target digest.
  3. If they match, you've cracked the password.

That's it. No cryptanalysis. No cleverness. Just hashing every word in a list.

The attack works because:

  • Most users pick passwords from a small, predictable set.
  • Leaked breach databases have published millions of real-world passwords.
  • The rockyou.txt wordlist, leaked in 2009, contains 14 million passwords used by real people. It is freely available online and ships with several penetration testing distributions.

If your password is in that list and stored with a fast hash, it is cracked in under a second.

Why crack rate matters

Different algorithms offer wildly different resistance to this attack. The key metric is guesses per second — how many candidates an attacker can try on a single GPU.

Algorithm Guesses/second (single GPU, approx.)
MD5 ~60 billion
SHA-256 ~20 billion
slow-SHA-256 (t=50,000) ~400,000
argon2id (m=65536, t=3, p=4) ~500–2,000

Against MD5: a 10-million-word list is cracked in under a millisecond.

Against argon2id: the same list at 1,000 guesses/second takes nearly three hours — per user, per attacker GPU. Scale that to a million-user database and the economics become untenable for the attacker.

The memory-hardness trick

Slow-SHA-256 (iterated hashing) helps, but it has a critical weakness: it's parallelisable. A GPU with thousands of cores can hash thousands of candidates simultaneously. The attacker buys GPUs and throughput scales linearly.

Argon2id adds a second ingredient: memory-hardness. Each iteration reads and writes a large memory block (by default, 64 MB per hash). GPUs have fast compute but limited memory bandwidth. You can't parallelise argon2id the same way — memory bandwidth becomes the bottleneck, not compute.

This is why argon2id is the right answer. The attacker's hardware advantage collapses.

Important: the argon2id-sim in this project is a simulation. It approximates argon2id's time cost using iterated SHA-256, but it does not implement memory-hardness. The crack rates shown in the visualizer are illustrative, not real-world measurements. In production, use argon2 (Node) or argon2-cffi (Python), which implement the full algorithm including memory-hard computation.

Unsalted hashes: the rainbow table problem

If the hash has no salt, the same password always produces the same digest. An attacker can pre-compute a table of all common passwords → digests once, then look up any stolen digest instantly. These are called rainbow tables.

A per-user random salt makes every digest unique, so pre-computation is useless. The attacker must hash every wordlist entry separately for every user.

Salts do not slow down a targeted attack — they prevent batch attacks across multiple users and pre-computation.

What you're doing in this level

You are given a stored $slow-sha256$ digest. You run a dictionary attack:

  • Iterate through the wordlist.
  • For each word, re-derive the hash with the stored salt and iteration count.
  • Check if the digest matches.
  • Report how many guesses per second you achieved.

Then look at the crack rate visualizer: the same wordlist against four algorithms. Watch how the rate collapses from billions per second to hundreds as you move up the hardness scale.

The takeaway

If you use argon2id with recommended parameters, a leaked database is not an immediate catastrophe. Users have time to reset passwords before an attacker finishes the attack — if they ever do. If you use MD5, users have already lost before you notice the breach.

Pick argon2id. Use the library defaults. Never roll your own.