Authors:
Ilia Dafchev, Security Researcher
Albert Zsigovits, Senior Security Researcher
Robert Neumann, Head, Acronis Cyber Protection Operations Center
Introduction
Unless you’ve been hibernating for the past decade, ransomware needs no further introduction. Hundreds of different ransomware families have emerged over the years. Initially, attackers aimed for mass impact via email as the main infection vector. Later, ransomware became more sophisticated and targeted, introducing and utilizing the RaaS model and adding double extortion to the mix, while still being true to its roots.
This article is the first in the ransomware diaries series. We will provide an in-depth look at some active ransomware families, such as Mallox or encryptors from the Epsilon Gang, revealing the unique picture they occasionally paint, along with commonalities they maintain along the way. Every family will represent a different piece of the current ransomware landscape to showcase how diversified it has become over the years.
Crypto done (almost) right
In this article, we delve into the inner workings of a recently identified ransomware family: QazLocker. It will serve as a reminder that the ransomware landscape — like the malware landscape in general — is diverse, encompassing both high-level threats and those with weaknesses that offer a chance for restoration. In each case, we will explore the attacker’s modus operandi, the tools leveraged by the threat actors and the encryption method they implemented.
Most ransomware families encrypt files in a way that makes is impossible to restore without the encryption key due to known limitations with breaking cryptological algorithms. Occasionally, however, new families will appear with a far-from-perfect implementation.
In the QazLocker case we have been investigating, threat actors mostly used readily available, off-the-shelf hacking tools for password dumping and port scanning. There were four days of dwell time between the first indications of compromise and several attempts at launching their “almost done right” ransomware payload.
Technical analysis
Tactics, techniques and procedures
Initially, the perpetrators showcased a mix of tools aimed at escalating privileges and spreading across the local network. Notably, several well-known hacking tools and so-called freeware admin utilities — misused for reconnaissance and lateral movement — were employed, including:
· Mimikatz
· Advanced Port Scanner
· Network Share Scanner (NS.exe) tool
· NirSoft MessenPass (mspass.exe)
· NirSoft Protected Storage Pass View (pspv.exe)
· NirSoft Password Sniffer (SniffPass.exe)
· NirSoft Wireless Key View
These tools were predominantly located either in the “C:\Users\<user>\Desktop\Loki[tools]\” directory or in the Downloads folder. Also present is a batch script called “!start.cmd,” which executes the following Mimikatz command to dump token and credentials:
Additional observations included attempts to install the Traffmonetizer PUA application and launch a suspicious “svchost.exe” binary from the desktop.
On day four of the attack, the threat actors introduced the ransomware payload “C:\PROGRA~2\COMMON~1\anti.exe” as a scheduled task.
Note that while these malicious programs were thwarted by Acronis Cyber Protect, the attackers persisted in their endeavors, and in the following weeks, tried to re-run them several times. After a couple of weeks of unsuccessful encryption attempts, the threat actors tried to deploy the RDP brute-force tool NLBrute, probably in an attempt to spread internally or use the compromised host to target other publicly accessible RDP services. This action also points to the possibility of and RDP-based initial attack vector. To see what damage it might pose, we took a copy of the payload, executed it without any protection in place and conducted an in-depth analysis.
Analysis of the ransomware binary
The main ransomware payload is a compiled AutoIt script with the UPX packer on top, which is a commonly used tool for compressing executables, especially in case of AutoIt. Upon execution of the payload, it carries out a set of commands, the majority being typical of ransomware threats. All the activities, including the encryption (more on that later), are implemented purely in the scripting capabilities of AutoIt. It will check the network configuration, create a new scheduled task, delete shadow copies, disable Windows automatic repair and set the “BootStatusPolicy” to “IgnoreAllFailures”. Each command window will set its title to a random number. Next, the encryptor replicates itself to “C:\Program Files (x86)\Common Files” and saves the log of encrypted files as “log.txt” in the same folder.
Once the encryption process is completed, the ransomware displays a ransom note in Notepad, along with a GUI window showing the list of encrypted files. The presence of an input field called “Key” suggests the potential of reversibility, as it would need to check the validity of it. Encrypted files retain their original extensions with an “.encrypted” string inserted before it, such as “test.encrypted.exe” for a file called “test.exe”.
Ransom note
The ransom note displayed in Notepad is rather simplistic — there are multiple email addresses provided for communication, along with the LOCK-ID specific to the given PC. There is no link to darknet sites or any sign of a wall of shame, no crypto coin wallet and no indication of the ransom the attackers would demand.
Dissecting AutoIt
AutoIt is a highly popular automation tool used by many IT professionals due to its flexible scripting capabilities, including compiling and embedding scripts into an executable for easy portability. There are various options for reversing and decompiling AutoIt binaries; however, depending on the skill set of the authors, we might face additional layers of obfuscation. After the initial decompilation, we were presented with a script using hex-encoded AutoIt code, as shown in the figure below.
Once we’ve deobfuscated, we will have a much more interpretable script for output. The core functionality of the script leverages Windows API function calls to achieve its goals. Both for basic file operations and encryption, it uses functions from system libraries such as kernel32.dll and advapi32.dll.
Network artifacts
Despite the attackers leaving no signs of their demands in the ransom note, we observed that the executable was trying to connect to “blockchain.info” to check the current bitcoin (BTC) value of $1,000 or $200, depending on whether the host is domain joined or not. If it succeeds, then the returned value is written as text to a file under “C:\Program Files (x86)\Common Files”. This file and the BTC value are not used elsewhere. This might indicate that the ransomware is based on existing code that was modified and certain functionality left unused instead of being removed.
Key generation flaws
Modern ransomware is known for having "safe enough” implementation of the cryptographic algorithms used for encryption. Cybercriminals often combine a fast, symmetric algorithm (i.e., AES, ChaCha20) and a considerably slower but significantly more secure asymmetric one (i.e., RSA, ECDSA) that protects the key generated by the former. How secure the final result will be depends not only on the algorithms chosen, but also on the actual implementation — even the most secure lock in the world is worthless if one leaves the key under the doormat.
While analyzing the deobfuscated AutoIt script in detail, we concluded that implementation might also be flawed. We discovered that the “LOCK-ID” in the ransom note was used as a seed for the key generation algorithm. The “LOCK-ID” is produced by getting the first (top) MAC address returned in the output from the “ipconfig /all” command, removing the delimiters and appending the current month as a hex digit to it.
The last five bytes from the LOCK-ID are used in the key derivation; those will be encrypted with RC4. The passphrase set for RC4 is the MD5 hash of the string “Kernel32.dll” — the output cipher text is also five bytes long. An MD5 hash of these five bytes is calculated, and the final result is used in the Windows API “CryptDeriveKey” to derive an AES 256bit key. The generated key is used with the Windows function “CryptEncrypt” to encrypt the files using AES cipher in CBC mode and the initialization vector (IV) set to zeroes.
Consequently, to derive the decryption key, either the LOCK-ID is needed or, alternatively, the month when encryption took place and the MAC address of the PC.
Building a decryptor
As showcased above, the encryption scheme in our case can be easily reversed due to a weak implementation of the otherwise secure encryption algorithms. To restore the encrypted files, we have created a proof-of-concept decryptor script in Python, which you can find in the appendix.
Conclusion
In this first article in the ransomware diaries, we have aimed to showcase a ransomware family that represents the lower ranks of the cybercriminal hierarchy. Our analysis reveals what happens when cybercriminals have the right (bad) intentions, but lack the skills required to build a sophisticated ransomware threat or penetrate the defenses of valuable targets. Despite the unsophisticated nature of QazLocker ransomware, it is still capable of encrypting critical information and causing significant damage for victims, especially those who lack adequate data backups and comprehensive endpoint protection.
Given the notoriety of major ransomware groups and the frequent media coverage of ransomware attacks, companies and individuals might assume that the possibility of decrypting their files is futile. While most of the time the above statement is correct, our analysis illustrates that less sophisticated threats still lurk in the wild and, encouragingly, file restoration might be achieved without succumbing to ransom demands. Unfortunately, the ransomware landscape is diverse and full of threat actors capable of causing damage of higher magnitudes. Stay tuned for part two of the ransomware diaries.
Protection statement
Acronis Active Protection, an advanced ransomware protection technology, protects against QazLocker ransomware. Victims without Active Protection may try to restore encrypted files via our decryptor script.
Ransom note emails:
· fiileky2023@onionmail.com
· fiileky2023@yahooweb.co
Ransom note filename:
· Readme.txt
Extension:
· <filename>.encrypted.<original_extension>
Mutex:
· “qazwsxedcrfvtgybhnujmiko”
Packer and obfuscation:
· UPX 3.91
· AutoIT 3.3.16.1
Executed commands:
· cmd.exe /c ipconfig /all
· cmd.exe /c schtasks /create /sc onlogon /tn 2953439145 /rl highest /tr C:\PROGRA~2\COMMON~1\CE43E9~2.EXE
· cmd.exe /C title 2676167|vssadmin.exe Delete Shadows /All /Quiet
· cmd.exe /C title 8612145|bcdedit /set {default} recoveryenabled No
· cmd.exe /C title 6039549|bcdedit /set {default} bootstatuspolicy ignoreallfailures
· notepad.exe
Web requests:
· https://blockchain[.]info/tobtc?currency=USD&value=200
· https://blockchain[.]info/tobtc?currency=USD&value=1000
Appendix:
Python decryptor:
from Crypto.Hash import MD5
from Crypto.Cipher import ARC4
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from ctypes import *
from ctypes.wintypes import DWORD, LPVOID , UINT, BOOL, BYTE, LPCSTR
import argparse
import sys, os
import binascii
CryptAcquireContextA = windll.advapi32.CryptAcquireContextA
CryptAcquireContextA.restype = BOOL
CryptCreateHash = windll.advapi32.CryptCreateHash
CryptCreateHash.restype = BOOL
CryptHashData = windll.advapi32.CryptHashData
CryptHashData.restype = BOOL
CryptEncrypt = windll.advapi32.CryptEncrypt
CryptEncrypt.restype = BOOL
CryptDeriveKey = windll.advapi32.CryptDeriveKey
CryptDeriveKey.restype = BOOL
CryptExportKey = windll.advapi32.CryptExportKey
CryptExportKey.restype = BOOL
parser = argparse.ArgumentParser(description="Decryptor")
parser.add_argument("-f", "--file", help="Target file to decrypt", type=str, metavar='FILE')
parser.add_argument("-l", "--lockid", help="The LOCK-ID from the ransom note", type=str, metavar='LOCKID')
parser.add_argument("-m", "--month", help="The month when the encryption happened (1-12)", type=int, metavar='MONTH')
parser.add_argument("-a", "--mac_address", help="The top(first) MAC address in the output from 'ipconfig /all' command", type=str, metavar='MAC')
args = parser.parse_args()
if args.lockid:
if args.month or args.mac_address:
print("ERROR: Either only LOCKID or both MONTH and MAC should be used!")
sys.exit()
if len(args.lockid) != 13:
print("ERROR: invalid LOCK-ID")
sys.exit()
for c in args.lockid.upper():
if c not in "0123456789ABCDEF":
print("ERROR: invalid LOCK-ID")
sys.exit()
lock_id = args.lockid
key_seed = args.lockid[-5:].upper()
else:
if not (args.month and args.mac_address):
print("ERROR: Either only LOCKID or both MONTH and MAC should be used!")
sys.exit()
if len(args.mac_address) != 17:
print("ERROR: invalid MAC address")
sys.exit()
for c in args.mac_address.upper():
if c not in "0123456789ABCDEF-:":
print("ERROR: invalid MAC address")
sys.exit()
if args.month < 1 or args.month > 12:
print("ERROR: invalid month")
sys.exit()
hex_month = hex(args.month)[2]
normalized_mac = args.mac_address.replace(':','').replace('-','')
lock_id = (normalized_mac + hex_month).upper()
key_seed = lock_id[-5:].upper()
RC4_PASSPHRASE = b"Kernel32.dll"
print(f"LOCK-ID: {lock_id}")
print(f"KEY SEED: {key_seed}")
print(f"RC4 PASSPHRASE: {RC4_PASSPHRASE.decode('utf8')}")
passphrase_md5 = MD5.new()
passphrase_md5.update(RC4_PASSPHRASE)
print(f"MD5(RC4_PASSPHRASE): {passphrase_md5.hexdigest()}")
cipherRC4 = ARC4.new(passphrase_md5.digest())
aes_key_seed = cipherRC4.encrypt(key_seed.encode('utf8'))
print(f"AES KEY SEED: {binascii.hexlify(aes_key_seed).decode('utf8')}")
hProv = c_void_p()
dwProvType = 0x0018
dwFlags = 0xF0000000
CryptAcquireContextA(byref(hProv), None, None, dwProvType, dwFlags)
error = GetLastError()
if error:
print("CryptAcquireContextA")
print(error)
print(WinError(error))
hHash = c_void_p()
CALG_MD5 = 0x00008003
CryptCreateHash(hProv, CALG_MD5, 0, 0, byref(hHash))
error = GetLastError()
if error:
print("CryptCreateHash")
print(error)
print(WinError(error))
CryptHashData(hHash, aes_key_seed, 5, 1)
error = GetLastError()
if error:
print("CryptHashData")
print(error)
print(WinError(error))
CALG_AES256 = 0x6610
hKey = c_void_p()
CryptDeriveKey(hProv, CALG_AES256, hHash, 1, byref(hKey))
error = GetLastError()
if error:
print("CryptDeriveKey")
print(error)
print(WinError(error))
PLAINTEXTKEYBLOB = 0x8
ptKey = create_string_buffer(64)
keyLen = DWORD(64)
CryptExportKey(hKey, 0, PLAINTEXTKEYBLOB, 0, byref(ptKey), byref(keyLen))
error = GetLastError()
if error:
print("CryptExportKey")
print(error)
print(WinError(error))
aes_key = ptKey.raw[keyLen.value-32:keyLen.value]
print(f"AES KEY: {binascii.hexlify(aes_key).decode('utf8')}")
if args.file:
if os.path.isfile(args.file):
output_filename = args.file.replace('.encrypted','')
with open(args.file, 'rb') as f_in, open(output_filename, 'wb') as f_out:
data = f_in.read()
IV = b"\x00"*16
print("IV: " + "00"*16)
print("Mode: CBC")
print(f"Decrypting file '{args.file}'..")
cipherAES = AES.new(aes_key, AES.MODE_CBC, iv=IV)
plaintext = cipherAES.decrypt(data)
f_out.write(unpad(plaintext, 16))
print(f"Decrypted successfuly. Output file: '{output_filename}'")
else:
print(f"ERROR: invalid file '{args.file}'")
Ilia Dafchev is a Security Researcher at Acronis, specializing in threat research while his skills also include malware analysis, developing anti-malware signatures and automation tools. Ilia's prior experience involved serving as a security analyst, where he responded to security incidents and performed digital forensic investigations.
Albert Zsigovits is a Senior Security Researcher at Acronis, specializing in threat hunting, memory forensics and signature development. He enjoys the challenge of connecting the dots between cybercrime and criminal rings leveraging threat intelligence and open source intelligence techniques. Albert is also a former conference speaker at AVAR, BSidesBUD, BSidesVienna, DisobeyFi, Hacktivity, SEC-T and VirusBulletin.
Robert Neumann is the Head of the Cyber Protection Operations Center at Acronis. Besides managing teams to counterbalance the fight against cybercriminals, he is focusing on various short- and long-term research projects, ranging from small-scale malicious campaigns through niche malware and file formats to in-depth investigations and threat actor attribution.