# You spin me round

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

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

**Description:**

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

Solution:

Voici le script pour répondre correctement aux attentes du système tournant derrière la connexion nc :&#x20;

```python
import re
import sys
import binascii

# ───────────────────────────────────────────────────────── helpers ──

def bytes2matrix(b: bytes):
    """Transforme 16 octets en une matrice 4×4 (colonne‑major)."""
    return [list(b[i:i + 4]) for i in range(0, 16, 4)]


def matrix2bytes(m):
    """Inverse de bytes2matrix."""
    return bytes(sum(m, []))


def xtime(a: int) -> int:
    """Multiplication par x dans GF(2^8)."""
    return (((a << 1) ^ 0x1B) & 0xFF) if a & 0x80 else (a << 1)


# ─────────────────────────────────────────────  MixColumns & inverse ──

def mix_single_column(a):
    t = a[0] ^ a[1] ^ a[2] ^ a[3]
    u = a[0]
    a[0] ^= t ^ xtime(a[0] ^ a[1])
    a[1] ^= t ^ xtime(a[1] ^ a[2])
    a[2] ^= t ^ xtime(a[2] ^ a[3])
    a[3] ^= t ^ xtime(a[3] ^ u)


def mix_columns(s):
    for col in s:
        mix_single_column(col)


def inv_mix_columns(s):
    for col in s:
        u = xtime(xtime(col[0] ^ col[2]))
        v = xtime(xtime(col[1] ^ col[3]))
        col[0] ^= u
        col[1] ^= v
        col[2] ^= u
        col[3] ^= v
    mix_columns(s)


# ────────────────────────────────────────────── ShiftRows & inverse ──

def shift_rows(s):
    s[0][1], s[1][1], s[2][1], s[3][1] = s[1][1], s[2][1], s[3][1], s[0][1]
    s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2]
    s[0][3], s[1][3], s[2][3], s[3][3] = s[3][3], s[0][3], s[1][3], s[2][3]


def inv_shift_rows(s):
    s[0][1], s[1][1], s[2][1], s[3][1] = s[3][1], s[0][1], s[1][1], s[2][1]
    s[0][2], s[1][2], s[2][2], s[3][2] = s[2][2], s[3][2], s[0][2], s[1][2]
    s[0][3], s[1][3], s[2][3], s[3][3] = s[1][3], s[2][3], s[3][3], s[0][3]


# ────────────────────────────────────────── Inversion de la diffusion ──

def decrypt_linear(diff: bytes, rounds: int = 10) -> bytes:
    """Inverse la partie linéaire (ShiftRows + MixColumns) quand SubBytes=Id."""
    state = bytes2matrix(diff)

    # Tour final : seulement InvShiftRows
    inv_shift_rows(state)

    # Tours 9 → 1 : InvMixColumns puis InvShiftRows (ordre inverse du chiffrement)
    for _ in range(rounds - 1):  # 9 fois pour AES‑128
        inv_mix_columns(state)
        inv_shift_rows(state)

    return matrix2bytes(state)


# ──────────────────────────────────────────── I/O et UX interactives ──

def afficher_bytes(nom: str, val: bytes, preview: int = 4):
    print(f"{nom} (hex): {val.hex()}")
    print(f"{nom} (bin): {' '.join(format(b, '08b') for b in val[:preview])} …")


def is_hex(s: str) -> bool:
    return bool(re.fullmatch(r"[0-9a-fA-F]+", s))


def calculer_reponse(message: bytes, missile: bytes):
    print("\n—— Calcul de la différence delta = missile ⊕ message ——")
    delta = bytes(a ^ b for a, b in zip(missile, message))
    afficher_bytes("delta", delta)

    print("\n—— Inversion de la diffusion (10 tours) ——")
    plaintext = decrypt_linear(delta)
    afficher_bytes("plaintext", plaintext)
    return plaintext


# ─────────────────────────────────────────────────────────── main ──

def main():
    print("=== Solveur « You Spin Me » ===")
    print("Ce script résout le défi « You Spin Me Round » de 404CTF 2025.\n")

    print("Voici le niveau de sécurité à envoyer : 277182\n")
    print("Choisissez l'option 1 pour demander à communiquer avec le serveur.")
    print(f"Maintenant, envoyez ce message au serveur : {'0' * 32}.\n")

    # Entrée de message
    while True:
        response = input("Entrez la réponse du serveur : ").strip()
        if is_hex(response) and len(response) == 32:
            break
        print("⟹ valeur hexadécimale attendue (32 caractères).")

    print("\nMaintenant, choisissez l'option 2 pour utiliser votre arme secrète.")
    print("Vous devez fournir la valeur de missile pour calculer la réponse.\n")

    # Entrée de missile
    while True:
        missile = input("Entrez le missile reçu (32 hex) : ").strip()
        if is_hex(missile) and len(missile) == 32:
            break
        print("⟹ valeur hexadécimale attendue (32 caractères).")

    message = bytes.fromhex(response)
    missile = bytes.fromhex(missile)

    print("\n—— Valeurs reçues ——")
    afficher_bytes("message", message)
    afficher_bytes("missile", missile)

    plaintext = calculer_reponse(message, missile)

    print("\n=== Renvoyer ceci au serveur : ===\n")
    print(plaintext.hex())
    print("\nBonne chance ! ✨")


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\nInterrompu.")
```

Le script tourne quelques secondes et nous demande d’interagir avec lui. En lui renvoyant les réponses, il nous donne les infos à renvoyer au serveur pour récupérer le flag :&#x20;

<figure><img src="/files/0QWJNzbmTSXBJ614TdiL" alt="" width="375"><figcaption></figcaption></figure>

<figure><img src="/files/NDoYqle6S2JOaES1tjCa" alt="" width="375"><figcaption></figcaption></figure>

En renvoyant les valeurs au bon moment, le script calcule la bonne valeur à renvoyer au serveur afin de récupérer le flag.

<details>

<summary>🚩FLAG</summary>

`404CTF{3vErY0n3_c4n7_TuRn_1nFiN1t3Ly}`

</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/you-spin-me-round.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.
