Analysis of the HelloKitty ransomware source code

Assembly and handwriting.

For the purpose of analysis, the source code was taken, leaked to public 10.10.2023.
The program is written in C++ (uses the C++17 standard and supports Windows XP) and was going to MSVS 2015.
Project file tags indicate that the source code was created on a Russian-language OS.

The include paths contain assemblies:

c:\Projects\LockerInnocentFork\lk\NTRUEncrypt\include\
c:\Projects\LockerInnocentFork\lk\mbedtls\include

suggestive of a fork of a certain LockerInnocent project. I couldn't find any information on it (but I didn’t really look for it either).

Algorithm.

Mathematically, encryption is implemented using the mbedtls library of cryptographic primitives and the NTRUEncrypt algorithm, which is currently considered resistant to hacking by quantum computers. NTRUcreated in 1996 year as an alternative to RSA and elliptic curve algorithms (ECC), and is still considered poorly understood.

The key is generated with the NTRU_EES743EP1 flag

which, according to the attached documentation, is an analogue of RSA with a key length 1920 byte.

Public key length 1028 one byte is inserted for each individual HelloKitty build.

initial stage.

Execution of the ransomware begins by prohibiting the system from dropping the program in case of critical errors and prohibiting closing the console using Ctrl + C.
Next comes the generation of a ransom note with the SHA256 public key.
The start time of work is recorded and when encryption is complete, the elapsed time is displayed.
The only supported command line switch is being checked: -path “path”. If it is specified, Only this folder is encrypted.
Through WMI, shadow copies are deleted and the contents of the recycle bin are cleared and threads are created.

Speed, parallelization and search​.

To process files, a number of threads are created in advance, equal to the number of processor cores * 2, which is considered quite effective. Files are processed asynchronously with notification of completion via the I/O completion port, after which the next block or file is encrypted in the same stream without creating a new one.

A separate thread is created to measure and display speed, which resets the counter every 1 second and displays reading and writing speed measurements in the title of the console window.

At this time, the main thread creates additional threads to search for and begin processing files, located on local, removable and network drives.

For each letter, its own thread is created. They will all launch in parallel, which is very suboptimal and will overload the disk with requests in case, if the physical disk is not an SSD and has many logical partitions.

The search itself is implemented through FindFirstFileW and recursion, that in a comparative analysis with other encryptors according to the researcherChuong Dong is highly suboptimal and can lead to stack overflow. There are linear heap-based recursive search algorithms without recursion, deprived of this disadvantage.

The following files and folders are skipped:

Some of them are responsible for the system boot stage and if they change, the OS will not be able to start.

Files size <= 1 MBs are not processed. You don’t have to worry about small documents

If the file has the attribute “Only reading”, this attribute is removed.

File recording and its structure.

Victim files are opened via CreateFileW with shared read rights and asynchronous operation mode. This is done immediately by the same thread, what is looking for files. And as we remember above, number of these threads = number of disks. Files could be opened in an infinite number. To resolve this issue, when listing files, the maximum number of files already open is checked.. The thread goes into an endless loop of repeatedly checking this value, if it is higher 200.

A file descriptor is associated with an I/O port.

The same thread reads the first block of data, filling the OVERLAPPED structure with primary data, necessary for encryption (cm. Further).

And other threads are responsible for writing and reading subsequent blocks of data. (them, what = number of cores *2). They pull completed read/write operations from the I/O port queue and process the next block of data of an arbitrary file.

If reading the first block fails, I/O operation is canceled.

While encrypting file blocks, I/O port in the OVERLAPPED pointer holds the over_struct service structure, having all the information about the progress of encryption of a specific file:

such as the path to the file, its size, current data block, sit, cryptography class context.

The file is processed in blocks of maximum 160 KB (DEFAULT_BLOCK_SIZE).

The operation field holds the current state of the object, by which it is determined, what to do next with the current block or file pointer.

*retry fields are not used, but by design, Seems like, were responsible for retrying read/write if unsuccessful.

This structure includes another structure - enc_header, necessary to process the file:

As a signature (magic number) the value used is 0xBAADC0DE

encType contains optional flags, one of:

