# HelloKitty Linux version malware analysis **soolidsnake.github.io/2021/07/17/hellokitty_linux.html** HOME July 17, 2021 Jul 17, 2021 ## Please read the disclaimer Introduction This report contains technical details of the new linux version of HelloKitty that targets VMware ESXi servers. The encryption used by this variant is AES_CBC and Elliptic-curve Diffie–Hellman (ECDH) to protect the keys. ## Encryption Overview The malware generates an ECDH keypair, then using the hardcoded public key of the threat actor, it generates an ECDH secret key, then an AES KEY/IV are randomly generated at run time, this key will be used to encrypt a file. Note: the AES KEY/IV are different for each file. The AES KEY/IV is encrypted using a randomly generated IV and the previous ECDH secret key with AES algorithm. Finally a structure is populated with the ECDH public key of the malware, the encrypted AES **KEY/IV used for file encryption and other stuff.** The structure is appended with the ransom note and the encrypted file `.crypt` The Threat actor can recover the ECDH secret to decrypt the encrypted AES KEY/IV used for encrypting the file with his Private ECDH key and the malware Public ECDH key. ### Ransom Note ----- Figure: Ransom note ## Technical Analysis ### CommandLine arguments Figure: Parsing commandLine arguments **option** **Functionality** ----- **option** **Functionality** **-k** Kill VM processes **-d** Run as daemon **-e** Encrypt VM files **-v** Enable verbose ### Dynamically loading libcrypto API The malware loads some OpenSSL API from libcrypto.so using dlopen/dlsym. Figure: Dynamically loading libcrypto API Looking at the array, we can see that each entry is a structure of 3 pointers: ``` { unsigned char* new_function_name; unsigned char* old_function_name; void* pointer_to_api; } ``` ----- First the ransomware tries to get the address of the function name stored in **new_function_name, if not found (which means the library is old) it uses** **old_function_name, if the API was found, it’s pointer will be stored in pointer_to_api** Figure: Array of libcrypto API names and addresses We can rename the pointer_to_api with this pythonIDA script, it gets new_function_name string and it then set the name for pointer_to_api ``` start = get_name_ea(0, "array_func_name") for i in xrange(0x39): func_name = get_strlit_contents(Qword(start)) set_name(start+0x10, func_name) start += 0x18 ### Ignores signals ``` ----- The malware will ignore the following signals, so that it won t be interrupted during encryption, this will prevent half encrypting files which leads to file corruption. SIGCHLD SIGTSTP SIGTTOU SIGTTIN SIGHUP SIGTERM Figure: Malware ignores some signals ### List VM processes It executes the command `esxcli vm process list to list every VirtualMachine processes` currently running on the infected machine. It then parses through the output to extract **Process ID and Config File which is basically the path to the VMX file of the VM This data** is saved in a array of stucture of type ``` { uint64_t Process_ID; unsigned char *Vmx_Path; } ### kill VM porcesses ``` Using the previous array, the malware first tries to kill the processes with a soft kill `esxcli` ``` vm process kill -t=soft -w= if it fails it uses a hard kill option esxcli vm process kill -t=hard -w= . ### Recursive file search ``` It uses the paths given as command line arguments and explore recursively the directories using opendir **readdir.** For each file read, it first checks if the file is not . or .. and does not contain the strings .crypt or .README_TO_RESTORE ----- ### Switch (file type) **case directory:** It checks if it is not one of the following directories: /bin /boot /dev /etc /lib /lib32 /lib64 /lost+found /proc ----- /run /sbin /usr/bin /usr/include /usr/lib /usr/lib32 /usr/lib64 /usr/sbin /sys /usr/libexec /usr/share /var/lib In case the check pass, it calls recursively the same function with the new directory path as argument. Figure: Recursive directory search **case file:** In case it was a file and the -e option was specified in command line arguments, it will check if the file does not contain the following strings .crypt, .tmp_, .README_TO_RESTORE, then checks if it contains one of the following strings **.vmdk** **.vmx** **.vmsd** **.vmsn** ----- if -e was not specified, it will check if the filename does not contain one of the following strings .crypt .READ_ME_TO_RESTORE .tmp_ .a .so .la Finally if the size of the file is bigger than 256 bytes, it saves the path to the file for later usage (encrypting it… of course) ### switch to daemon process If the -d option was specified in command line arguments the malware calls daemon to detach itself from the controlling terminal and run in the background as system daemons. ----- Figure: Detach and run as daemon ### start thread it starts a thread at address 0x402AA2 then creates 2 strings, `filename + .crypt and` ``` filename + .tmp_ ``` A function is called that tries to set a lock on the file using `fcntl, if it fails it will get the PID` of the process that is currently locking the file Figure: Malware try to set a lock on the file If the PID is greater than 10 (not a system process), it will kill it with the command `kill -9` ``` ``` ----- The malware then rename the file to `filename + .tmp_ then it will call a function` (0x405D64) to encrypt the file. In case of failure it will roll back to the original filename In case of successful encryption it will rename the `.tmp_ to` `.crypt` ### Encryption **Generation of keys** It derives an AES_256_CBC **KEY and IV with libcrypto function EVP_BytesToKey with a** randomly generated salt and data using RAND_bytes API that will be used for file content encryption. Figure: Generate AES KEY/IV ----- Figure: Official documentation of OpenSSL API https://www.openssl.org/docs/man1.0.2/man3/EVP_BytesToKey.html Afterwards it generates the malware ECDH private/public keys. Figure: Generate client ECDH keypair Next it will call a function at address 0x4054F1 (I named it func_compute_secret) with the newly generate EC_KEY and the public key of the author ----- Figure: Author public key Then It calls libcrypto api ECDH_compute_key to generate an ECDH shared secret. Figure: Generate ECDH secret After that it populate a custom structure `(I named it custom_structure00) of the` following type with the AES KEY, IV and the size of the file. ``` { unsigned char* save_AES_IV[0x10]; unsigned char* save_AES_KEY[0x20]; unsigned __int64 size_of_file; unsigned int defined_constant; unsigned int alignemnt; } custom_structure00; ``` ----- Figure: Populate the above structure with AES key data Figure: Example of the structure populated with data Then it encrypts the structure `custom_structure00 using the ECDH secret and a` randomly generated IV of 16 bytes with AES algorithm. Figure: Encrypt the above structure with the ECDH secret After that, it populates yet another important structure `custom_structure01 of following` type: ----- ``` { // The IV used to encrypt the custom_structure00 structure. | offset 0 0x10 unsigned char secret_IV[0x10]; // The size of custom_structure00 | offset 0x10 - 0x14 unsigned int size_of_custom_structure00; // Encrypted custom_structure00 | offset 0x14 - 0x34 custom_structure00 encrypted_custom_structure00; // Size of the client public key | offset 0x58 - x5c unsigned int size_of_public_key ; // Client public key | offset 0x5c - 0xa0 unsigned char public_key[0x44]; // Size of the sig | offset 0xa0 - 0xa4 unsigned int size of sig; // Sig | offset 0xa4 - 0xf0 unsigned char sig[0x47]; } custom_structure01; ``` Finally it writes to `filename + .README_TO_RESTORE the ransomware note, then it append` the previous structure at the end of the file. It also append the SHA256 of the ` (see next) Example: ``` ----- ``` .README_TO_RESTORE file tail, showcasing the above structure (custom_structure01) and the SHA256 hash of the file ``` It then appended the same structure `(custom_structure01) to the target file.` Figure: Original content of the file + `(custom_structure01)` Finally it reads the data of the target file and uses the file encryption AES key to encrypt it. ----- Figure: Malware encrypt the content of the target file Figure: File encrypted Finally it append again the structure + the sha256 of the file. ----- Figure: Encrypted file + custom_structure01 + sha256 ## Conclusion This linux variant can target Virtual machines files, which can be crucial to companies without backup and replication. The encryption scheme used utilize ECDH (Elliptic-curve Diffie–Hellman) algorithm, which means without the private key owned by the threat actor, it will be near impossible to decrypt the encrypted files. ## YARA Rule ----- ``` rule hellokitty_linux { meta: description = "YARA rule HelloKitty linux variant ransomware" reference = "https://soolidsnake.github.io/2021/07/17/hellokitty_linux.html" author = "@soolidsnakee" date = "2021-07-17" strings: $str1 = ".crypt" $str2 = ".README_TO_RESTORE" $str5 = "switch to daemon" $str6 = "esxcli vm process kill -t=hard -w=%d" $str7 = "work.log" $str8 = "m:vdekc:" condition: all of ($str*) } ``` -----