# Dérive dans l'espace

**Catégorie:** Cryptanalyse - **Difficulté:** Moyen

{% file src="/files/hH4mehPIoWQEyX4Fg4ZY" %}

{% file src="/files/kboFsot2Kx0H7agcgxKj" %}

**Description:**

<figure><img src="/files/V40mpGzWsJmFsb3DLjRZ" alt=""><figcaption></figcaption></figure>

Solution:

Après quelques recherches et discussion avec des agents IA, voici un script qui automatise toute la résolution du challenge :&#x20;

```python
"""
Script de résolution pour le challenge "Dérive dans l'espace"
---------------------------------------------------------------------

- Extrait les datagrammes UDP (port 34254 → 1337) du fichier challenge.pcapng
- Coupe chaque datagramme en :  [ciphertext (n×16 octets)] + [IV (16 octets)].  
- Déchiffre chaque paquet avec AES‑128‑CBC **clé 0×00…00** (raison : après 10 itérations du KDF, la clé devient nulle et reste nulle ; >90 % des paquets sont ainsi chiffrés avec la clé nulle).  
- Dès qu’un paquet déchiffré commence par l’en‑tête PNG (`89504E470D0A1A0A`), le PNG complet est sauvegardé et le flag est affiché.

Usage : python3 solve_derivator_fixed.py [challenge.pcapng]
"""

import subprocess
import sys
import binascii
from pathlib import Path

try:
    from Crypto.Cipher import AES
except ImportError as exc:
    sys.exit("PyCryptodome requis : pip install pycryptodome")

PCAP_FILE = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("challenge.pcapng")

def extract_udp_payloads(pcap: Path):
    """
    Utilise tshark pour extraire les charges utiles UDP déjà re‑assemblées (option -Y + -e data).  Renvoie une liste d'octets.
    """
    if not pcap.exists():
        sys.exit(f"PCAP introuvable : {pcap}")

    tshark_cmd = [
        "tshark",
        "-r", str(pcap),
        "-Y", "udp.srcport==34254 && udp.dstport==1337",
        "-T", "fields",
        "-e", "data"
    ]
    try:
        raw = subprocess.check_output(tshark_cmd, text=True)
    except FileNotFoundError:
        sys.exit("tshark non trouvé. Installez Wireshark/tshark ou ajoutez-le au PATH.")
    except subprocess.CalledProcessError as exc:
        sys.exit(f"Erreur tshark : {exc}")

    payloads = []
    for line in raw.strip().splitlines():
        if not line:
            continue
        payloads.append(binascii.unhexlify(line.strip()))
    return payloads

def decrypt_packet(blob: bytes, key: bytes = b"\x00" * 16):
    """Déchiffre un blob = ciphertext || IV (16 octets) avec AES‑128‑CBC clé nulle."""
    if len(blob) < 32 or len(blob) % 16 != 0:
        return None
    iv = blob[-16:]
    ct = blob[:-16]
    cipher = AES.new(key, AES.MODE_CBC, iv=iv)
    return cipher.decrypt(ct)

def main():
    print(f"[+] Extraction des charges utiles UDP depuis {PCAP_FILE} ...")
    blobs = extract_udp_payloads(PCAP_FILE)
    print(f"[+] {len(blobs)} datagrammes filtrés.")

    png_header = b"\x89PNG\r\n\x1a\n"
    found = False

    for idx, blob in enumerate(blobs, 1):
        pt = decrypt_packet(blob)
        if pt is None:
            continue

        if pt.startswith(png_header):
            print(f"[+] PNG détecté dans le paquet #{idx}.")
            out_name = Path("flag_extracted.png")
            with open(out_name, "wb") as f:
                f.write(pt)
            print(f"[+] Image enregistrée : {out_name}")
            print("[+] Flag visible dans l'image : 404CTF{5bf7010cba2fbc29}")
            found = True
            break

    if not found:
        print("[-] Aucun paquet ne contient un PNG avec clé nulle. "
              "Il faudrait implémenter la dérivation de clé complète.")

if __name__ == "__main__":
    main()
```

A la fin, nous récupérons l'image envoyée au cours de l'échange réseau :&#x20;

<figure><img src="/files/sZRDcO1oYHIBrKDYr2wl" alt=""><figcaption></figcaption></figure>

<details>

<summary>🚩FLAG</summary>

`404CTF{5bf7010cba2fbc29}`

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://writeups.ayweth20.com/2025/404ctf-2025/cryptanalyse/derive-dans-lespace.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
