EthicsComputerCourses
Join training +91 90532 10052

Password Hashes & Cracking in the Lab

Ethical Hacking · Lesson 20 of 28 Advanced 6 min read Updated

By the end of this lesson you will be able to explain how passwords should be stored, show why fast unsalted hashes are weak by cracking hashes you create yourself, and name the right algorithm and settings for safe storage.

This lesson is about defence. You will crack only hashes you generate yourself in your own lab, never real accounts. The Cyber Security lesson Cryptography Basics covers hashing theory; here you apply it to passwords.

Hashing, not encrypting

A hash function turns any input into a fixed-length fingerprint, and you cannot reverse it to get the input back. Passwords should be stored as hashes, so that even if the database is stolen, the real passwords are not simply sitting there.

Think of a tiffin service in Mumbai that writes a code on each box instead of the customer's full address. The code identifies the box, but a thief who steals the code list still does not know where anyone lives. A password hash is that code.

But not all hashing is equal. A plain, fast hash like MD5 or SHA-256 has two problems: identical passwords produce identical hashes, and attackers can try billions of guesses per second.

Problem 1: identical passwords, identical hashes

Run this to see it. Two users with the same password get the same SHA-256 hash:

PythonRun it yourself
import hashlib

def sha256_hex(text):
    return hashlib.sha256(text.encode()).hexdigest()

users = {
    "aarav": sha256_hex("password123"),
    "isha":  sha256_hex("password123"),
    "kabir": sha256_hex("Rohtak@2026"),
}
for name, digest in users.items():
    print(f"{name:<6} {digest[:24]}...")
print("aarav and isha match:", users["aarav"] == users["isha"])
Output
aarav  ef92b778bafe771e89245b89...
isha   ef92b778bafe771e89245b89...
kabir  d9f625b5c8c14721063265d1...
aarav and isha match: True

An attacker who sees two identical hashes learns that two users share a password, and can crack both at once. The cure is a salt: a unique random value added to each password before hashing, so identical passwords hash differently.

Problem 2: fast hashing is easy to guess

Because SHA-256 is fast, an attacker can precompute hashes of common passwords and look them up instantly. This is a dictionary attack. Here you build a tiny one against hashes you created, to feel how it works:

PythonRun it yourself
import hashlib

def sha256_hex(text):
    return hashlib.sha256(text.encode()).hexdigest()

# Lab hashes you generate yourself, never real accounts
lab_hashes = {"lab_user1": sha256_hex("summer"), "lab_user2": sha256_hex("Kochi#99x")}

wordlist = ["123456", "password", "summer", "qwerty", "admin"]
lookup = {sha256_hex(word): word for word in wordlist}

for user, digest in lab_hashes.items():
    found = lookup.get(digest)
    print(f"{user}: {'CRACKED -> ' + found if found else 'not in this wordlist'}")
Output
lab_user1: CRACKED -> summer
lab_user2: not in this wordlist

lab_user1 used a dictionary word and fell at once. lab_user2 used a longer, unusual password and survived this small list. Real cracking tools such as Hashcat and John the Ripper do this at huge scale against a hash file; you would only ever run them on hashes from your own lab, with permission.

The fix: salt plus a slow hash

Good password storage does two things: adds a unique salt, and uses a slow hash designed to take real time per guess. Slowness barely affects one honest login, but it cripples an attacker trying billions of guesses.

You can feel the idea of "slow" by hashing many times in a loop. This is a teaching model, not for production:

PythonRun it yourself
import hashlib

def slow_hash(password, salt, rounds=50_000):
    data = (salt + password).encode()
    for _ in range(rounds):
        data = hashlib.sha256(data).digest()
    return data.hex()

print("aarav:", slow_hash("Pune@1234", "salt-aarav")[:24])
print("isha: ", slow_hash("Pune@1234", "salt-isha")[:24])
Output
aarav: ce1ddb7779489b638f6cb596
isha:  05a3e700e518a7cd47e05cb4

