Как нужно делать пароли (How I Make My Passwords)
Как нужно делать пароли (How I Make My Passwords)
Platform: hackerlab | Category: Crypto | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-01-02 | Status: Solved Techniques: AES-CBC decryption with recovered key, IV matching for seed verification, PRNG seed recovery via timestamp bruteforce, Timestamp extraction from WhatsApp screenshot
Summary
Task: AES-CBC encrypted data with key generated using Python random seeded with time.time(). Solution: Extract timestamp from WhatsApp screenshot, bruteforce PRNG seeds around that time, verify by matching IV, decrypt with recovered key.
Как нужно делать пароли (How I Make My Passwords) — hackerlab
Description
Недавно я гулял по Москве. И встретил в кафе крутого тим-лида одной компании! Теперь напишу ему, как делаю свои пароли. Думаю, он никогда не создавал их так удобно и безопасно :)
Files:
gen_pass.py- Python password generation scriptsample.txt- IV and encrypted datawhatsapp_chat.png- WhatsApp chat screenshot
Analysis
1. Generator source code (gen_pass.py)
python read-only • copy allowedfrom Crypto.Cipher import AES from Crypto.Util.Padding import pad import random import time KEY_LEN = 16 BS = 16 time_s = int(time.time()) random.seed(time_s) key = bytes([random.randint(0, 255) for _ in range(KEY_LEN)]) iv = bytes([random.randint(0, 255) for _ in range(BS)]) cipher = AES.new(key, AES.MODE_CBC, iv) final = cipher.encrypt(pad(passwd, BS))
Critical vulnerability: time.time() is used as seed for PRNG!
2. Data from sample.txt
IV: e49af1c15dad9962c45547b81414a399
Encrypted: 5239047215d18b79ffed9b8a93063e44a0ed0615ace44c8f80855775375bd85920dc6c0e37486ee2109887a55c337b66
3. WhatsApp screenshot
The screenshot shows:
- Date: November 01, 2023
- Time: ~17:10 (Moscow time)
- Message about password generation
Vulnerability
Python random module uses Mersenne Twister PRNG. With a known seed, all subsequent values are fully deterministic.
Attack:
- Determine approximate encryption time from the screenshot
- Bruteforce timestamps around that time
- For each timestamp, generate key and IV
- Compare generated IV with the known one
- When IV matches, use the key for decryption
Solution
python read-only • copy allowed#!/usr/bin/env python3 """ Hackerlab: Как нужно делать пароли PRNG seed bruteforce attack on AES-CBC """ from Crypto.Cipher import AES from Crypto.Util.Padding import unpad import random from datetime import datetime import pytz # Known values from sample.txt iv_hex = "e49af1c15dad9962c45547b81414a399" final_hex = "5239047215d18b79ffed9b8a93063e44a0ed0615ace44c8f80855775375bd85920dc6c0e37486ee2109887a55c337b66" iv = bytes.fromhex(iv_hex) final = bytes.fromhex(final_hex) KEY_LEN = 16 BS = 16 # Time from WhatsApp screenshot: 01 November 2023, ~17:10 Moscow time moscow_tz = pytz.timezone('Europe/Moscow') base_time = moscow_tz.localize(datetime(2023, 11, 1, 17, 10, 0)) base_timestamp = int(base_time.timestamp()) print(f"[*] Base timestamp: {base_timestamp}") print(f"[*] Searching in range [{base_timestamp - 300}, {base_timestamp + 300}]") # Bruteforce timestamps around the known time for offset in range(-300, 301): # +/- 5 minutes time_s = base_timestamp + offset # Reproduce PRNG state random.seed(time_s) key = bytes([random.randint(0, 255) for _ in range(KEY_LEN)]) test_iv = bytes([random.randint(0, 255) for _ in range(BS)]) # Check if IV matches if test_iv == iv: print(f"[+] Found matching timestamp: {time_s}") print(f"[+] Offset from base: {offset} seconds") print(f"[+] Key: {key.hex()}") # Decrypt the ciphertext cipher = AES.new(key, AES.MODE_CBC, iv) decrypted = unpad(cipher.decrypt(final), BS) print(f"[+] Decrypted: {decrypted.decode()}") break else: print("[-] No matching timestamp found in range")
Execution result
[*] Base timestamp: 1698847800
[*] Searching in range [1698847500, 1698848100]
[+] Found matching timestamp: 1698847827
[+] Offset from base: 27 seconds
[+] Key: <recovered_key>
[+] Decrypted: CODEBY{REDACTED}
Lessons
- Never use
randomfor cryptography - usesecretsoros.urandom()instead - Timestamp is a bad seed - easy to guess with second precision
- IV leak helps verification - allows checking seed correctness without decryption
- Metadata matters - chat screenshot provided time reference
Alternative Approaches
- Without time reference: Bruteforce all timestamps for the last N years (slower but works)
- With known plaintext: If flag format is known, can verify decryption directly
- Parallel bruteforce: Split the range into parts for speedup
References
- Python random module documentation
- Mersenne Twister PRNG
- CWE-330: Use of Insufficiently Random Values