Comparison of the ransomware used against Enel and Honda

Published by GLIMPS on

Comparison of the ransomware used against Enel and Honda

François did an internship with us between April and August. He worked on the development of a tool that extracts symbols from a program written in Go. Here is an article that presents an application of his work for ransomware analysis and comparison.

EKANS analysis

EKANS (SNAKE upside down) is a new ransomware programmed in Go language which appeared in December 2019, it affected Honda and Enel among many other companies. The particularity of the EKANS, the one that has generated interest, does not lay in its method of propagation but rather in its willingness to “kill” industrial control systems. This peculiarity was notably studied and explained by Dragos.

 GLIMPS technology makes it possible to detect similarities between binaries sharing source code, even if compiled differently or for different architectures. In addition, during my internship in the company, I developed a tool to extract symbols from the Go executable runtime.

Two malware with identified similarities, and written in Go… It is therefore a good case study to check the relevance of the results and to test the symbol retrieval tool in a real situation!

This analysis allowed us to verify the indisputable common origin of the viruses used in the Honda and Enel attacks.

Application of GLIMPS code conceptualization technology

GLIMPS has developed a code conceptualization technology that allows to compare compiled software very efficiently, even if they have undergone transformations during the compilation stages, or if they target different architectures.2 applications de cette technologie ont été développées : 

  • GLIMPS-Malware compares a file to a database of millions of classified malware copies, in order to identify whether a file is benevolent or malicious, and if it is malicious, to characterize the probable origin of the attack.
  • GLIMPS-Audit will help the detailed analysis of a software, legitimate or malware, by identifying and documenting the known code (libraries on shelves…) constituting it. It also allows  software-to-software comparison, which we have used in this analysis.

By passing files from the Honda and Enel attacks into GLIMPS-Malware, they are immediately detected as malicious files and characterized as variants of the SNAKE ransomware. We have recovered the right files !

Thanks to GLIMPS-Audit, we then compared the 2 ransomware between them. We can confirm that, despite the methods of offuscation, the ransomware that targeted Enel and Honda are almost identical and come from the same origin: out of 4369 functions, 4230 are identified for sure, and 88 additional matches have a good probability to be identical. Therefore, out of the 4369 functions of the 2 ransomware, there are less than 50 functions for which the correlation is less immediate.

The retrieval of runtime symbols

The Go language is a high-level language with a garbage collector and a runtime capturing execution errors (division by 0, overflow buffers, etc.). The Go runtime when it detects an error causes a “panic” and displays the error details. For example :

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x460c1f]

goroutine 1 [running]:
main.main()
/tmp/sandbox311401280/prog.go:18 +0x1f
exit status 2

This detail contains the path of the source files (/tmp/sandbox311401280/prog.go), the name of the functions (main.main), the line numbers (18), the address of the functions (pc=0x460c1f and +0x1f so the address of the function is 0x460c00), etc… These are the same symbols that we recover.

Once the EKANS symbols have been applied to the disassembled code, important similarities become apparent. Indeed, almost all the functions in the main package (package containing the main function in GB) have had their names and the path of the files containing them offended, transformed into a random string. Note, that the name of the main function of the main package, main.main (main_main in IDA) could not be changed since it is necessary for compilation (it is the entry point of the program) and their modifications take place before the compilation. In addition, the line number of several functions corresponds, for example the main function is on line 339 in both ransomwares. But again, the obfuscation of the file path is partial and shows important similarities, as we can see in the example below :

“Enel” : [{
“Name”:”main.cempcamllplldijidcni”,
“File”:”C:/Users/Admin3/go/src/nmhgfmidblhkfacdajkc/pbopnijdlnfbnimbiham.go”,
“Line”:254
}]

“Honda” : [{
“Name”:”main.jfplojgoheneeggeidee”,
“File”:”C:/Users/Admin3/go/src/cgillndadlcobliljlfo/nknejkdfponfiknchiad.go”,
“Line”:254
}]

