Category: Forensic
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é}.
Files: mem.dmp
An analysis of the ransomware gives us a pattern to find that contains the encryption key. The key is found thanks to strings
and grep
.
Now that we know the identity of the ransomware we are able to analyze it..
First we'll extract it from the memory dump with 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
And now we're going to do some reverse with Ghidra because I like its integrated decompiler.
As I don't know much about reverse, I decided to focus on strings.
We notice that there is a link to github. Let's go see what it is.
The github repo seems to be the source code of the ransomware.
By comparing the repo code with the decompiled code there are many similarities. We deduce that the repo code corresponds to the malware analysis.
In the file cryptofs/file.go there is an interesting function:
func (file *File) Encrypt(enckey string, dst io.Writer) error {
[...]
}
The encryption key is passed as a parameter to the function Encrypt
.
By looking at where this key is generated we arrive at a file called ransomware.go
which contains this function:
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)
[...]
}
We can see that the key is generated and then sent to a remote server.
Volatility confirms it:
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
[...]
If the connection has been established and sent to a server it is necessarily somewhere in the memory.
In the code we can see which one is sent according to a very precise pattern: {"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{})
}
Good, so strings is our friend in CTF!
We will search for all the lines that contain the word enckey
and we will take 10 lines above and below.
>_ 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
[...]
Among all the exits there is one that is interesting.
{"id": "cd18c00bb476764220d05121867d62de", "enckey": "
cd18c00bb476764220d05121867d62de64e0821c53c7d161099be2188b6cac24cd18c00bb476764220d05121867d62de64e0821c53c7d161099be2188b6cac2495511870061fb3a2899aa6b2dc9838aa422d81e7e1c2aa46aa51405c13fed15b95511870061fb3a2899aa6b2dc9838aa422d81e7e1c2aa46aa51405c13fed15b
We observe the pattern {"id": "%s", "enckey": "%s"}
with the parameter enckey
which seems a little long: cd18c00bb476764220d05121867d62de64e0821c53c7d161099be2188b6cac24cd18c00bb476764220d05121867d62de64e0821c53c7d161099be2188b6cac2495511870061fb3a2899aa6b2dc9838aa422d81e7e1c2aa46aa51405c13fed15b95511870061fb3a2899aa6b2dc9838aa422d81e7e1c2aa46aa51405c13fed15b
The enckey
parameter starts with the same key as the id.
The string is divided into 8 equal parts and 4 potential encryption keys are obtained. In reality 3 because we can exclude the one that corresponds to the id.
cd18c00bb476764220d05121867d62de
64e0821c53c7d161099be2188b6cac24
cd18c00bb476764220d05121867d62de
64e0821c53c7d161099be2188b6cac24
95511870061fb3a2899aa6b2dc9838aa
422d81e7e1c2aa46aa51405c13fed15b
95511870061fb3a2899aa6b2dc9838aa
422d81e7e1c2aa46aa51405c13fed15b
Well, we'll try to get them back in to see the one that validates the challenge.
The most likely is this one but it doesn't validates the challenge 64e0821c53c7d161099be2188b6cac24
.
We'll try again with the 2nd 95511870061fb3a2899aa6b2dc9838aa
and she flag.
ECSC{95511870061fb3a2899aa6b2dc9838aa}