Introduction

It is no secret that ransomware is still on the rise and is proving to be an extremely lucrative digital crime. But what happens when the very code that is supposed to keep the ransom secure is flawed? In this blog post, we’ll take a deep dive into the inner workings of ChileLocker, a ransomware variant of the ARCrypter malware family, revealing a critical bug in its key generation process.

Background

A Managed Service Provider (MSP) partnered with Blackpoint Cyber contacted the Adversary Pursuit Group (APG) requesting we look at a ransomware sample. The sample was obtained from the MSP’s customer prior to their onboarding and was responsible for encrypting files on their VMWare ESXi host machines. The APG took the opportunity to reverse engineer the sample in hopes of acquiring the decryption keys. During the investigation, the APG uncovered several interesting discoveries.

New ARCrypter Variant

ChileLocker was first reported back in August 2022 by Chile’s Computer Security and Incident Response Team (CSIRT). Details of the original variant can be found here. ChileLocker falls under the ARCrypter malware family and borrows several features from Red Alert ransomware.

The recent version, named dist_386, is written in the Golang programming language and is compiled into a 32-bit ELF (Executable and Linkable Format) file, which runs on most Unix-like operating systems. Figure 1 shows how the file command finds this information, including un-stripped symbols.

 

Figure 1: File information

Figure 1: File information

 

This leads to the first two interesting discoveries:

  • The file naming convention, dist_386, suggests that the file could be masquerading as a distribution file compiled for an x86-based processor.
  • The malware is not stripped, meaning a symbol table for function and variable names, as well as debugging information, are still present in the binary.

Malicious binaries that are un-stripped of their symbolic information are not a common occurrence. This information is usually removed to make reverse engineering and static analysis more difficult. This, coupled with the name of the binary, leads to several questions about the malware author’s intentions or lack thereof. Was it a mistake or simply a lack of skill?

Failure to Launch?

When the sample is executed without an argument, it will print out a help statement requesting a path to be encrypted as seen in Figure 2.

 

Figure 2: Path to be encrypted

Figure 2: Path to be encrypted

 

If a path is provided, the malware will proceed to encrypt anything in the folder recursively. All encrypted files are then appended with a .crypt extension and a ransom note named ReadMeToDecrypt.txt is placed in each directory (Figure 3).

 

Figure 3: Encrypted directory and ransom note

Figure 3: Encrypted directory and ransom note

 

This leads to the next two interesting discoveries:

  • The sample takes a path as an argument and will quit if no argument is provided.
  • The ransom note is empty! Notice the size of the ransom note is 0 kilobytes in Figure 3.

Unlike RedAlert ransomware, which encrypts the current directory by default if a path argument is not specified, this sample will not execute unless an existing path is provided.

Writing a ransom note with no content is a major mistake. The note’s contents are found in the binary and can be extracted manually. There are a couple cross-references to the note when viewed in a disassembler and oddly enough, the symbol name for the note is _noteRaaS. RaaS is short for Ransomware as a Service (Figure 4).

 

Figure 4: Ransom note

Figure 4: Ransom note

Encryption

The sample uses the ChaCha20 cipher to generate a key stream and encrypt files with XORKeyStream. The same key stream can also be used to decrypt files. Unless the key stream is exfiltrated or encrypted with a public key in the encrypted file, there is no way for recovery. This sample does not make any network connections, nor does it have any functionality for asymmetric cryptography. What we do find are bytes appended to each encrypted file of a fixed length which we expand on further down in the report. The following will detail how this sample generates its key stream, what data is appended to each file, and how the authors got it wrong.

ScalarMult

A 32-byte array is randomly generated with crypto/rand.Reader and is used as the scalar argument for the first call to crypto/curve25519/ScalarMult. The base point argument is hard coded as 0x9, followed by 31 0x0 bytes, and the result is stored in dest1 (Figure 5).

 

Figure 5: First call to ScalarMult

