Матрешка (Matreshka)
Матрешка (Matreshka)
Platform: hackerlab | Category: Forensics | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-01-06 | Status: Solved Techniques: nested_archive_extraction, password_pattern_discovery, scripted_extraction
Summary
Task: Extract flag from 26 nested password-protected ZIP archives. Solution: Discovered password pattern where each archive's password is the previous archive's filename, automated extraction with Python script.
Матрешка (Matreshka) — HackerLab
Description
"Жизнь – матрёшка: ждёшь новое, а получаешь старое" (Life is a matryoshka: you expect something new, but get something old)
Provided file: task.tar
Analysis
Initial Inspection
bash read-only • copy allowed$ tar -xvf task.tar flag_A1.zip $ unzip -l flag_A1.zip Archive: flag_A1.zip Length Date Time Name --------- ---------- ----- ---- 3184 2024-05-04 00:00 flag_B2.zip --------- ------- 3184 1 file
The first archive contains a second archive. A classic "matryoshka" — nested archives.
Password Pattern Discovery
bash read-only • copy allowed$ unzip flag_A1.zip Archive: flag_A1.zip creating: flag_B2.zip $ unzip flag_B2.zip Archive: flag_B2.zip [flag_B2.zip] flag_C3.zip password:
The second archive is password-protected. After analysis, a pattern was discovered:
- Password for each archive = name of the previous archive (without .zip)
flag_B2.zip-> passwordflag_A1flag_C3.zip-> passwordflag_B2- and so on...
Nesting Structure
task.tar
└── flag_A1.zip (no password)
└── flag_B2.zip (password: flag_A1)
└── flag_C3.zip (password: flag_B2)
└── flag_D4.zip (password: flag_C3)
└── ... (26 levels)
└── flag_Z26.zip (password: flag_Y25)
└── flag.txt
Total of 26 nested archives (A1 - Z26), corresponding to the number of letters in the alphabet.
Solution
Automated Script
python read-only • copy allowed#!/usr/bin/env python3 """ Matreshka Solver - Nested ZIP extraction with password pattern Password for each archive = filename of previous archive (without .zip) """ import zipfile import os def extract_matreshka(): prev_name = None current_zip = "flag_A1.zip" count = 0 while os.path.exists(current_zip): try: with zipfile.ZipFile(current_zip, 'r') as zf: for info in zf.infolist(): # Check if encrypted (flag_bits & 0x1) is_encrypted = info.flag_bits & 0x1 if is_encrypted and prev_name: password = prev_name.encode() zf.extractall(pwd=password) print(f"[+] {current_zip} -> password: {prev_name}") else: zf.extractall() print(f"[+] {current_zip} (no password)") extracted = info.filename count += 1 # Check if we found the flag if not extracted.endswith('.zip'): print(f"\n[!] Found: {extracted}") with open(extracted, 'r') as f: print(f"[FLAG] {f.read().strip()}") return count # Prepare for next iteration prev_name = current_zip.replace('.zip', '') current_zip = extracted break except Exception as e: print(f"[-] Error: {e}") return count return count if __name__ == "__main__": print("=== Matreshka Solver ===\n") total = extract_matreshka() print(f"\n[*] Total archives extracted: {total}")
Execution
bash read-only • copy allowed$ python3 solve.py === Matreshka Solver === [+] flag_A1.zip (no password) [+] flag_B2.zip -> password: flag_A1 [+] flag_C3.zip -> password: flag_B2 [+] flag_D4.zip -> password: flag_C3 ... [+] flag_Y25.zip -> password: flag_X24 [+] flag_Z26.zip -> password: flag_Y25 [!] Found: flag.txt [FLAG] CODEBY{REDACTED} [*] Total archives extracted: 26
Alternative Approaches
Bash one-liner (manual)
bash read-only • copy allowed# For each level manually: unzip flag_A1.zip unzip -P flag_A1 flag_B2.zip unzip -P flag_B2 flag_C3.zip # ... and so on 26 times
Using 7z
bash read-only • copy allowed# 7z can prompt for password interactively for i in {A..Z}; do 7z x "flag_${i}*.zip" -p"flag_${prev}" prev="${i}${num}" done
Notes
- The task name "Matryoshka" is a direct hint at the nested structure
- The quote "you expect something new, but get something old" hints at the repeating pattern
- 26 levels = 26 letters of the alphabet (A-Z)
- The flag contains leetspeak: M47RY0SHK4 = MATRYOSHKA, D3F3473D = DEFEATED