Yesterday, the world got the news that the Brazilian Supreme Justice Court was the target of a ransomware attack, and had all of their data (and backup) encrypted (check here). What really motivated this attack is still unclear, and several questions arise: Was it performed by a cyber criminal? A group? Was it revenge? Today, Kaspersky released a report confirming that the source of attack was a ransomware (check here).
We had access to the sample mentioned by Kaspersky’s report (don’t ask us how), so here is our brief analysis of the ELF artifact.
We started our analysis by submiting the sample to our sandbox solution (check report here). Nothing very interesting was found: No virustotal detection, none of our ML classifiers flagged the file, the sandbox trace finishes abruptly…. except for some suspicious AES strings in the import section.
Digging deeper, we discovered that the AES is related to the embedding of the entire mbedtls framework in this binary, as can be seen in the figure. We did not expect the malware embedding the entire framework, since it would make more sense to include only an implementation of the AES algorithm, but who is able to completely understand the mind of attackers?
Looking at the binary “main”, we notice a simple structure. A setup step and a short loop. The loop creates a thread that searches for files in a directory (EnumFIles). That was easy to understand since the binary is not stripped.
Looking at the setup step, we notice the GeneratePreData function. Delving into it, we notice subsequent calls to time, srand, and rand — srand(time(seed)), if you are used to this type of construction. It seems that someone is generating a secret here!
More specifically, the sample works in a producer-consumer manner. The EnumFile function adds the identified files to a queue and creates a thread to consume it, as the following figure shows.
The worker thread invokes the CryptOneFile function (shown below) for each file it pops from the queue.
This function invokes the mbedtls framework to encrypt the data with the AES key generated in the setup step, as shown in the figure below.
But why did this simple “main” failed to execute in the sandbox? We have discovered that this failure happened because the EnumFile has nothing to do by itself. So, we feed it with some seed, i.e., we called the binary with some arguments:
Bazinga! Populating the directory with some file to be affected and running the sample with the current directory as an argument does the trick. File encrypted, extension modified… and another txt files (NEWS) dropped in the folder.
The News file is in fact the ransom’s message. In fact, that ransom’s message was visible since the beginning, as it can be seen in the output of the strings command (below).
After executing the ransomware in our “bait directory” with the file honeyfile.txt, the resulting file (honeyfile.txt.31gs1-4aa9b9dd) is an encrypted version of the original one, making it irrecoverable at the moment.
Will it be possible to recover the affected files? It is hard to say so right now. The figures above show that each time you run the sample, it encrypts the data with a distinct key.
One possible attempt to recover the files would be to attack the mbedtls implementation. We are not cryptographers, so we don’t know if this framework is vulnerable to any attack. Another possible attempt would be to try to recover the key using some extra information. For instance, since the key is generated using the time function as a seed, if we know the approximate time that the files were encrypted, we can bruteforce these values as the return of the time function to check the generated key. In fact, we tried that, as shown in the figure below (The value in rax is the key for that execution). Unfortunately, this approach does not succeed since the mbedtls adds extra randomness to the key via its entropy functions, making key generation not reproducible.
So, after all this randomness, how the attacker knows which key encrypted the files? The answer is that the attacker doesn’t know! This is why it asks for a file to be sent to it in the ransom note, so it can discover the key used for that file.
It is possible because the sample encrypts the used AES key with an attacker’s RSA public key (shown in the figure below) and adds it to the encrypted file.
Not much to do here unless we discover something like a weakness in the attacker’s key generation procedure that allows us discover its private key (really unlikely).