Writeup - Challenge Venona
- Catégorie :
Cryptanalysis - Fichiers fournis :
DIANA.tiff,MESSAGES.txt - Format du flag :
texsaw{FLAG} - Auteur du WriteUp :
DonAsako
Contexte
Nous sommes déployés au cœur de la jungle vietnamienne pour une mission de reconnaissance. Notre équipe découvre un poste de communication abandonné. En tant que cryptanalyste de l’unité, vous devez analyser les documents récupérés, comprenant :
- Une table de chiffrement trouvée dans le fichier image
DIANA.tiff - Deux messages en clair et trois messages chiffrés dans
MESSAGES.txt
L’objectif est de trouver un message critique contenant des détails sur une opération ennemie et d’en extraire le flag.
🔍 Observations initiales
Le fichier DIANA.tiff révèle une table de Vigenère inversée. Sur la droite, on observe un carré de Vigenère modifié où chaque ligne est une permutation de l’alphabet suivant une logique spécifique.
Le fichier MESSAGES.txt contient :
- 2 messages en clair
- 3 messages chiffrés
Démarche pas à pas
-
Comparaison de longueur : On commence par comparer les longueurs des messages en clair et chiffrés, dans l’idée d’associer un message en clair à un message chiffré de même longueur.
-
Hypothèse : Si un message en clair a la même longueur qu’un message chiffré, on suppose qu’ils sont liés. On peut alors déduire une clé potentielle à partir de ce couple, et tester cette clé sur les autres messages chiffrés pour tenter leur déchiffrement.
-
Déchiffrement : Avec la clé récupérée, on essaie de déchiffrer les autres messages.
-
Extraction du flag : Le flag est probablement caché dans le message chiffré qui n’a pas de message en clair correspondant. On teste la clé dérivée sur ce message pour l’extraire.
Processus de déchiffrement
===== MESSAGES EN CLAIR =====
-OPERATION BLUE EAGLE MOVING TO SECTOR FOUR STOP REQUEST EXTRACTION AT BLUE EAGLE
-AGENT SUNFLOWER COMPROMISED NEAR HANOI STOP ABORT MISSION COMPROMISED
===== MESSAGES CHIFFRÉS =====
-RCPZURNPAQELEPJUJZEGAMVMXWVWCTBMHKNYEEAZVXQWVKGMRVWXDLCANHLGY
-FLPDBSBQIGBJECHMIOZGJMQONXJANFPQYQPWIIONYKNERKHIABLJTPTAOZMDGZUTAESK
-KDPRMZZKNBECTGTKMKQOWXKCHMVNDOPQXUWJJLECUCLBQKKVDXJNUEYFIDAGVIUG
On commence par associer les messages chiffrés et en clair :
# On enlève les espaces des messages en clair :
plaintext_messages = [
"OPERATION BLUE EAGLE MOVING TO SECTOR FOUR STOP REQUEST EXTRACTION AT BLUE EAGLE",
"AGENT SUNFLOWER COMPROMISED NEAR HANOI STOP ABORT MISSION COMPROMISED"
]
plaintext_messages = [message.replace(" ", "") for message in plaintext_messages]
encrypted_messages = [
"RCPZURNPAQELEPJUJZEGAMVMXWVWCTBMHKNYEEAZVXQWVKGMRVWXDLCANHLGY",
"FLPDBSBQIGBJECHMIOZGJMQONXJANFPQYQPWIIONYKNERKHIABLJTPTAOZMDGZUTAESK",
"KDPRMZZKNBECTGTKMKQOWXKCHMVNDOPQXUWJJLECUCLBQKKVDXJNUEYFIDAGVIUG"
]
# On compare la taille des messages chiffrés et en clair pour les associer
pair = [[], []]
for plaintext_message in plaintext_messages:
for encrypted_message in encrypted_messages:
if len(plaintext_message) == len(encrypted_message):
pair[0].append(plaintext_message)
pair[1].append(encrypted_message)
encrypted_messages.remove(encrypted_message)
On obtient donc 2 paires message clair/message chiffré, et un message chiffré seul :
OPERATIONBLUEEAGLEMOVINGTOSECTORFOURSTOPREQUESTEXTRACTIONATBLUEEAGLE
FLPDBSBQIGBJECHMIOZGJMQONXJANFPQYQPWIIONYKNERKHIABLJTPTAOZMDGZUTAESK
AGENTSUNFLOWERCOMPROMISEDNEARHANOISTOPABORTMISSIONCOMPROMISED
RCPZURNPAQELEPJUJZEGAMVMXWVWCTBMHKNYEEAZVXQWVKGMRVWXDLCANHLGY
================================================================
KDPRMZZKNBECTGTKMKQOWXKCHMVNDOPQXUWJJLECUCLBQKKVDXJNUEYFIDAGVIUG
On récupère la clé du premier message :
def char_to_int(c):
return ord(c.upper()) - ord('A')
def int_to_char(i):
return chr(i % 26 + ord('A'))
def find_key(plaintext, ciphertext):
key = ''
for p, c in zip(plaintext, ciphertext):
shift = (char_to_int(c) - char_to_int(p)) % 26
key += int_to_char(shift)
return key
pair = [
(
'OPERATIONBLUEEAGLEMOVINGTOSECTORFOURSTOPREQUESTEXTRACTIONATBLUEEAGLE',
'AGENTSUNFLOWERCOMPROMISEDNEARHANOISTOPABORTMISSIONCOMPROMISED',
),
(
'FLPDBSBQIGBJECHMIOZGJMQONXJANFPQYQPWIIONYKNERKHIABLJTPTAOZMDGZUTAESK',
'RCPZURNPAQELEPJUJZEGAMVMXWVWCTBMHKNYEEAZVXQWVKGMRVWXDLCANHLGY',
)
]
for p, c in zip(pair[0], pair[1]):
partial_key = find_key(p, c)
print(f"Clé trouvée : {partial_key}")
On trouve 2 clés identiques :
Clé trouvée : RWLMBZTCVFQPAYHGXKNSOEDIUJRWLMBZTCVFQPAYHGXKNSOEDIUJRWLMBZTCVFQPAYHG
Clé trouvée : RWLMBZTCVFQPAYHGXKNSOEDIUJRWLMBZTCVFQPAYHGXKNSOEDIUJRWLMBZTCV
On tente maintenant de déchiffrer le dernier message avec cette clé :
def decrypt(ciphertext, key):
decrypted_text = ''
for i, c in enumerate(ciphertext):
if c.isalpha():
c_index = char_to_int(c)
k_index = char_to_int(key[i % len(key)])
p_index = (c_index - k_index) % 26
decrypted_text += int_to_char(p_index)
else:
decrypted_text += c
return decrypted_text
key = "RWLMBZTCVFQPAYHGXKNSOEDIUJRWLMBZTCVFQPAYHGXKNSOEDIUJRWLMBZTCVFQPAYHG"
encrypted = "KDPRMZZKNBECTGTKMKQOWXKCHMVNDOPQXUWJJLECUCLBQKKVDXJNUEYFIDAGVIUG"
print(decrypt(encrypted, key))
Résultat :
THEFLAGISWONTIMEPADWITHUNDERSCORESBETWEENWORDSWRAPPEDINTHEHEADER
Flag
Le message déchiffré est :
LE FLAG EST WON TIME PAD AVEC DES SOULIGNÉS ENTRE LES MOTS ENCAPSULÉ DANS L’ENTÊTE
Ainsi, le flag final est : texsaw{WON_TIME_PAD}