Worksheet 3 — Cryptography Used Correctly (and Misused) (3 hrs)
← all weeks · readme · slides
Worksheet 3 — Cryptography Used Correctly (and Misused) (3 hrs)
Course: Software Security (KOSEN69) · Week 3 Aligned to: OWASP 2025 A04 Cryptographic Failures · CWE-327, CWE-916, CWE-330, CWE-798 Signature game: "Capture the Hash" (recover plaintext from weak hashes)
Ethics note: Crack only the hashes provided in
hashes.txton your own machine. Password-cracking against accounts or systems you don't own is illegal. Wordlists and recovered values stay inside the lab VM.
Part 1 — Student Information
| Name | Student ID | Date | Group |
|---|---|---|---|
Part 2 — Lecture Questions
Answer in your own words (2–4 sentences each).
- Distinguish hashing, encryption, and encoding — and give one job each is the wrong tool for.
- Why is a fast hash like MD5/SHA-1 a bad choice for storing passwords, and what should be used instead?
- What is a salt, what attack does it defeat, and why must it be unique per password?
- Why does AES-ECB leak structure, and what does an authenticated mode like AES-GCM add?
- What's the difference between
randomand a CSPRNG (e.g.secrets), and where does it matter?
Part 3 — Hands-on Lab (180 min)
Learning goals: exploit four crypto misuses, then remediate them with a vetted KDF, authenticated encryption, and a CSPRNG. Prerequisites: Docker (or local Python 3.12); hashcat or john; the rockyou.txt wordlist.
Environment setup
cd labs/week03-cryptography
docker compose up # installs pycryptodome + argon2-cffi, runs both scripts
# or locally:
pip install pycryptodome argon2-cffi
python vulnerable_crypto.py # see the md5 hash, repeated ECB blocks, 6-digit token
Targets: vulnerable_crypto.py (the misuses), hashes.txt (four unsalted MD5s), and solution_skeleton.py (the fix).
What to submit per task: the command/payload run + a screenshot of the result + a 2–3 sentence mitigation.
Task 0 — Onboarding (5 min) · Goal: see the misuse output. Steps: run python vulnerable_crypto.py; note the md5 digest, the identical ECB ciphertext blocks, and the short token. Deliverable: screenshot of the program output.
Task 1 — Capture the Hash (30 min) · Goal: recover the passwords. Steps: strip the comment lines from hashes.txt, then run hashcat -m 0 hashes.txt rockyou.txt (or the john --format=raw-md5 equivalent); recover all four plaintexts. Deliverable: screenshot of the cracked results (mask any real-looking value). Note in one line why unsalted MD5 fell so fast (CWE-916/327).
Task 2 — ECB structure leak (20 min) · Goal: prove ECB leaks. Steps: call encrypt_ecb(b"A"*16 + b"A"*16) from vulnerable_crypto.py and show the two 16-byte ciphertext blocks are identical; explain how this leaks plaintext structure (CWE-327). Deliverable: hex output highlighting the repeated block.
Task 3 — Predictable token (15 min) · Goal: show the reset token is guessable. Steps: call reset_token() repeatedly; argue why a 6-digit random token (10^6 space, non-CSPRNG) is brute-forceable (CWE-330). Deliverable: sample tokens + a one-line attack estimate.
Task 4 — Hardcoded key (5 min) · Goal: identify the key-management flaw. Steps: find HARDCODED_KEY in vulnerable_crypto.py; explain why shipping a key in source is CWE-798. Deliverable: the line + a 2-sentence mitigation.
Task 6 — Crack the project target's hashes (25 min) · Goal: apply cracking to your term project. Steps: NoteVault stores unsalted MD5 password hashes; obtain them (via the app's /admin once you can reach it, or from its seed()), and crack them with hashcat -m 0. Deliverable: the recovered password(s) + note the CWE — record this finding for your project report.
Task 7 — Password storage migration (25 min) · Goal: fix it the way real apps do. Steps: write store_password/verify_password with argon2id, and a rehash-on-login path that upgrades a legacy MD5 record to argon2id the next time the user logs in. Deliverable: the code + a short note on why migration matters.
Task 8 — Authenticated encryption round-trip (20 min) · Goal: use AEAD correctly. Steps: encrypt+decrypt a message with AES-GCM using a random 12-byte nonce and a key from an env var; then flip one ciphertext byte and show decryption fails (tag check). Deliverable: the round-trip output + the tampered-fails proof.
Task 9 — TLS in practice (15 min) · Goal: read a real cert. Steps: run openssl s_client -connect example.com:443 </dev/null 2>/dev/null | tee /tmp/tls.txt | openssl x509 -noout -issuer -subject -dates for the cert summary, then grep -E 'Protocol|New,' /tmp/tls.txt for the negotiated TLS version (the version line is printed by s_client, not by x509, so the plain pipe would discard it); identify issuer, validity, and that TLS version. Deliverable: the cert summary + one line on what TLS protects that hashing/at-rest encryption does not.
Task 5 — Defend / fix it (20 min) · Goal: remediate using solution_skeleton.py. Steps: run python solution_skeleton.py; confirm store_password/verify_password use argon2id (auto-salted), encrypt_gcm uses a random 12-byte nonce + auth tag with a key from ENC_KEY_HEX env, and reset_token uses secrets. Map each fix to the CWE it closes. Deliverable: before/after table (misuse → fix → CWE closed) + screenshot of the fixed script running.
Part 4 — Reflection
- Map each of the four misuses to its CWE and to OWASP A04, in one line each.
- Name a real-world breach caused by weak password hashing or hardcoded keys, and which fix here would have prevented it.
- Across all four fixes, which closes the largest real-world risk, and why?
Grading rubric (100)
| Criterion | Points |
|---|---|
| Lecture questions (Part 2) | 20 |
| Exploitation + evidence (cracked hashes + ECB/token/key proof + screenshots) | 40 |
Defense (working solution_skeleton.py + before/after mapping) | 25 |
| Reflection (CWE/OWASP mapping + breach + biggest-risk fix) | 15 |
Evidence & Integrity (required)
- Identity proof: every screenshot/diagram must show your **
whoami/ login email / student ID and a timestamp**. Generic or borrowed evidence is not accepted. - Personalized flag (if this lab issues one): ____________________
Flags are unique per student — submitting another student's flag is a violation. See SUBMISSION.md.
- Explain in your own words (graded on your reasoning, not copied text):
- What did you do, and why did the vulnerability work?
- Why does your fix actually stop it — and what could still break it?
🤖 Audit the AI (required)
AI is a power tool you must distrust — you are graded on your critique, not the AI's answer.
- Ask an AI assistant to exploit or fix this week's vulnerability. Paste its full answer.
- Find what's wrong or risky in it — insecure code, a subtly incomplete fix, a hallucinated API/function/CVE, a missed edge case, or wrong reasoning. Quote the exact line(s).
- Produce the correct, verified version yourself and explain in 2–3 sentences why the AI's output was insufficient.
Disclose your AI use in the Part 1 table. This task counts toward your Defense + Reflection score.
🧠 Comprehension & Prompt (required)
A. Explain in Plain English (EiPE). In 2–3 sentences, in your own words, describe what this week's vulnerable code/endpoint actually does and why it is exploitable — explain the mechanism, don't dump jargon.
B. Prompt Problem. Write a single prompt that makes an AI produce a correct, secure fix for one finding. Run it: does the exploit now fail? If not, refine the prompt and try again. Submit the final prompt + the verified result. Graded on the prompt's precision and your verification — this trains problem decomposition and AI literacy (Denny et al. 2024).