← Back to Writeups
CUSTOMEasyForensics

Матрешка (Matreshka)

XESXOR9/2/20263 min read
#forensics#custom#easy#nested_archive_extraction#password_pattern_discovery#scripted_extraction#linux

Матрешка (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
$ 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
$ 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 -> password flag_A1
  • flag_C3.zip -> password flag_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
#!/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
$ 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
# 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
# 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 ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