Post

Matryoshka Bits : Forensic & Automatisation

Matryoshka Bits : automatisation de l'extraction de 150 archives imbriquées en Python et reconstruction d'une image JPEG à partir de bits ASCII.

Matryoshka Bits : Forensic & Automatisation

Contexte narratif

Les secrets les mieux gardés sont ceux qu’on cache à la vue de tous.”

Fichier fourni : challenge.zip


Étape 1 — Première reconnaissance

On commence toujours par identifier ce qu’on a entre les mains.

1
2
file challenge.zip
# challenge.zip: Zip archive data, at least v1.0 to extract, compression method=store

Un fichier ZIP classique. On extrait.

1
2
unzip challenge.zip
# → layer_001.zip

On retombe sur un ZIP. On extrait encore.

1
2
unzip layer_001.zip
# → layer_002.zip

Et encore… À ce stade, le participant comprend qu’il va falloir automatiser.


Étape 2 — Automatiser l’extraction des 150 couches

Extraire 150 ZIP à la main c’est hors de question. On écrit un script Python.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# solve_matryoshka.py
import os, subprocess, shutil, glob

WORK = "solve_work"
os.makedirs(WORK, exist_ok=True)
shutil.copy("challenge.zip", f"{WORK}/challenge.zip")

current = f"{WORK}/challenge.zip"

for i in range(1, 151):
    print(f"[{i:03d}/150] Extraction de {os.path.basename(current)}...")
    subprocess.run(
        ["unzip", "-o", "-d", WORK, current],
        capture_output=True
    )
    os.remove(current)

    files = glob.glob(f"{WORK}/*")
    if not files:
        print("❌ Rien trouvé, arrêt.")
        break
    current = files[0]

print(f"\n✅ Fichier final : {current}")
1
2
python3 solve_matryoshka.py
# ✅ Fichier final : solve_work/digits.bin

Étape 3 — Analyser le fichier final

On identifie ce qu’on vient d’extraire.

1
2
file solve_work/digits.bin
# digits.bin: ASCII text, with very long lines (65536), with no line terminators

Intéressant — un fichier .bin qui est en réalité du texte ASCII. On jette un œil au contenu.

1
2
head -c 64 solve_work/digits.bin
# 1111111111011000111111111110000000000000000100000100101001000110

Une longue suite de 0 et de 1. Ce sont des bits représentés en ASCII.


Étape 4 — Décoder la chaîne binaire

On analyse la structure et on identifie le type de fichier caché via les magic bytes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# decode.py
with open("solve_work/digits.bin", "r") as f:
    bits = f.read().strip()

print(f"Longueur totale  : {len(bits)} bits")
print(f"Divisible par 8  : {len(bits) % 8 == 0}")

data = bytearray()
for i in range(0, len(bits), 8):
    data.append(int(bits[i:i+8], 2))

print(f"Magic bytes (hex) : {data[:4].hex()}")

with open("output.jpg", "wb") as f:
    f.write(data)

print("Image extraite : output.jpg")
1
2
3
4
Longueur totale  : 70960 bits
Divisible par 8  : True
Magic bytes (hex) : ffd8ffe0
Image extraite   : output.jpg

FFD8FF = signature JPEG. On a reconstruit une image.


Étape 5 — Récupérer le flag

1
xdg-open output.jpg

L’image affiche le flag en clair.

1
CYB3R{b1t5_4r3_3v3rywh3r3}

Concepts testés

ConceptDescription
AutomatisationSavoir scripter face à une tâche répétitive
Identification de fichierUtiliser file et lire les magic bytes
Représentation binaireComprendre bits vs bytes
Reconstruction de fichierConvertir une chaîne de bits en fichier binaire
Persévérance150 couches = challenge de mindset autant que technique

This post is licensed under CC BY 4.0 by the author.