A Deep Dive into Cactus Ransomware
Executive summary
Cactus ransomware was discovered in March 2023. The malware creates a mutex called “b4kr-xr7h-qcps-omu3cAcTuS” to ensure that only one copy is running at a time. Persistence is achieved by creating a scheduled task named “Updates Check Task”. The ransomware requires an AES key to decrypt the encrypted public RSA key stored in the binary.
The files are encrypted using the AES algorithm (OpenSSL library), with the key being encrypted using the public RSA key. The extension of the encrypted files is changed to “cts0” or “cts1”.
Analysis and findings
SHA256: 78C16DE9FC07F1D0375A093903F86583A4E32037A7DA8AA2F90ECB15C4862C17
The ransomware is packed with UPX. It retrieves the window handle used by the console:
The process hides the window by calling the ShowWindow API (0x0 = SW_HIDE):
It obtains a pseudo handle for the current process using GetCurrentProcess:
The GetProcessAffinityMask function is utilized to extract the process affinity mask and the system affinity mask for the system:
The malware can run with at least one of the following parameters: “-s”, “-r”, “-i”, “-l”, “-e”, “-c”, “-t”, “-d”, and “-f”. We’ll describe the purpose of every parameter in the upcoming paragraphs.
The binary creates a mutex called “b4kr-xr7h-qcps-omu3cAcTuS” to ensure that only one copy of the executable is running at a time (see Figure 6).
Running with the -s parameter
The public RSA key is stored in an encrypted form. The AES key used to decrypt the RSA key is parsed from the “C:\ProgramData\ntuser.dat” file, which should have been created earlier. The initialization vector is hard-coded “OLi3bTN6ekZCY7jd”:
The public key is decrypted using AES256 Galois Counter Mode (GCM):
OpenSSL’s EVP_DecryptInit_ex function is used to start decrypting the information, as highlighted below.
Finally, the RSA key is decrypted by calling the EVP_DecryptUpdate method (Figure 11).
The ransomware checks if the decryption was successful by verifying the first 3 characters:
The malicious process loads the public RSA key using the PEM_read_bio_PUBKEY function, as shown in the figure below.
GetModuleFileNameW is utilized to extract the path of the executable file (see Figure 14).
The binary is looking for the “D:\ProgramData” directory via a function call to CreateDirectoryW:
It retrieves file system attributes for the ProgramData folder:
The above folder is hidden using the SetFileAttributesW API (0x12 = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN):
The executable is copied into the ProgramData folder as “C:\ProgramData\b4kr-xr7h-qcps-omu3.exe”:
The malicious binary deletes the “ntuser.dat” file found in the ProgramData directory if it exists:
It creates the above file that will be populated:
Cactus ransomware writes 2 junk strings, the executable path converted to hex, and the AES key passed in the “-i” parameter to the file:
The “ntuser.dat” file is hidden via a function call to SetFileAttributesW (Figure 22).
The ransomware establishes persistence by creating the “Updates Check Task” scheduled task, which runs the malware with the “-r” parameter:
Running with the -r parameter
The wfopen method is utilized to open the file created earlier, as highlighted in the figure below.
The process extracts the AES key from the file. It’s important to mention that we don’t have the threat actor’s key and performed some modifications that allow the analysis to continue.
The “ntuser.dat” file is deleted afterwards:
The binary spawns the initial executable with the “-i” parameter, including the AES key that was set to a specific string:
Running with the -i parameter
The executable creates a new thread that runs the searchFilesThreadControl function:
It retrieves the valid drives on the system using the GetLogicalDriveStringsW API (see Figure 28).
The malware obtains the type of the drive by calling the GetDriveTypeW function:
The files are enumerated using the FindFirstFileW and FindNextFileW APIs:
The following directories will not be encrypted:
- “$recycle.bin” “system volume information” “windows” “tmp” “temp” “thumb” “winnt” “windows.~bt” “windows.old” “perflog” “perflogs” “boot” “programdata” “packages” “efi” “windowsapps” “microsoft” “windows defender” “microsoft shared” “internet explorer” “tor browser” “ctslck”
GetFileAttributesW is used to extract file system attributes for a target file, as shown below:
Cactus ransomware doesn’t encrypt the “CaCtUs.ReAdMe.txt” ransom note and the following files:
- “desktop.ini” “update.log” “ntuser.dat”
The following file extensions will be avoided:
- “exe” “dll” “lnk” “sys” “msi” “bat” “cts0” “cts1”
The ransomware opens the target file using CreateFileW (0xC0000000 = GENERIC_READ | GENERIC_WRITE, 0x3 = OPEN_EXISTING):
The binary uses Restart Manager APIs to determine if the target files are blocked by other processes (Figure 36).
The wfopen function is utilized to open the file:
The malicious process moves the file pointer to the end of file using lseek64 (0x2 = SEEK_END):
It creates a new thread that handles the file’s encryption (see Figure 39).
The file’s size is compared with 8074034 bytes (approximately 7.7MB). If the size is greater than 7.7MB, then cryptPartFile is called; otherwise, the malware calls the cryptFullFile function. Basically, a large file is partially encrypted (50%, but the percentage can be modified) by Cactus ransomware.
The ransomware allocates and obtains a cipher context using OpenSSL’s EVP_CIPHER_CTX_new:
The algorithm used to encrypt the files is AES256 in CBC mode, as highlighted in the figure below.
The process sets up the cipher context for encryption using the EVP_EncryptInit_ex method (Figure 42).
EVP_CIPHER_get0_provider is utilized to obtain an OSSL_PROVIDER pointer to the provider:
The ransomware generates a random 32-byte key using EVP_CIPHER_CTX_rand_key:
The 16-byte IV is generated by calling the RAND_priv_bytes_ex function:
Using the key and IV previously generated, the binary calls the EVP_EncryptInit_ex method again:
The executable allocates the public RSA key algorithm context via a call to EVP_PKEY_CTX_new_from_pkey, as highlighted in the figure below.
The AES256 key is encrypted using the public key:
The encrypted file’s extension is changed to “cts0” or “cts1”:
The ransomware appends the following information to the encrypted file: encrypted AES256 key, non-encrypted IV, 0x64 (encryption percentage), and “~~!!~~!”.
It reads the content that will be encrypted using the _read function:
EVP_EncryptUpdate is used to encrypt data:
Finally, the malware calls the EVP_SealFinal method:
The extension is changed again to the other remaining value:
The structure of an encrypted file can be seen in Figure 58.
Running with the -l parameter
In this case, the ransomware sets the needLogger variable to 1 and creates a log file called “update.log” in the ProgramData directory.
Running with the -e parameter
This is the extra logging feature of the ransomware, which adds even more steps to the same log file.
Running with the -c parameter
This parameter is used to change the encryption percentage (sizeCoverGlobal variable) when partially encrypting the files.
Running with the -t parameter
The number of threads available for encryption can be changed in the maxThreads variable.
Running with the -d parameter
The ransomware only encrypts a specific directory.
Running with the -f parameter
In this case, a single file is encrypted by the malware.
Indicators of Compromise
SHA256
78C16DE9FC07F1D0375A093903F86583A4E32037A7DA8AA2F90ECB15C4862C17
Cactus Ransom Note
CaCtUs.ReAdMe.txt
Mutex
b4kr-xr7h-qcps-omu3cAcTuS
Files created
C:\ProgramData\ntuser.dat
C:\ProgramData\b4kr-xr7h-qcps-omu3.exe
C:\ProgramData\update.log
Scheduled task
Updates Check Task