Я работаю в криптовалюте (I work in cryptocurrency)
Я работаю в криптовалюте (I work in cryptocurrency)
Platform: hackerlab | Category: Reversing | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2025-12-25 | Status: Solved Techniques: Custom encryption algorithm reverse engineering, XOR + ROL + block swap + modifier decryption, Function size to bitmap conversion, Image transformation (flip + rotate)
Summary
Two files provided: - crypter — encryption binary - FLAG.crypt — encrypted file
Я работаю в криптовалюте — HackerLab
Description
Two files provided:
crypter— encryption binaryFLAG.crypt— encrypted file
Analysis
Step 1: Reverse Engineering the Encryptor
Analysis of the crypter binary revealed:
- Encryption key found in strings:
Th1s_1s_N0t_Th3_K3y_U_R_L00k1ng_F0r
- Encryption algorithm (4 stages):
- XOR each byte with
SECRET_KEY[i % key_len] - ROL (rotate left) each byte by
(SECRET_KEY[i % key_len] % 8)bits - Swap 16-byte blocks in each 32-byte chunk
- Add modifier
(file_size & 0xFF)to each byte
- XOR each byte with
Step 2: Decryption
To decrypt, perform the operations in reverse order:
python read-only • copy allowed#!/usr/bin/env python3 """ Decryption script for the crypter binary. Encryption algorithm (from reverse engineering): 1. XOR each byte with SECRET_KEY[i % key_len] 2. ROL (rotate left) each byte by (SECRET_KEY[i % key_len] % 8) bits 3. Swap 16-byte blocks (first 16 with second 16) for each 32-byte chunk 4. Add modifier byte (file_size & 0xFF) to each byte Decryption is the reverse: 1. Subtract modifier byte from each byte 2. Swap 16-byte blocks back 3. ROR (rotate right) each byte 4. XOR with SECRET_KEY """ SECRET_KEY = b"Th1s_1s_N0t_Th3_K3y_U_R_L00k1ng_F0r" def ror(byte, n): """Rotate right by n bits (8-bit)""" n = n & 7 return ((byte >> n) | (byte << (8 - n))) & 0xFF def proprietary_block_swap(data, offset): """Swap first 16 bytes with second 16 bytes in a 32-byte block""" if offset + 32 > len(data): return temp = data[offset:offset+16] data[offset:offset+16] = data[offset+16:offset+32] data[offset+16:offset+32] = temp def decrypt(encrypted_data): """Decrypt data encrypted by the crypter binary""" data = bytearray(encrypted_data) file_size = len(data) key_len = len(SECRET_KEY) # The modifier is file_size & 0xFF (low byte of file size) modifier = file_size & 0xFF # Step 4 reverse: Subtract modifier from each byte for i in range(len(data)): data[i] = (data[i] - modifier) & 0xFF # Step 3 reverse: Swap 16-byte blocks back (same operation, it's symmetric) num_blocks = file_size >> 5 # file_size / 32 for i in range(num_blocks): proprietary_block_swap(data, i * 32) # Step 2 reverse: ROR each byte (reverse of ROL) for i in range(len(data)): key_byte = SECRET_KEY[i % key_len] shift = key_byte % 8 data[i] = ror(data[i], shift) # Step 1 reverse: XOR with SECRET_KEY for i in range(len(data)): data[i] ^= SECRET_KEY[i % key_len] return bytes(data) with open("FLAG.crypt", "rb") as f: encrypted = f.read() decrypted = decrypt(encrypted) with open("FLAG.decrypted", "wb") as f: f.write(decrypted)
The decrypted file turned out to be a 32-bit ELF executable.
Step 3: Analyzing the Decrypted Binary
The decrypted ELF contains 7300 functions with names like e_X_Y:
- X from 0 to 99 (100 values)
- Y from 0 to 72 (73 values)
- Forms a 100×73 matrix
Each function has a specific size. Key observation: function sizes encode a bitmap image.
Step 4: Visualizing the Flag
Extracting function sizes and building the image:
python read-only • copy allowed#!/usr/bin/env python3 from PIL import Image import subprocess import re # Extract function sizes using nm result = subprocess.run(['nm', '-S', 'FLAG.decrypted'], capture_output=True, text=True) # Parse function sizes functions = {} for line in result.stdout.split('\n'): match = re.search(r'([0-9a-f]+)\s+([0-9a-f]+)\s+\w+\s+e_(\d+)_(\d+)', line) if match: size = int(match.group(2), 16) x = int(match.group(3)) y = int(match.group(4)) functions[(x, y)] = size # Create image width, height = 100, 73 threshold = 70 img = Image.new('RGB', (width, height), 'white') pixels = img.load() for (x, y), size in functions.items(): if size <= threshold: pixels[x, y] = (0, 0, 0) # Black else: pixels[x, y] = (255, 255, 255) # White # Apply transformations img = img.transpose(Image.FLIP_LEFT_RIGHT) # Horizontal flip img = img.rotate(90, expand=True) # 90 degrees counter-clockwise img.save('flag_image.png')
Transformations for readability:
- Horizontal flip (mirror)
- 90° counter-clockwise rotation
After transformations, the flag becomes readable.
Solution
CODEBY{REDACTED}
Failed Attempts
Reading the flag from the image was difficult due to leetspeak. Tried:
CODEBY{yoREDACTEDand_found_me_easily}— incorrectCODEBY{REDACTEDand_found_me_easily}— incorrectCODEBY{0bfusc4t10n_1s_n0t_pr0t3ct10n}— incorrect (attempt to guess by meaning)CODEBY{yoREDACTEDn00000L9y}— incorrect (misread the ending)- Various leetspeak substitution variants (0/o, 3/e, 1/i, 4/a)
Key mistake: initially only did horizontal flip without 90° rotation. After counter-clockwise rotation, the text became readable.
Difficult characters:
Y0u— capital Y, then zero, then lowercase udecrYpTED— mixed case@nD— @ symbol instead of af0unD— zero instead of oh00000ray— five zeros (not letter O)
Task Features
- Multi-stage: first cryptography, then steganography
- Visual steganography: data encoded in function sizes
- Image transformations: flip + rotate required for readability
- Threshold selection: correct threshold (70) is critical for visualization
- Leetspeak: flag uses mixed case and character substitutions