Functions are located on the same line and are in the same package (main), are located in files whose paths start in the same way and are offended in the same way. We can therefore consider without taking too much risk that they are the same functions. This was already confirmed by the results of GLIMPS-Audit and that we can also see by a more precise analysis with a reverse engineering software (IDA). These observations allow in many cases to confirm the relevance of the results obtained with GLIMPS-Audit.

Another important similarity visible from the symbols concerns the names of the imported functions. Indeed, for both ransomwares, the same functions of the same packages are imported.

The search for functions to kill processes

Once the previously recovered symbols were loaded into a reverse engineering software we decided to search for the mechanism used by ransomwares to kill processes.

To do so, we searched for the different Go functions allowing to close a process. Unfortunately, its standard library does not provide a function performing such a task independently of the OS. So we looked at the Windows libraries (since ransomwares are PEs allowing to kill a process whose name and strings of executable names are known, usually targeted by ransomwares). These executables are, among others, antivirus (for example, kavshell.exe) and browsers (for example, firefox.exe).  Only the TerminateProcess function was found. By tracing back the origin of its arguments we understood that the other functions, especially those allowing to list processes, were dynamically imported. Once the function allowing to perform dynamic imports was found NewLazyDll we realized that if we could not find function or process names it was because all the strings used by both ransomwares are encrypted. In fact, each of the string assignments was replaced by a call to a literal function that uses two other strings to obtain and return the original string. For example,<:P>

print(“Hello world\n”);
//devient
print(func () string {

var string1 = “\x21\x0d\xc3\xb5\x79\x7c\x2d\x9e\x38\x92\xb2\x99”
var string2 = “\x69\x6a\xab\xd7\xee\xa6\x4e\xc3\x3a\xc8\xa2\xa5”

var slice1 = []byte(string1)
var slice2 = []byte(string2)

var size = len(slice1)

var sliceRes = make([]byte, size)
for i := 0; i < size; i++ {
sliceRes[i] = byte((int(slice1[i]) + i*2) ^ int(slice2[i]))
}
return string(sliceRes)/*la valeur de retour est “Hello world\n”*/

}())

This method results in the creation of more than 1,000 almost identical literal functions and doubles the space taken up by strings in the data section. The encryption being relatively simple the following function in Go language allows to decrypt the original string from the two new corresponding strings :

func decode(a, b string) string{
var slice1 = []byte(a)
var slice2 = []byte(b)

var size = len(slice1)

var sliceRes = make([]byte, size)
for i := 0; i < size; i++ {
sliceRes[i] = byte((int(slice1[i]) + i*2) ^ int(slice2[i]))
}
return string(sliceRes)
}

Once the sequences were decoded we found, for each ransomware, the names of the dynamically imported functions and the names of the processes killed by the ransomware. We also observe that the vast majority of the decrypted strings obtained are present in each of the two ransomwares.

The encryption protocol

We then tried to understand the encryption mechanism of the program. To do this we started with the Go encryption libraries and looked at which ones are used. The first found was the AES-256. After studying the input and output paths of the AES encryption function and the surrounding documented function calls we were able to determine the encryption procedure, again the same for both ransomwares.


First a public key pair, private key that will be used to perform an RSA encryption (and later a decryption) is obtained. The public key is hard written into the program sources while the private key is kept by the ransomware designers.only the public key is present in the executable. Note that the ransomwares that targeted Honda and Enel have different public keys.

The second step is the listing of the files. The ransomwares parallel their calculation in order to encrypt several files simultaneously. Then, for each of the files found, a 256-bit key is randomly generated. This key is used to perform an AES-256 encryption on the file. It is then encrypted with an RSA using the public key mentioned above. Finally, the result of the RSA (the encrypted AES key) is formatted before being written to the end of the encrypted file.. Remember, since the RSA is an asymmetric encryption, it is with the private key held by the ransomware designer only that we will be able to decrypt the AES key present at the end of the file and thus decrypt the file. You will find below a diagram detailing the procedure for encrypting and decrypting the ransomware.

Conclusion

To conclude, we can say that the ransomwares are indeed two versions of the same program. Glimps Audit has successfully detected their important similarities. In addition, the Go symbol recovery tool proved to be efficient and greatly facilitated the reverse engineering work.

Categories: Uses-case