Catégorie: Forensique
Points: 330
Description: Une victime de plus tombée sous le coup d’un rançongiciel. Le paiement de la rançon n’est pas envisagée vu le montant demandé. Vous êtes appelé pour essayer de restaurer les fichiers chiffrés. Une suite d’éléments est nécessaire pour avancer dans l’investigation et constituer le rapport d’incident. Retrouvez la clé de chiffrement de ce rançongiciel! Note : l’image disque fait environ 440 Mo compressée et environ 1.4 Go décompressée. Elle est identique au challenge 3615 Incident - 1. Réponse attendue au format ECSC{clé}.
Fichiers: mem.dmp
Une analyse du rançongiciel nous donne un pattern à retrouver qui contient la cle de chiffrement. Le cle est retrouve grace à strings
et grep
.
Maintenant qu'on connaît l'identité du ransomware on va pouvoir le décortiquer.
Pour commencer on va l'extraire du dump mémoire avec Volatillity.
>_ volatility -f mem.dmp --profile=Win10x64 procdump -p 5208 -D dump
Volatility Foundation Volatility Framework 2.6.1
Process(V) ImageBase Name Result
------------------ ------------------ -------------------- ------
0xffffe000106bb840 0x0000000000400000 ? OK: executable.5208.exe
Et maintenant on va faire un peu de reverse avec Ghidra car j'aime bien son décompilateur intégré.
Comme j'y connais pas grand chose en reverse, je décide de me focaliser sur les strings.
On remarque qu'il y a un lien vers github. Allons voir ce que c'est.
Le repo github a l'air d'être le code source du ransomware.
En comparant le code du repo avec le code décompilé il y a beaucoup de similarités. On en déduis que le code du repo correspond au malware analyse.
Dans le fichier cryptofs/file.go il y a une méthode intéressante:
func (file *File) Encrypt(enckey string, dst io.Writer) error {
[...]
}
La cle de chiffrement est passe en paramètre à la méthode Encrypt
.
En regardant ou est généré cette cle on arrive vers un fichier qui s'appelle ransomware.go
et qui contient cette méthode:
func encryptFiles() {
[...]
// Generate the id and encryption key
keys["id"], _ = utils.GenerateRandomANString(32)
keys["enckey"], _ = utils.GenerateRandomANString(32)
// Persist the key pair on server
res, err := Client.AddNewKeyPair(keys["id"], keys["enckey"])
if err != nil {
cmd.Logger.Println("Ops, something went terribly wrong when contacting the C&C... Aborting...")
cmd.Logger.Println(err)
return
}
[...]
// Encrypt the file sending the content to temporary file
err = file.Encrypt(keys["enckey"], tempFile)
[...]
}
On peut voir que la cle est générée puis envoyée sur un serveur distant
Volatility nous le confirme:
volatility -f mem.dmp --profile=Win10x64 netscan 9:44:20
Volatility Foundation Volatility Framework 2.6.1
Offset(P) Proto Local Address Foreign Address State Pid Owner Created
[...]
0xe0001265ad10 TCPv4 192.168.248.133:49774 192.168.1.25:8080 ESTABLISHED 5208 ? 2019-05-08 20:00:17 UTC+0000
[...]
Si la connexion a ete établie et envoyée vers un serveur elle est forcement quelque part dans la mémoire.
Dans le code on peut voir quelle est envoyée suivant un pattern bien précis: {"id": "%s", "enckey": "%s"}
// AddNewKeyPair persist a new keypair on server
func (c *Client) AddNewKeyPair(id, encKey string) (*http.Response, error) {
payload := fmt.Sprintf(`{"id": "%s", "enckey": "%s"}`, id, encKey)
return c.SendEncryptedPayload("/api/keys/add", payload, map[string]string{})
}
Bon bah strings est notre ami en CTF !
On va chercher toutes les lignes qui contiennent le mot enckey
et on va prendre 10 lignes au dessus et en dessous.
>_ strings mem.dmp | grep -A 10 -B 10 enckey
[...]
"C:\Users\TNKLSAI3TGT7O9\Downloads\assistance.exe"
C:\Users\TNKLSAI3TGT7O9\Downloads\assistance.exe
S-1-5-21-2377780471-3200203716-3353778491-1000
{"id": "cd18c00bb476764220d05121867d62de", "enckey": "
cd18c00bb476764220d05121867d62de64e0821c53c7d161099be2188b6cac24cd18c00bb476764220d05121867d62de64e0821c53c7d161099be2188b6cac2495511870061fb3a2899aa6b2dc9838aa422d81e7e1c2aa46aa51405c13fed15b95511870061fb3a2899aa6b2dc9838aa422d81e7e1c2aa46aa51405c13fed15b
Encrypting C:\Users\Administrateur\Contacts\desktop.ini...
C:\Users\TNKLSA~1\AppData\Local\Temp\desktop.ini
C:\Users\TNKLSA~1\AppData\Local\Temp\desktop.ini
Encrypting C:\Users\Administrateur\Documents\desktop.ini...
C:\Users\TNKLSA~1\AppData\Local\Temp\desktop.ini
C:\Users\TNKLSA~1\AppData\Local\Temp\desktop.ini
Walking C:\Users\Administrateur\Favorites\Bing.url
Walking C:\Users\Administrateur\Favorites\Bing.url
C:\Users\Administrateur\Favorites\Links\desktop.ini
[...]
Parmis toutes les sorties il y en a une qui est interessante.
{"id": "cd18c00bb476764220d05121867d62de", "enckey": "
cd18c00bb476764220d05121867d62de64e0821c53c7d161099be2188b6cac24cd18c00bb476764220d05121867d62de64e0821c53c7d161099be2188b6cac2495511870061fb3a2899aa6b2dc9838aa422d81e7e1c2aa46aa51405c13fed15b95511870061fb3a2899aa6b2dc9838aa422d81e7e1c2aa46aa51405c13fed15b
On observe le pattern {"id": "%s", "enckey": "%s"}
avec le parametre enckey
qui parrait un peu long: cd18c00bb476764220d05121867d62de64e0821c53c7d161099be2188b6cac24cd18c00bb476764220d05121867d62de64e0821c53c7d161099be2188b6cac2495511870061fb3a2899aa6b2dc9838aa422d81e7e1c2aa46aa51405c13fed15b95511870061fb3a2899aa6b2dc9838aa422d81e7e1c2aa46aa51405c13fed15b
le parametre enckey
commence par la meme cle que l'id.
On decoupe la string en 8 parts egales et on obtient 4 potentielles cles de chiffrement. En realite 3 car on peut exclure celle qui correspond à l'id.
cd18c00bb476764220d05121867d62de
64e0821c53c7d161099be2188b6cac24
cd18c00bb476764220d05121867d62de
64e0821c53c7d161099be2188b6cac24
95511870061fb3a2899aa6b2dc9838aa
422d81e7e1c2aa46aa51405c13fed15b
95511870061fb3a2899aa6b2dc9838aa
422d81e7e1c2aa46aa51405c13fed15b
Bon bah on va essayer de les retrer pour voir celle qui passe.
La plus probable est celle ci mais elle passe pas 64e0821c53c7d161099be2188b6cac24
.
On retente avec la 2e 95511870061fb3a2899aa6b2dc9838aa
et elle flag.
ECSC{95511870061fb3a2899aa6b2dc9838aa}