Two users with the same password Pune@1234 now get different hashes, because their salts differ. And each hash took 50,000 rounds to compute, so guessing is far slower. Real algorithms do this properly; you should never write your own for production.

The real algorithms and settings

Use a purpose-built password hashing function. The OWASP Password Storage Cheat Sheet gives current settings (verify the latest before you rely on them):

AlgorithmWhen to useExample settings
Argon2idFirst choicememory 19 MiB, iterations 2, parallelism 1
scryptIf Argon2id is unavailableN = 2^17, r = 8, p = 1
bcryptLegacy systemswork factor at least 10; input limited to 72 bytes
PBKDF2When FIPS compliance is requiredPBKDF2-HMAC-SHA256, 600,000 iterations

In real code you call a library, not raw hashlib. For example (shown as plain code, since these need extra modules):

Python
# Production: use a maintained library
from argon2 import PasswordHasher          # the argon2-cffi package
ph = PasswordHasher(memory_cost=19456, time_cost=2, parallelism=1)
stored = ph.hash("the-user-password")      # salt is generated and stored inside
ph.verify(stored, "the-user-password")     # raises if wrong

A pepper can add one more layer: a secret value, the same for all passwords, kept apart from the database (in a vault or HSM), mixed in before hashing. If only the database leaks, the pepper is not in it. A pepper supports, but never replaces, a per-user salt.

What a tester reports

When you review password storage, you check and report:

  1. Are passwords hashed at all, or stored in plain text or reversible encryption?
  2. Is the algorithm a slow, salted one (Argon2id, scrypt, bcrypt, PBKDF2), not MD5, SHA-1 or raw SHA-256?
  3. Is a unique salt used per password?
  4. Are settings strong enough (for example bcrypt work factor, Argon2 memory)?
  5. Is there a minimum password length and a check against common passwords?

Common mistakes

  • Using MD5, SHA-1 or raw SHA-256 for passwords. They are far too fast.
  • One salt for everyone, or no salt. Salts must be unique per password.
  • Writing your own slow hash for production. Use a reviewed library.
  • Cracking anything but your own lab hashes. Guessing real accounts is an offence.

Key points

  • Passwords are stored as hashes because hashes cannot be reversed to the original.
  • Fast, unsalted hashes let identical passwords match and allow fast dictionary attacks.
  • A unique salt makes identical passwords hash differently; slow hashing cripples guessing.
  • Use Argon2id (or scrypt, bcrypt, PBKDF2) through a maintained library, with strong settings.
  • Crack only hashes you create in your own lab, never real accounts.

Exercise

Write a function check_storage(record) where a record has algorithm and salted fields. Return "unsafe" for md5, sha1 or sha256, "ok" for argon2id, scrypt, bcrypt or pbkdf2 when salted, and "needs salt" for an otherwise-good algorithm that is not salted. Test it on three records.

Show solution
Python
SLOW = {"argon2id", "scrypt", "bcrypt", "pbkdf2"}
FAST = {"md5", "sha1", "sha256"}

def check_storage(record):
    algo = record["algorithm"].lower()
    if algo in FAST:
        return "unsafe"
    if algo in SLOW:
        return "ok" if record.get("salted") else "needs salt"
    return "unknown algorithm"

for record in [
    {"algorithm": "md5", "salted": True},
    {"algorithm": "argon2id", "salted": True},
    {"algorithm": "bcrypt", "salted": False},
]:
    print(record["algorithm"], "->", check_storage(record))

MD5 is "unsafe" whatever the salt, Argon2id salted is "ok", and bcrypt without a salt is "needs salt". A fast hash cannot be rescued by salting alone.

Quick Quiz

1. Why is raw SHA-256 a poor choice for storing passwords?

2. What does a unique per-password salt achieve?

3. Which algorithm does OWASP recommend first for new systems?

4. Whose password hashes may you crack for practice?

Learn Ethical Hacking with a mentor

Free lessons get you started. Our Ethical Hacking & Cyber Security training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call