Introduction đź“Ś
Le contexte reste le même que lors de la première partie et seconde partie. Une victime de plus est tombée sous le coup d’un rançongiciel. Le paiement de la rançon n’est pas envisagée vu le montant demandé. Nous sommes donc appelés pour essayer de restaurer les fichiers chiffrés.
Cette fois-ci, l’objectif est de dĂ©chiffrer le fichier data ci-joint.
La rĂ©solution de l’Ă©preuve s’effectue toujours Ă l’aide du fichier mem.dmp.tar.xz
. Pour rappel, il s’agit d’une image mĂ©moire de l’ordinateur de la victime. Concrètement, celle-ci correspond au contenu de la mĂ©moire volatile (RAM
) au moment de l’acquisition. De plus, nous avons Ă disposition le fichier data
à déchiffrer.
1. Étude de l’algorithme de chiffrement đź“‹
Pour pouvoir déchiffrer le fichier data
, nous allons devoir Ă©tudier l’algorithme de chiffrement mis en place par ce rançongiciel. Comme nous avons accès au code source, cela simplifie grandement le processus.
Un zoom rapide sur ransomware.go
(encore oui)
Replongeons nous dans le fichier /cmd/ransomware/ransomware.go, ligne 223 cette fois ci.
// Encrypt the file sending the content to temporary file
err = file.Encrypt(keys["enckey"], tempFile)
if err != nil {
cmd.Logger.Println(err)
continue
}
Nous pouvons constater que la fonction de chiffrement Encrypt()
provient du fichier file
. Elle semble prendre en paramètre la clĂ© de chiffrement et un nom de fichier temporaire. Il est donc nĂ©cessaire d’analyser ce que fait prĂ©cisĂ©ment cette fameuse fonction.
Un zoom sur file.go
Le fonctionnement de l’algorithme de chiffrement employĂ© par la fonction Encrypt()
se trouve Ă partir de la ligne 21 du fichier cryptofs/file.go.
func (file *File) Encrypt(enckey string, dst io.Writer) error {
[...]
// Create a 128 bits cipher.Block for AES-256
block, err := aes.NewCipher([]byte(enckey))
if err != nil {
return err
}
// The IV needs to be unique, but not secure
iv := make([]byte, aes.BlockSize)
if _, err = io.ReadFull(rand.Reader, iv); err != nil {
return err
}
// Get a stream for encrypt/decrypt in counter mode (best performance I guess)
stream := cipher.NewCTR(block, iv)
// Write the Initialization Vector (iv) as the first block
// of the dst writer
dst.Write(iv)
[...]
}
Le première partie du code nous permet de constater l’utilisation de l’algorithme de chiffrement AES-256
. Le chiffrement s’effectue en counter mode (CTR), observable un peu plus bas.
Le second partie du code, quant Ă elle, nous indique que l’IV
est le premier bloc du fichier chiffrĂ©. C’est une bonne nouvelle pour nous. En effet, comme nous disposons des fichiers chiffrĂ©s et de la clĂ© de chiffrement, il nous suffit d’extraire l’IV de ceux-ci pour pouvoir les dĂ©chiffrer.
2. DĂ©chiffrement du fichier data
🔓
Extraction de l’IV
Pour extraire l’IV
de data
, nous pouvons utiliser xxd
pour obtenir le contenu du fichier en hexadécimal et fold
pour le dĂ©couper en bloc de 32 caractères (rappelez-vous, l’IV est une chaine de 32 caractères hexadĂ©cimaux). Ensuite, nous pouvons utiliser head
pour ne garder que le premier bloc Ă l’aide de l’option -n 1
.
┌──(hashp4㉿kali)-[~/Bureau]
└─$ xxd -p data | fold -b32 | head -n 1
b627d24fc90dfe7ce421c43312dc2f2e
Ainsi, nous obtenons l’IV
correspondant Ă notre fichier data
: b627d24fc90dfe7ce421c43312dc2f2e
.
DĂ©chiffrement via Cyberchef (flemmard)
Pour déchiffrer notre fichier, nous pouvons nous aider de Cyberchef. Pour ce faire, il faut lui donner un entrée (input) le contenu du fichier chiffré (ici data) en hexadécimal. Pour ce faire nous pouvons utiliser xxd
.
(⚠️ : n’oublions pas de supprimer le contenu correspondant Ă l’IV de notre fichier, sans quoi le dĂ©chiffrement ne marchera pas. Nous utilisons l’outil sed
pour le faire).
┌──(hashp4㉿kali)-[~/Bureau]
└─$ xxd -p -c0 data | sed 's/b627d24fc90dfe7ce421c43312dc2f2e//g'
abf961d204bf8c684dff45fc658d5bba4da43a8 [...]7febfd28649595e720a8
Le rĂ©sultat Ă©tant trop grand, je n’Ă©cris ici que les caractères correspondant au dĂ©but et Ă la fin du fichier.
Nous devons ensuite copier/coller ce résultat dans Cyberchef, sélectionner la recette AES Decrypt
et rentrer les paramètres suivants :
- Key (UTF-8) :
95511870061fb3a2899aa6b2dc9838aa
- IV (HEX) :
b627d24fc90dfe7ce421c43312dc2f2e
- Mode :
CTR
- Input :
HEX
- Output :
RAW
Nous pouvons remarquer que le dĂ©chiffrement semble bien effectif puisque nous remarquons le header d’un fichier ZIP 50 4b 03 04
correspondant Ă PK
et d’autres chaines de caractères telles que :
- _rels/.rels
- docProps/core.xml
- docProps/app.xml
- word/_rels/document.xml.rels
- word/document.xml […]
Celles-ci nous portent Ă croire que nous avons Ă faire Ă un document Word. Notre fichier serait donc l’Ă©quivalent de flag.docx
que nous avions trouvé lors de la première partie de cette épreuve. Nous pouvons ensuite télécharger le fichier sur notre machine. Ici, nous le nommons flag.zip
. Nous pouvons maintenant le dézipper :
┌──(hashp4㉿kali)-[~/Bureau]
└─$ unzip flag.zip
Archive: flag.zip
inflating: _rels/.rels
inflating: docProps/core.xml
inflating: docProps/app.xml
inflating: word/_rels/document.xml.rels
inflating: word/document.xml
inflating: word/styles.xml
inflating: word/fontTable.xml
inflating: word/settings.xml
inflating: [Content_Types].xml
Le contenu d’un fichier word se trouve en gĂ©nĂ©ral dans le document word/document.xml
. Nous pouvons donc utiliser grep
pour afficher directement le flag sans s’embĂŞter Ă l’ouvrir :
┌──(hashp4㉿dragon)-[~/Bureau]
└─$ grep "ECSC{" word/document.xml
[...]
</w:rPr><w:t>Flag: ECSC{M4ud1t3_C4mp4gn3_2_r4NC0nG1c13L}</w:t></w:r></w:p><w:sectPr>
[...]
Et voilà ! Le déchiffrement est un succès. Regardons maintenant une autre manière de faire.
DĂ©chiffrement via Python (street cred++)
Pour déchiffrer notre fichier data
, nous pouvons Ă©galement faire appel Ă notre talent de programmeur (ou appel Ă notre ami ChatGPT :p). Ayant une plus grande familiaritĂ© avec Python, c’est avec celui-ci que nous allons pouvoir dĂ©chiffrer notre fichier. Cependant, libre Ă vous de choisir un autre langage de programmation pour cet exercice.
Voici le script decrypt.py
en question :
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
def decrypt_file(input_file, output_file, key):
# Read encrypted content from file
with open(input_file, 'rb') as file:
encrypted_content = file.read()
# Extract IV (first 32 characters)
iv = encrypted_content[:16]
print(f"The IV of the file is : {iv.hex()}")
encrypted_data = encrypted_content[16:]
# Initialize AES-CTR cipher
backend = default_backend()
cipher = Cipher(algorithms.AES(key), modes.CTR(iv), backend=backend)
decryptor = cipher.decryptor()
# Decrypt the content
decrypted_data = decryptor.update(encrypted_data) + decryptor.finalize()
# Write the decrypted content to the output file
with open(output_file, 'wb') as file:
file.write(decrypted_data)
def main():
input_file = input("Enter the path to the encrypted file: ")
output_file = input("Enter the path for the output file (decrypted content): ")
key = input("Enter the AES key: ").encode("utf-8")
flag = decrypt_file(input_file, output_file, key)
print(f"Decryption completed. Decrypted content saved in '{output_file}'.")
if __name__ == "__main__":
main()
Le principe est simple :
- demander Ă l’utilisateur le chemin du fichier chiffrĂ©,
- demander Ă l’utilisateur le chemin et le nom du fichier dans lequel il souhaite mettre le contenu dĂ©chiffrĂ©,
- demander Ă l’utilisateur la clĂ© de dĂ©chiffrement.
Ensuite, ce script va extraire automatiquement l’IV du fichier chiffrĂ©, l’afficher Ă l’utilisateur et enfin dĂ©chiffrer son contenu.
Il serait intéressant de modifier ce script pour pouvoir déchiffrer tous les fichiers ayant pour extension .chiffré
et de nommer ceux-ci par leur nom original (il suffit de décoder leur nom en base64
).
Voici un exemple d’utilisation :
┌──(hashp4㉿kali)-[~/Bureau]
└─$ python3 decrypt.py
Enter the path to the encrypted file: data
Enter the path for the output file (decrypted content): /tmp/flag
Enter the AES key: 95511870061fb3a2899aa6b2dc9838aa
The IV of the file is : b627d24fc90dfe7ce421c43312dc2f2e
Decryption completed. Decrypted content saved in '/tmp/flag'.
Nous pouvons vĂ©rifier le type du fichier Ă l’aide de file
:
┌──(hashp4㉿kali)-[~/Bureau]
└─$ file /tmp/flag
/tmp/flag: Microsoft Word 2007+
Le script est fonctionnel puisque la commande détecte bien le fichier déchiffré comme un document Word. Nous pouvons donc le dézipper et utiliser le même grep
que précédemment :
┌──(hashp4㉿dragon)-[~/Bureau]
└─$ grep "ECSC{" /tmp/word/document.xml
[...]
</w:rPr><w:t>Flag: ECSC{M4ud1t3_C4mp4gn3_2_r4NC0nG1c13L}</w:t></w:r></w:p><w:sectPr>
[...]
Nous retrouvons bien notre flag. :D
3. Flag đźš©
Nous avons donc réussi à aider notre victime à déchiffrer ses fichiers.
Le flag pour cette dernière épreuve est donc : ECSC{M4ud1t3_C4mp4gn3_2_r4NC0nG1c13L}
.
Ce troisième et dernier challenge marque la fin de l’Ă©preuve. Je vous remercie d’avoir lu mes writeups et espère avoir Ă©tĂ© assez clair dans mes explications. N’hĂ©sitez pas Ă me faire vos retours en me contactant directement sur Discord ou Twitter. ;)
BONUS - Retrouver le flag sans le fichier data
đź’ˇ
Etant de nature curieuse, j’ai voulu voir s’il Ă©tait possible de retrouver le flag directement Ă l’aide du fichier flag.docx
chiffré (ZmxhZy5kb2N4.chiffré
) Ă partir du dump mĂ©moire. Pour rappel, nous avions trouvĂ© son adresse virtuelle dans le dump suite Ă l’utilisation du plugin windows.filescan
de Volatility3.
┌──(hashp4㉿kali)-[~/Bureau]
└─$ python3 ~/Tools/volatility3/vol.py -f mem.dmp windows.filescan | grep "ZmxhZy5kb2N4"
0xe000123988d0.0\ZmxhZy5kb2N4.chiffré 216
De ce fait, j’ai ensuite rĂ©cupĂ©rĂ© le fichier Ă l’aide du plugin windows.dumpfiles
et de l’option --virtaddr
suivie de l’adresse virtuelle de ZmxhZy5kb2N4.chiffrĂ©
.
┌──(hashp4㉿kali)-[~/Bureau]
└─$ python3 vol.py -f mem.dmp windows.dumpfiles --virtaddr 0xe000123988d0
Volatility 3 Framework 2.5.2
Progress: 100.00 PDB scanning finished
Cache FileObject FileName Result
DataSectionObject 0xe000123988d0 ZmxhZy5kb2N4.chiffré file.0xe000123988d0.0xe00010401370.DataSectionObject.ZmxhZy5kb2N4.chiffré.dat
J’ai ensuite exĂ©cutĂ© mon script Python sur le fichier chiffrĂ© :
┌──(hashp4㉿kali)-[~/Bureau]
└─$ python3 decrypt.py
Enter the path to the encrypted file: ZmxhZy5kb2N4.chiffré
Enter the path for the output file (decrypted content): /tmp/flag
Enter the AES key: 95511870061fb3a2899aa6b2dc9838aa
The IV of the file is : b627d24fc90dfe7ce421c43312dc2f2e
Decryption completed. Decrypted content saved in '/tmp/flag'.
┌──(hashp4㉿kali)-[~/Bureau]
└─$ file /tmp/flag
/tmp/flag: Microsoft Word 2007+
Celui-ci Ă©tant bel et bien considĂ©rĂ© comme un document Word, je l’ai dĂ©zippĂ© et j’ai utilisĂ© grep
pour en extraire le flag :
┌──(hashp4㉿dragon)-[~/Bureau]
└─$ grep "ECSC{" /tmp/word/document.xml
[...]
</w:rPr><w:t>Flag: ECSC{M4ud1t3_C4mp4gn3_2_r4NC0nG1c13L}</w:t></w:r></w:p><w:sectPr>
[...]
Il est donc possible de rĂ©soudre cette dernière Ă©preuve sans s’appuyer sur le fichier data
ci-joint.