Хеш-станция (Hash Station)
Хеш-станция (Hash Station)
Platform: hackerlab | Category: Misc | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2025-12-26 | Status: Solved Techniques: Rainbow table / precomputed hash lookup, SQLite for fast hash-to-password mapping, Socket programming with timeout handling, rockyou.txt wordlist usage
Summary
Service: 192.169.2.100:10300
Хеш-станция (Hash Station) — hackerlab
Description
"Как обычно ломают хеш? Сверяют с хешами паролей из популярного словаря пока не найдется совпадение"
Service: 192.169.2.100:10300
Analysis
When connecting to the service:
- Need to send "start" command to begin the game
- Service sends an MD5 hash
- Need to send the original password within 5 seconds
- Repeat 100 times to get the flag
Key problem: 5 seconds per hash is too short for online bruteforce. Pre-computation is required.
Solution
Step 1: Preparing the Rainbow Table
Download rockyou.txt (14+ million passwords) and create an SQLite database with precomputed hashes:
python read-only • copy allowed#!/usr/bin/env python3 import sqlite3 import hashlib # Create database conn = sqlite3.connect('rainbow.db') cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS hashes ( hash TEXT PRIMARY KEY, password TEXT ) ''') cursor.execute('CREATE INDEX IF NOT EXISTS idx_hash ON hashes(hash)') # Load rockyou.txt with open('/usr/share/wordlists/rockyou.txt', 'r', encoding='latin-1') as f: batch = [] for i, line in enumerate(f): password = line.rstrip('\n') md5_hash = hashlib.md5(password.encode('latin-1')).hexdigest() batch.append((md5_hash, password)) if len(batch) >= 100000: cursor.executemany('INSERT OR IGNORE INTO hashes VALUES (?, ?)', batch) conn.commit() batch = [] print(f"Processed {i+1} passwords...") if batch: cursor.executemany('INSERT OR IGNORE INTO hashes VALUES (?, ?)', batch) conn.commit() conn.close() print("Rainbow table created!")
Step 2: Adding Additional Patterns
Add short words, dates, and numeric combinations:
python read-only • copy allowed#!/usr/bin/env python3 import sqlite3 import hashlib from itertools import product import string conn = sqlite3.connect('rainbow.db') cursor = conn.cursor() def add_hash(password): md5_hash = hashlib.md5(password.encode()).hexdigest() cursor.execute('INSERT OR IGNORE INTO hashes VALUES (?, ?)', (md5_hash, password)) # Short words (1-4 characters) for length in range(1, 5): for combo in product(string.ascii_lowercase, repeat=length): add_hash(''.join(combo)) # Numbers (0-999999) for i in range(1000000): add_hash(str(i)) # Dates in various formats for year in range(1950, 2025): for month in range(1, 13): for day in range(1, 32): # DDMMYYYY add_hash(f"{day:02d}{month:02d}{year}") # MMDDYYYY add_hash(f"{month:02d}{day:02d}{year}") # YYYYMMDD add_hash(f"{year}{month:02d}{day:02d}") conn.commit() conn.close()
Step 3: Solution Script
python read-only • copy allowed#!/usr/bin/env python3 import socket import sqlite3 def solve(): # Connect to database conn = sqlite3.connect('rainbow.db') cursor = conn.cursor() # Connect to service sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(10) sock.connect(('192.169.2.100', 10300)) # Read greeting data = sock.recv(4096).decode() print(data) # Send start sock.send(b'start\n') cracked = 0 while True: try: data = sock.recv(4096).decode().strip() print(f"Received: {data}") if 'CODEBY{' in data: print(f"\n[+] FLAG: {data}") break # Extract hash (32 hex characters) md5_hash = None for word in data.split(): if len(word) == 32 and all(c in '0123456789abcdef' for c in word.lower()): md5_hash = word.lower() break if not md5_hash: continue # Look up in database cursor.execute('SELECT password FROM hashes WHERE hash = ?', (md5_hash,)) result = cursor.fetchone() if result: password = result[0] cracked += 1 print(f"[{cracked}/100] {md5_hash} -> {password}") sock.send(f"{password}\n".encode()) else: print(f"[-] Hash not found: {md5_hash}") break except socket.timeout: print("Timeout!") break except Exception as e: print(f"Error: {e}") break conn.close() sock.close() if __name__ == '__main__': solve()
Result
[1/100] 5f4dcc3b5aa765d61d8327deb882cf99 -> password
[2/100] e10adc3949ba59abbe56e057f20f883e -> 123456
...
[99/100] 827ccb0eea8a706c4c34a16891f84e7b -> 12345
[100/100] 25d55ad283aa400af464c76d713c07ad -> 12345678
[+] FLAG: CODEBY{REDACTED}
Alternative Approaches
- Hashcat with GPU — faster for online bruteforce, but requires GPU
- Pre-built rainbow tables — can download ready-made tables for MD5
- Online services — crackstation.net, but slow for 100 hashes
Optimizations
- SQLite with index on hash — O(log n) lookup
- Batch insert when creating the table — speeds up loading by 10x
- Preloading database into memory (
:memory:) — even faster