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
-
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.
-
Calcul de la Clé Initiale : En utilisant la formule de XOR (a ^ b = c), où
aest le texte en clair,best la clé, etcest le texte chiffré, nous pouvons récupérer la clé initiale. -
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)