ENCTYPE_FULL_FILE = 2 (обработка файла целиком)
ENCTYPE_RANDOM_BLOCKS = 4 (обработка рандомных участков)
ENCTYPE_LIMIT_FILE_SIZE = 8 (ограничение длины файла для обработки)
ENCTYPE_USE_CRC32 = 16 (создание контрольной суммы самого заголовка для верификаци, что он не повреждён)
qwMaxEnctyptionSize – ограничение максимальной длины обработки файла (для флага ENCTYPE_USE_CRC32).
endBlockCrc32 – CRC32 заголовка (для флага ENCTYPE_USE_CRC32).
aes_key и aes_iv – ключ и вектор инициализации.

The bytes of the enc_header structure are then encrypted and written to the end of the file (ntru_encrypted field) as a structure enc_end_of_file_ntru:

cipherLen is also written there (size of ntru_encrypted in bytes) and a flag signature indicating the completion of encryption with the value ENCRYPTED_FILE_FLAG (0xABCCDCDA + 1).

At the end the file is renamed, adding the .kitty extension

Build configuration.

The configuration is built into the source code itself.

and contains fields:

  • configSignature (not used, contains the number 0xAAEECCD0)
  • real block size
  • maximum file length for processing, if bFullFileEncrypt mode is enabled
  • flag for enabling recording and checking the CRC32 checksum of the tail header
  • flag “Encrypt the entire file”
  • flag “Encrypt random blocks” (either this flag must be selected, or whole encryption).

Standard settings: encryption of random blocks of size 160 KB, and CRC32 check.

Network functions.

Before starting a search on network drives, the main thread demotes itself in an elegant way (usually use a token, stolen from another process) – in this case, in the code, the current process receives detailed information about its own token, namely the limited token associated with it, because. in essence, the increase in rights is carried out by joining the current (limited) elevated token token.

This is done, because network drives are usually connected with limited rights, and are not visible through the elevated token.

The search for network shares is implemented through the WNetOpenEnumW function. To search for files, a separate thread is created for each of the shares., performing the same, code for searching local files. Subsequently, they are encrypted by a set of threads common to local files.. This may block the entire encryption procedure, if for example, there will be one very slow network resource.

Maximum number of search threads (network and local) strictly limited to a limit of 64. Otherwise, all subsequent network resources are skipped.

Ransom note.

A ransomware note named read_me_lkdtt.txt is created in each directory
To contact the attackers, it is suggested to go to the website, located on a service on the Tor network.

Protecting and removing locks from a file

If you can't open the file, the program checks, is it busy with other processes?, and removes blockages, using Restart Manager. The code is deprived of additional. checks and may well drop the system into BSOD.

Self-removal is implemented with a delay via ping to loopback and the cmd command, however, in the source code the call is commented out.

The code is not protected in any way from debugging or running inside sandboxes. Probably, an additional cryptor is used, processing a ready-made assembly or other solution, masking the process and its activity.

The encryptor's work ends by waiting for all search threads and reaching the number of open file descriptors. 0.

Dead code.

Probably, some versions contained protection against re-running the encryption part. There are lines in the code that are not used in any way

The functionality is commented out in the source code, responsible for killing processes according to the list. What’s noteworthy is that the kit includes a list of as many 1686 process names.

Breaker.

Creates a mutex “EnigmaThread“, to prevent restart

Decryption is performed in reverse order by extracting the enc_end_of_file_ntru structure from the tail of the file and decrypting it with the private key, built into a specific build.
File processing is performed in multi-threaded mode through a thread pool and synchronous I/O with file opening via \\?\ prefix, which means support for long paths.
If the CRC32 calculation option was selected in the build config, then the decrypted header is checked against the checksum, true after trying to decrypt the file. In case of mismatch, the file will not be renamed.

The decryptor also supports the -path command line switch “” to select a specific decryption path.

Draw your own conclusions

The article was written to develop the ability to read other people's code., better understanding of the operating techniques of modern malware and the ability to search for artifacts, which in HelloKitty let's say, not so much; and also in view of the desire to publish at least some article during the long break, making it in the style of the blog articles of reversing expert Chuong, who can write also in detail and beautifully, without having the source code in hand

The article also contains small hints of shortcomings, which one way or another can be used to prevent or minimize the effectiveness of encryption, including the creation of special. tools. Sequence of deployment of specific malware and understanding, what functions a process performs at a specific point in time can help the authors of antivirus solutions to properly organize protection and select behavioral analysis rules for blocking an already running ransomware.

The article was compiled Dragok and is the intellectual property of SafeZone.cc
Republishing on other resources without the written permission of the administrator is prohibited.