PrideLocker - a new fork of Babuk ESX encryptor
Introduction
During an incident response that occurred a few months ago, involving a ransomware attack, we encountered several pieces of malware.
- Dagon Locker1, a ransomware targeting Windows assets. It seems to be the new variant of MountLocker. Its analysis reveals that the Dagon Locker sample involved in this case is quite similar to the analysis made by SecurityScorecard on Quantum Locker (the version based on MountLocker that precedes Dagon).2
- Several CobaltStrike beacons and custom tools,
- And an ELF ransomware targeting ESXi servers named PrideLocker, which we focus on in this article.
After analysis, we concluded that PrideLocker is most probably a derivative of the Babuk ESX ransomware whose source code leaked in September 202134. In May 2022, TrendMicro described another ESX ransomware named CheersCrypt that is even more similar to Babuk ESX leaked source code5.
Therefore, the purpose of this article is to describe the new additions brought by PrideLocker. Another purpose is also to help detect PrideLocker and variants based on Babuk source code in order to improve the qualification of such ransomware during incident response.
Basic information
File name | encryptor.esx.bin |
MD5 | 2dbf12d19306611b8deeb708bc61c18c |
SHA1 | a0e29552db15adc29ac60dc7e5fe757b42e07a76 |
SHA256 | a312fef3873b96ce5829cc00b724291ece7a0fd238a007c52695dc4a3268e3c1 |
File type | ELF 64-bit LSB executable x86_64 stripped |
File size | 165928 |
Threat | ESX ransomware |
Ransom note
What happened?
All your files are encrypted on all devices across the network
Huge volume of your data including financial, customer, partner and employees data was downloaded to our internal servers
What's next?
If you don't get in touch with us next 48 hours, we'll start publishing your data
How do I recover?
There is no way to decrypt your files manually unless we provide a special decryption tool
Please download TOR browser (https://www.torproject.org/) and CONTACT US (http://<redacted>.onion/?cid=<redacted>) for further instructions
Ransom note
Quantum Locker is the version preceding Dagon Locker, so it is not surprising to see it appearing on the *secure* chat linked to this PrideLocker sample ransom note, since Dagon Locker was deployed to encrypt Windows assets in this ransomware attack.
Code analysis
String Obfuscation
The PrideLocker sample we encountered obfuscated its strings. Let's cover in detail its obfuscation mechanism.
The picture below describes the beginning of the main function assembly code. The string loading pattern is always the same:
- Call a function that loads an encrypted stack string
- Call a function containing a unique key to decrypt the string
Below is a function loading an encrypted stack string. The first byte is the length of the encrypted string.
Next, the decryption function of such encrypted string loads a unique QWORD (8 bytes) as a key and calls another function that is the actual decryption routine.
The decryption routine is quite simple. Each byte of the encrypted string is xor-ed with the shifted key.
Below is the decryption routine translated in Python:
def decrypt_string(enc_str, qword_key):
dec_str = bytearray(len(enc_str))
for i in range(0, len(enc_str)):
tmp = (qword_key >> (8 * (i&7)))&0xff
dec_str[i] = enc_str[i] ^ tmp
return dec_str
How to analyse such program with this kind of obfuscation? Each string has its own loading functions: one loading the encrypted stack string and one decrypting it. Therefore, there are hundreds of functions involved in loading and decrypting the strings. However, the pattern remains similar and the same decryption routine (sub_408D0C
) is used.
I wanted to get all the strings decrypted in order to have a good understanding of this malware, without spending too much time debugging it. Therefore, I chose to develop an IDA Python script since I am more used to this framework. To help develop such a script, I recommend reading icecr4ck's IDA Python cheat sheet6 and of course the official documentation7.
The full script is available on Synacktiv's Github organization: https://github.com/synacktiv/pridelocker-analysis
The approach of this script is first to get all the cross-references (XrefsTo
) from the unique decryption routine. That way, for each cross-reference, we can fetch the unique key and the length of the encrypted string. Then the instruction pointer is moved back until the Stack string loader function is found (check get_function_with_encrypted_string
function in the script). Once this function is found, it is browsed until the stack string is loaded (get_encrypted_string
function). Finally, the stack string is collected, decrypted, and added as a new IDA comment in both disassembly and decompiler views. Moreover, the obfuscation functions that have been met in the process are renamed. That way, I can focus on the relevant code of the ransomware, and leave the obfuscation part behind.
You can see below the beginning of the main function in both disassembler and decompiler views, after the execution of the script.
As you can see in Figure 6, every string has been recovered correctly. Also, around 280 functions have been renamed in the process, so that's a lot of code I could skip. 😃
As a reminder, I made a list of a few IDA Python functions that are useful most of the time:
- Moving around the assembly:
- looping over a list of instruction based on the start and end addresses:
idautils.Heads
, - cross-references of an address:
idautils.XrefsTo
, - get the function that possesses a specific address:
ida_funcs.get_func
.
- looping over a list of instruction based on the start and end addresses:
- Decoding instructions:
- current instruction pointed by an address:
idautils.DecodeInstruction
, - get the previous instruction:
idautils.DecodePreviousInstruction
, - get the text representation of the mnemonic (mov, call, etc.):
idc.print_insn_mnem
, - get the operand type (o_reg, o_displ, o_imm):
idc.get_operand_type
, - get the operand value:
idc.get_operand_value
, - get the text representation of the operand:
idc.print_operand
.
- current instruction pointed by an address:
- Getting data:
- get bytes (e.g. a chunk of data to decrypt):
idc.get_bytes
, - get the string contents pointed by an address:
idc.get_strlit_contents
.
- get bytes (e.g. a chunk of data to decrypt):
- Setting comments:
- In the disassembly :
idc.set_cmt
- In the decompiler, it's a bit more complicated, I recommend reading the function
setCommentToDecompilation
from my script, that I actually took from gdataadvancedanalytics' ida-python GitHub repository8.
- In the disassembly :
Command line arguments
Babuk ESX Locker required to be executed with the target path to encrypt as a command line argument. It did not require other arguments.
On contrary, PrideLocker can be executed without any argument. Several optional arguments can also be specified from the command line. The following help note is printed when executed with the -h
flag:
PrideLocker ESX Encryptor (HYDRA-220218) started
Usage: ./encryptor.esx.bin <arguments>
Arguments:
-h, --help Show this help message and exit
-v, --verbose (OPTIONAL) Verbose encryptor output
-p, --path (OPTIONAL) Path to encrypt (/vmfs/volumes by default)
-d, --dryrun (OPTIONAL) Run in dryrun mode (i.e. no real encryption)
-n, --nostop (OPTIONAL) Do not stop VMs
-t, --threads (OPTIONAL) Set number of threads
Help note
As you can see in the help note, the first line PrideLocker ESX Encryptor (HYDRA-220218) started
indicates the name of the ransomware "PrideLocker ESX Encryptor" and probably some kind of build version "HYDRA-220218".
The default path to encrypt is /vmfs/volumes
. It is actually the default path where virtual machines are stored in ESXi (the datastore browsable from vSphere client). Among the optional arguments, it is possible to specify the path to encrypt, to choose not to stop the virtual machines before encryption, to specify a number of threads, to enable the verbose mode, or even to run in dry-run mode. The dry-run mode does not stop the virtual machines and does not encrypt the files.
Time-limited license
At the very beginning of the execution, the current time is checked against one stored and encrypted in .data
segment.
If the current timestamp is 14 days too late or too early to the one stored in the .data segment, the encryptor exits with the following error:
Err: LICEXPR => <c>1668595744 <l>[encrypted hardcoded timestamp] <d>[hardcoded timestamp]
<c>1668595744
being the current timestamp.
As you probably guessed, it is a very simple mechanism to prevent this specific sample from being executed outside the expected period of execution planned by the attackers.
This functionality is not present in the source code of Babuk ESX. So we think it is specific to PrideLocker.
Thread pool
The thread handling is the same as in Babuk ESX source code, except that the number of threads can be customised from the command line with option -t
.
Virtual machines shutdown
PrideLocker creates a temporary file named /tmp/stopall.sh
. It contains the following shell script:
for i in $(esxcli vm process list 2>/dev/null| grep 'World ID:' | grep -o '[0-9]*'); do esxcli vm process kill --type=force --world-id=$i; done;
This script is executed then removed.
It is common to see the use of esxcli
command in ESXi encryptors in order to shutdown virtual machines before encrypting them9. However, this functionality was not present in Babuk ESX source code. By the way, both the script path /tmp/stopall.sh
and the escxli
command are in clear text in the data segment of the ransomware, so we can use that for the detection!
Encryption process
The ransom note is created in the specified path to encrypt (default is /vmfs/volumes
). The filename is HOW TO RECOVER YOUR FILES.txt
. Its content has been detailed in the Ransom note section.
Then PrideLocker recursively scans the path to encrypt. Only files with the following filename extensions are targeted:
.log
.vmdk
.vmem
.vswp
.vmsn
.vib
.vbm
.vbk
Contrary to Babuk ESX encryptor, PrideLocker adds three new filename extensions that targets Veeam Agent backup files10:
.vib
: incremental backup files that store incremental changes of VM images,.vbm
: backup metadata files that store information about the backup job,- and
.vbk
: the full backup files that store copies of full VM images.
When a file matches one of these extensions, it is encrypted in a new thread.
Encryption algorithm
The encryption routine used by PrideLocker is the same as the one in Babuk ESX and CheersCrypt5 so I will not give a thorough description of the algorithm. It uses SOSEMANUK stream cipher to encrypt files. The ECDH (X25519) algorithm, combined with SHA256, are used to generate the SOSEMANUK key. In the picture below, the left side is the encryption routine as described in Babuk ESX source code, and the right side is the decompiled version of PrideLocker encryption routine.
The encrypted files are renamed with the .encrypted
extension.
The sample is stripped, so when I first analysed this piece of malware it was difficult to recognise the SOSEMANUK and ECDH algorithms. So I gave this piece of malware to my colleague Eloi Benoist-vanderbeken, who succeeded to determine the complete encryption routine. Thanks to that, the similarity with Babuk ESX became obvious. The detection section gives tips and rules to help detecting these encryption algorithms.
Stats
At the end of the execution, statistics about how it performed are printed, indicating some numbers. Below is an example of what is printed, if the verbose mode -v
is enabled:
Stats:
found files: 142
encrypted files: 54
skipped files: 72
failed files: 06
Total encrypted volume: 123.0 GiB
This functionality was already present in Babuk ESX, the strings are just slightly different.
Detection
The following pattern helps detecting the ECDH (or Curve25519) algorithm:
u_priv[0] &= 248;
u_priv[31] &= 127;
u_priv[31] |= 64;
These instructions clear the bits 0, 1, 2 of the first byte, clear the bit 7 of the last byte, and set the bit 6 of the last byte of the generated secret key. Its purpose is for security reasons of Curve25519 algorithm, as defined in David Bernstein's paper11.
Regarding the detection of SOSEMANUK, the constant 0x54655307 is used in order to update its finite state machine12. 0x54655307 is the hexadecimal representation of the first ten decimals of π. I did not find any use of this constant other than in SOSEMANUK. Moreover, there are two bytes arrays, which - I think - are related to polynomial multiplication used to update the shift register13. Anyway, they are great to detect SOSEMANUK encryption capability.
PrideLocker Yara rule
Below is a Yara rule whose purpose is to detect similar PrideLocker samples:
rule Linux_Ransomware_PrideLocker
{
meta:
author = "Theo Letailleur, Synacktiv"
source = "Synacktiv"
status = "RELEASED"
sharing = "TLP:WHITE"
category = "MALWARE"
malware = "PrideLocker"
description = "Yara rule that detects PrideLocker ransomware"
strings:
// for i in $(esxcli vm process list 2>/dev/null| grep 'World ID:' | grep -o '[0-9]*'); do esxcli vm process kill --type=force --world-id=$i; done;
$shut_down_esxi = {
66 6F 72 20 69 20 69 6E 20 24 28 65 73 78 63 6C 69 20 76 6D 20 70 72 6F 63 65 73
73 20 6C 69 73 74 20 32 3E 2F 64 65 76 2F 6E 75 6C 6C 7C 20 67 72 65 70 20 27 57
6F 72 6C 64 20 49 44 3A 27 20 7C 20 67 72 65 70 20 2D 6F 20 27 5B 30 2D 39 5D 2A
27 29 3B 20 64 6F 20 65 73 78 63 6C 69 20 76 6D 20 70 72 6F 63 65 73 73 20 6B 69
6C 6C 20 2D 2D 74 79 70 65 3D 66 6F 72 63 65 20 2D 2D 77 6F 72 6C 64 2D 69 64 3D
24 69 3B 20 64 6F 6E 65 3B
}
// Load "/tmp/stopall.sh" string
$shut_down_esxi_load_filename = {
48 B? 2F 74 6D 70 2F 73 74 6F // mov r64, 6F74732F706D742Fh
48 89 ?? ?? // mov qword ptr [rbp+?], r64
48 B? 70 61 6C 6C 2E 73 68 00 // mov r64, 68732E6C6C6170h
48 89 ?? ?? // mov [rbp+?], r64
}
$x25519_clear_set_bits = {
0F B6 ?? [1-4] // movzx r32, [rbp+?]
83 ?? F8 // and r32, 0FFFFFFF8h
88 ?? [1-4] // mov [rbp+?], r8
0F B6 ?? [1-4] // movzx r32, [rbp+?]
83 ?? 7F // and r32, 7Fh
88 ?? [1-4] // mov [rbp+?], r8
0F B6 ?? [1-4] // movzx r32, [rbp+?]
83 ?? 40 // or r32, 40h
88 ?? [1-4] // mov [rbp+?], r8
??
}
// Multiplication by alpha: alpha * x = T32(x << 8) ^ mul_a[x >> 24]
$sosemanuk_encrypt_mul_a = {
00 00 00 00 E1 9F CF 13 6B 97 37 26 8A 08 F8 35 D6 87 6E 4C 37 18 A1 5F BD 10 59
6A 5C 8F 96 79 05 A7 DC 98 E4 38 13 8B 6E 30 EB BE 8F AF 24 AD D3 20 B2 D4 32 BF
7D C7 B8 B7 85 F2 59 28 4A E1 0A E7 11 99 EB 78 DE 8A 61 70 26 BF 80 EF E9 AC DC
60 7F D5 3D FF B0 C6 B7 F7 48 F3 56 68 87 E0 0F 40 CD 01 EE DF 02 12 64 D7 FA 27
85 48 35 34 D9 C7 A3 4D 38 58 6C 5E B2 50 94 6B 53 CF 5B 78
}
// DWORD array version
$sosemanuk_encrypt_mul_a_4byte_array_le = {
00 00 00 00 13 CF 9F E1 26 37 97 6B 35 F8 08 8A 4C 6E 87 D6 5F A1 18 37 6A 59 10
BD 79 96 8F 5C 98 DC A7 05 8B 13 38 E4 BE EB 30 6E AD 24 AF 8F D4 B2 20 D3 C7 7D
BF 32 F2 85 B7 B8 E1 4A 28 59 99 11 E7 0A 8A DE 78 EB BF 26 70 61 AC E9 EF 80 D5
7F 60 DC C6 B0 FF 3D F3 48 F7 B7 E0 87 68 56 01 CD 40 0F 12 02 DF EE 27 FA D7 64
34 35 48 85 4D A3 C7 D9 5E 6C 58 38 6B 94 50 B2 78 5B CF 53
}
// Multiplication by 1/alpha: 1/alpha * x = (x >> 8) ^ mul_ia[x & 0xFF]
$sosemanuk_encrypt_mul_ia = {
00 00 00 00 18 0F 40 CD 30 1E 80 33 28 11 C0 FE 60 3C A9 66 78 33 E9 AB 50 22 29
55 48 2D 69 98 C0 78 FB CC D8 77 BB 01 F0 66 7B FF E8 69 3B 32 A0 44 52 AA B8 4B
12 67 90 5A D2 99 88 55 92 54 29 F0 5F 31 31 FF 1F FC 19 EE DF 02 01 E1 9F CF 49
CC F6 57 51 C3 B6 9A 79 D2 76 64 61 DD 36 A9 E9 88 A4 FD F1 87 E4 30 D9 96 24 CE
C1 99 64 03 89 B4 0D 9B 91 BB 4D 56 B9 AA 8D A8 A1 A5 CD 65
}
// DWORD array version
$sosemanuk_encrypt_kk_mul_ia_4byte_array_le = {
00 00 00 00 CD 40 0F 18 33 80 1E 30 FE C0 11 28 66 A9 3C 60 AB E9 33 78 55 29 22
50 98 69 2D 48 CC FB 78 C0 01 BB 77 D8 FF 7B 66 F0 32 3B 69 E8 AA 52 44 A0 67 12
4B B8 99 D2 5A 90 54 92 55 88 31 5F F0 29 FC 1F FF 31 02 DF EE 19 CF 9F E1 01 57
F6 CC 49 9A B6 C3 51 64 76 D2 79 A9 36 DD 61 FD A4 88 E9 30 E4 87 F1 CE 24 96 D9
03 64 99 C1 9B 0D B4 89 56 4D BB 91 A8 8D AA B9 65 CD A5 A1
}
condition:
uint32(0) == 0x464C457F and
(
$shut_down_esxi and $shut_down_esxi_load_filename
and $x25519_clear_set_bits
and 2 of ($sosemanuk_encrypt_*)
)
}
You can find the Yara rule on our Github repository: https://github.com/synacktiv/pridelocker-analysis
The conditions could be loosened up a bit (e.g. or between $shut_down rules and crypto rules) to detect more variants.
ECDH and SOSEMANUK CAPA rules
CAPA14 is a tool developed by Mandiant FLARE team that detects capabilities in executable files.
To detect ECDH algorithm, there is already a Mandiant's CAPA rule named encrypt data using Curve25519
written by Dimiter Andonov15 that helps detecting the encryption function.
To detect Sosemanuk algorithm, there is also a Mandiant's CAPA rule named encrypt data using Sosemanuk
written by Andrew Williams16 that does a pretty good job detecting the encryption function. New CAPA rules to detect sosemanuk_schedule
and sosemanuk_init
function could be added.
Conclusion
PrideLocker ESX encryptor is a Babuk ESX encryptor fork that brings new features: string obfuscation, the shutdown of virtual machines using esxcli
, optional command line arguments, and a time-limited "license". The ransom note shows that the affiliate using Dagon Locker and involved in our incident response, is also using PrideLocker to target ESXi servers, but we cannot say whether there is a link between the developers of both encryptors.
Based on this PrideLocker sample analysis, a methodology using IDAPython to automate the decryption of strings as been detailed.
Finally, tips to detect ECDH and Sosemanuk algorithms covered in this article can help detecting other recent ransomware families based on Babuk leaked encryptors.
Many thanks to Eloi, who helped us to determine PrideLocker encryption capabilities.
- 1. https://malpedia.caad.fkie.fraunhofer.de/details/win.mount_locker
- 2. https://securityscorecard.pathfactory.com/research/quantum-ransomware
- 3. https://cyberthreatintelligence.com/news/full-source-code-of-babuk-rans…
- 4. https://github.com/Hildaboo/BabukRansomwareSourceCode
- 5. a. b. https://www.trendmicro.com/en_us/research/22/e/new-linux-based-ransomwa…
- 6. https://gist.github.com/icecr4ck/7a7af3277787c794c66965517199fc9c
- 7. https://www.hex-rays.com/products/ida/support/idapython_docs/
- 8. https://github.com/gdataadvancedanalytics/ida-python/blob/master/Trickb…
- 9. https://blogs.vmware.com/security/2022/10/esxi-targeting-ransomware-tac…
- 10. https://helpcenter.veeam.com/docs/backup/vsphere/backup_files.html?ver=…
- 11. http://cr.yp.to/ecdh/curve25519-20060209.pdf
- 12. https://www.rocq.inria.fr/secret/Anne.Canteaut/Publications/BBC08a.pdf
- 13. https://github.com/Hildaboo/BabukRansomwareSourceCode/blob/main/esxi/en…
- 14. https://github.com/mandiant/capa
- 15. https://github.com/mandiant/capa-rules/blob/d2ad3a045a39e7656ddff7cdec5…
- 16. https://github.com/mandiant/capa-rules/blob/d2ad3a045a39e7656ddff7cdec5…