Inside the world of ransomware dissecting the attack
After some time of respite in the world of ransomware, different players in the field started rebranding their operations. Recently, one of the most active groups returned. The notorious LockBit group introduced a new strain of their ransomware, LockBit 3.0. More specifically, the threat actor dubbed its latest release LockBit Black, enriching it with new extortion tactics and introducing an option to pay in Zcash, in addition to the already offered Bitcoin and Monero crypto payment alternatives.
Additionally, as a first in the ransomware world, LockBit launched a bug bounty program with rewards ranging from a thousand to a million dollars. Confident of its privacy, the affiliate manager, known as LockBitSupp, offers one million dollars for anyone who can reveal his real identity.
Within the infosec community, several analyses showed that LockBit 3.0 seems heavily based on the BlackMatter codebase, hence the name LockBit Black [1, 2]. Following our previous whitepaper on LockBit, Northwave obtained a sample of the latest strain and performed an in-depth analysis. Additionally, Northwave tried to recover the config and extracted information that could help during incident response engagements and support the root cause analysis. This blog presents the method for extracting the config from a LockBit Black sample and describes the included fields and functions.
Furthermore, Northwave published an open-source IDAPython script for analysing the config and scripts to perform the necessary string decryption and API call deobfuscation. Finally, Northwave will add a command-line tool for dumping the content of the config. All of this is available on Northwave's GitHub.
Unlike BlackCat, which included its config in plaintext up until recently, the LockBit 3.0 authors exert extreme effort to hide their configuration details.
The malware starts by unpacking itself in place (a good hint is given that the
segment is Read-Write-eXecute) and then initialises its custom Import Address Table for calling API functions.
After these two initial steps, the malware begins executing, starting with a call to a big <code>__setup</code> function. This entire function mainly concerns running functionality to configure and prepare the environment for successful ransomware execution. Many of these steps depend on values from the config; hence, we see the config decryption function being called very early in the setup stage.
Again, LockBit takes extra measures here to protect its most important data. Rather than just decrypting once, it takes numerous decryption, decompression and decoding steps to extract the entire config. From our analysis, we observed that LockBit splits its config decryption into three main parts:
Before one can access any of the config's individual sections, full decryption must occur. In the sample, we can see that it takes a pointer to the start of the config and takes two steps (custom decrypt, aplib decompress) to decrypt it fully.
The `load_and_decrypt_config_value` function contains logic for the config's decryption, its values and the decryption of values in the data segment. This function works as follows:
- Take the pointer to the start of the encrypted block, read out the 4 bytes preceding it to get the size, and allocate it.
- Copy the encrypted blob into the newly made allocation using the given <code>size</code>.
- Pass the allocation and its size to the decryption function.
- Once again, take the pointer to the start of the config section, and read out the first two dwords. The <code>custom_rand</code> function uses these two dwords as a "seed".
- Call the <code>custom_rand</code> function with the two dwords and a pointer to the config section as arguments. This function returns 2 "random" dwords used as a key in step
- Use bytes from the two random dwords and use them to decrypt the encrypted blob (8 bytes at a time).
NOTE: The <code>custom_rand</code> function is generated dynamically and needs to be either decrypted separately or viewed inside a debugger.
As the decryption uses dwords generated from a given seed that is constant for a given sample, it is unnecessary to decrypt each blob 8 bytes at a time. Instead, with careful analysis, it is possible to convert the decryption scheme into a "keystream" generator that can generate a potentially infinitely long stream of key bytes based on the seed for a given sample.
We have taken some time to write this out in c for clarity. Below you will find the decryption scheme transformed into a key stream generator that one can use to decrypt any encrypted blob in the sample.
After decrypting and aplib decompressing the entire config blob, the parameters inside of the variable block become visible. In our sample, this block was
bytes long and contained three values. More on the meaning of the values later.
The string block is slightly more obtuse as opposed to the variable block. The string block is formatted using a header with an array of offsets from the base of the string block to base64 encoded strings. There is no clear way of finding the size of this array except for analysing the config decryption function. In the case of our sample, it supports up to ten entries. However, there are not guaranteed to be ten because individual offset entries can be 0, in which case the string is ignored.
The first eight entries just require a base64 decode. The last two entries need additional decryption.
For a complete overview of the decryption steps described above, please take a look at our example IDApython script for dealing with LockBit's config.
After decrypting the config, the following values will remain.
Functionality activated if the value is set unless states otherwise.
While LockBit Black looks to be taking much of its code from the BlackMatter ransomware, the codebase has seen quite a refresh. With the config and other parts changing substantially, we deemed it time for an update to the existing knowledge. We hope this analysis and the tools provided will benefit the infosec community and support CERTs worldwide dealing with LockBit cases.