Skip to content

Exciting Outpost Recon


Description

Write Up: offpath
Format du flag: HTB{flag}

Enoncé

Nous avons un script Python qui chiffre un fichier plaintext.txt en utilisant une clé générée aléatoirement de 32 octets. Le chiffrement est effectué par blocs de 32 octets en utilisant l'algorithme de hachage SHA-256 pour mettre à jour la clé après chaque bloc.

We have a Python script that encrypts a plaintext.txt file using a randomly generated key of 32 bytes. Encryption is performed in blocks of 32 bytes using the SHA-256 hashing algorithm to update the key after each block.


Code source

from hashlib import sha256
import os

LENGTH = 32

def encrypt_data(data, k):
    data += b'\x00' * (-len(data) % LENGTH)
    encrypted = b''

    for i in range(0, len(data), LENGTH):
        chunk = data[i:i+LENGTH]

        for a, b in zip(chunk, k):
            encrypted += bytes([a ^ b])

        k = sha256(k).digest()

    return encrypted

key = os.urandom(32)

with open('plaintext.txt', 'rb') as f:
    plaintext = f.read()

assert plaintext.startswith(b'Great and Noble Leader of the Tariaki') # have to make sure we are aptly sycophantic

with open('output.txt', 'w') as f:
    enc = encrypt_data(plaintext, key)
    f.write(enc.hex())

Solution détaillée

Le fichier chiffré output.txt nous est fourni et contient les données chiffrées. Nous savons également que le texte en clair commence par la chaîne Great and Noble Leader of the Tariaki.

Analyse du Chiffrement

Le script utilise une clé de 32 octets pour chiffrer les données par XOR, puis met à jour cette clé à chaque bloc de 32 octets en utilisant SHA-256. Cela signifie que si nous connaissons un bloc de texte en clair et son équivalent chiffré, nous pouvons récupérer la clé initiale.

Étapes de la Résolution
  1. Extraction du Bloc Chiffré Connu : Puisque nous connaissons les premiers 32 octets du texte en clair, nous pouvons utiliser cette information pour extraire la clé initiale.

  2. Calcul de la Clé Initiale : En utilisant la formule de XOR (a ^ b = c), où a est le texte en clair, b est la clé, et c est le texte chiffré, nous pouvons récupérer la clé initiale.

  3. Déchiffrement des Données : En utilisant la clé initiale, nous pouvons déchiffrer les données en appliquant le même algorithme de XOR et en mettant à jour la clé après chaque bloc.

Voici le code de déchiffrement que nous avons utilisé :

from hashlib import sha256

LENGTH = 32

# Données connues
known_plaintext = b'Great and Noble Leader of the Tariaki'
output_hex = 'fd94e649fc4c898297f2acd4cb6661d5b69c5bb51448687f60c7531a97a0e683072bbd92adc5a871e9ab3c188741948e20ef9afe8bcc601555c29fa6b61de710a718571c09e89027413e2d94fd3126300eff106e2e4d0d4f7dc8744827731dc6ee587a982f4599a2dec253743c02b9ae1c3847a810778a20d1dff34a2c69b11c06015a8212d242ef807edbf888f56943065d730a703e27fa3bbb2f1309835469a3e0c8ded7d676ddb663fdb6508db9599018cb4049b00a5ba1690ca205e64ddc29fd74a6969b7dead69a7341ff4f32a3f09c349d92e0b21737f26a85bfa2a10d'
output_bytes = bytes.fromhex(output_hex)

# Extraire les 32 premiers octets chiffrés
encrypted_chunk = output_bytes[:32]

# Brute force pour retrouver la clé initiale
initial_key = bytes([a ^ b for a, b in zip(encrypted_chunk, known_plaintext[:32])])

# Fonction de déchiffrement
def decrypt_data(data, k):
    decrypted = b''

    for i in range(0, len(data), LENGTH):
        chunk = data[i:i+LENGTH]

        for a, b in zip(chunk, k):
            decrypted += bytes([a ^ b])

        k = sha256(k).digest()

    return decrypted

# Déchiffrement des données complètes
decrypted_data = decrypt_data(output_bytes, initial_key)
print(decrypted_data)