Figure 5: First call to ScalarMult

 

A second call is made to ScalarMult with the same scalar but a different base point of:

0B B8 11 92 24 DA 83 CD 75 F6 DB 8D 93 6C 1B DD A5 B1 2F D2 3E 7B CE 51 F4 FB 37 96 00 E1 D9 33

 

The result is stored in dst2 (Figure 6).

 

Figure 6: Call to second ScalarMult function

Figure 6: Call to second ScalarMult function

Hashing and Key Stream

The resulting 32 bytes are hashed with the SHA256 algorithm, which is the encryption key. The key is hashed again with SHA256 to create the nonce. The nonce is a 12-byte slice of the hash starting at offset 20. The key and the nonce are passed to crypto/chacha20/newUnauthenticatedCipher to create a key stream cipher (Figure 7).

 

Figure 7: Generating key and nonce

Figure 7: Generating key and nonce

 

Below is the structure of a key stream in memory (Figure 8).

 

Figure 8: Example keystream

Figure 8: Example keystream

 

To demonstrate how the nonce is derived from the hashed key, we can create a recipe in CyberChef to convert the key hash to a string, then hash it with SHA256. Notice that the nonce begins at offset 20 of the hashed key (Figures 8 & 9).

 

Figure 9: Hashed key to obtain nonce

Figure 9: Hashed key to obtain nonce

XORKeyStream

The ChaCha20/XORKeyStream function is used to encrypt files using the newly generated key stream (Figure 10).

 

Figure 10: XORKeyStream

Figure 10: XORKeyStream

 

The 32 bytes generated from the first call to ScalarMult are written to the end of the encrypted file, along with the bytes 0xabbccddeeff0 (Figure 11).

 

Figure 11: Appending scalar and an additional six bytes

Figure 11: Appending scalar and an additional six bytes

 

The original test file, which contained the text “hello world”, is now encrypted with some additional data.

 

Figure 12: Encrypted file

Figure 12: Encrypted file

 

To summarize the steps for encryption:

  1. Generate random 32 bytes and pass to first call of ScalarMult
  2. Save the results of ScalarMult on the stack for later
  3. Pass the same random 32 bytes to a second call of ScalarMult
  4. Hash with result with SHA256, which becomes the key
  5. Hash the key with SHA256 and take a 12-byte slice of the result as the nonce
  6. Generate the keystream with newUnauthenticatedCipher
  7. Encrypt the file with XORKeyStream
  8. Append the 32-byte result of the first call to ScalarMult to the end of the file
  9. Append the bytes “0xab 0xbc 0xcd 0xde 0xef 0xf0” to the end of each file.

This brings us to the largest mistake observed in the sample. Saving the result of the first call to ScalarMult is fine, however, it is never used again in the routine! Instead, the same randomly generated 32 bytes are passed along, which cannot be guessed or recovered. The authors should have either used the result of the first ScalarMult call in the second call or saved the randomly generated bytes to the end of the file and encrypted it with a public key. That said, any file encrypted with this sample is not recoverable!

Summary

While ransomware authors often use advanced techniques to evade detection and maximize their profits, they are not immune to making mistakes. It is difficult to determine if this was a result of poor coding or the deployment of an unfinished product. These errors can sometimes provide victims with a way to recover their files or in this case, refuse to pay a ransom for files that cannot be recovered. What is important is staying vigilant in the fight against ransomware by ensuring that you keep your software up to date, maintain backups of your data, and invest in an endpoint protection solution.

Blackpoint Brief – The Cyber Intel You Need

Don’t want to miss any of APG’s write-ups or podcast episodes? Subscribe to the Blackpoint Brief! Our monthly e-newsletter covers the latest APG research, SOC saves, sales resources, and more. Stay up to date so you can best protect your clients. 

Subscribe now!

Want something new to listen to?

Check out our podcast, The Unfair Fight, where you can hear industry insights from Blackpoint Cyber leadership and our special guests firsthand.