A new kind of ransomware written in Python has upped the encryption game by using a unique key for every file it encrypts on a victim’s machine, researchers have warned.
The ransomware, dubbed CryPy, is not the only kind of malware which has been written in the Python programming language — joining the likes of HolyCrypt, Fs0ciety Locker, and Zimbra.
However, what makes this particular malware stand out is a rather sophisticated and nefarious practice — the fetching of unique encryption keys to individually encrypt files on a victim’s system — making decryption and cracking very difficult.
CryPy was discovered due to a security flaw in the Magento content management system (CMS) which permitted attackers to upload and execute a PHP shell script to a vulnerable Israeli web server which now acts as the malware’s command and control (C&C) center.
Data is transferred from the server in clear text, which allows man-in-the-middle (MiTM) attacks to take place — and drops of additional PHP scripts which call up the ransomware to attack victim PCs.
The C&C center is also used to conduct phishing attacks and contained PayPal phishing pages. It is believed that the threat actors behind the ransomware are Hebrew-speaking.
In an analysis posted by Kaspersky researchers, the team says the malware comprises of two main files, boot_common.py and encryptor.py. The first error logs on Windows platforms, while the latter is the actual locker. Once a system is infected, CryPy disables Registry Tools, Task Manager, CMD, and Run before disabling recovery tools and the boot status policy
Encryption then begins, with a fresh encryption key fetched for each file individually. However, Kaspersky believes CryPy is in the early stages of development as the malware is, in its current form, failing to encrypt files as the threat actor has recently moved to a new server and the malware has not been updated as of yet.
When a system is locked and encrypted, victims are then asked to contact the threat actor via email to pay for a decryption program. By undergoing this process, victims may be able to decrypt a few files for free, showing the malware’s functions and potentially an element of trust — in other words, a lure to push victims into paying for the full decryption system.
Earlier this week, Symantec researchers revealed that ransomware operators are switching tactics to expand their attack area by using Windows Script Files (WSF) to distribute ransomware as they are less likely to be picked up by antivirus programs.
This Python executable comprises of two main files. One is called boot_common.py and the other encryptor.py. The first is responsible for error-logging on Windows platforms, while the second, the encryptor, is the actual locker. Within the encryptor are a number of functions including two calls to the C&C server.
The C&C is hidden behind a compromised web server located in Israel. The Israeli server was compromised using a known vulnerability in a content management system called Magento, which allowed the threat actors to upload a PHP shell script as well as additional files that assist them in streaming data from the ransomware to the C&C and back.
A notable point to mention is that the server was also used for phishing attacks, and contained Paypal phishing pages. There are strong indications that a Hebrew-speaking threat actor was behind these phishing attacks. The stolen Paypal credentials were forwarded to another remote server located in Mexico and which contained the same arbitrary file upload technique, only with a different content management.
It is a known practice for attackers to look for low-hanging fruit into which they can inject their code in order to hide their C&C server. One such example was the CTB-Locker for web servers reported last March.
Size: 5.22 MB
To reverse the executable one should first conduct a number of checks using a convenient debugger. The universal steps for unpacking an unknown packer start with trying to set a memory breakpoint on popular functions that packers use, such as VirtualAlloc.
If the breakpoint hits, the next step involves switching to user mode and setting a hardware breakpoint (on access). That will assist in inspecting where exactly the program initializes the memory block. In most cases, an executable magic header (MZ) should appear in the memory block. However, in this case the following screenshot (Figure 1) shows the readable data that was allocated to that memory block:
After the data was allocated to the memory block, it appeared to be using VM code (python vm) to execute the code. For those who are not familiar with the term, VM code is the process of creating new instruction sets based on the author’s request. The CPU uses those instruction sets to understand the instructions.
py2exe simply converts the code to x86 assembly, the architecture used on the CPU for communication, and, by loading a python DLLs, loads all the modules into the memory.
We found that the executable file was generated using py2exe. The first indicator was a stack PUSH instruction to add the string – PY2EXE_VERBOSE: a module that compiles Python scripts to Microsoft Windows executables.
A module that reverse the operation of the py2exe can be found in Github and is called unpy2exe. This module will revert the executable back to its origin Python compiled code (i.e. .pyc file). From that format, another step will be required to fully revert to the original code. We randomly chose to use EasyPythonDecompiler.
In its current state, the executable fails to encrypt the file system, simply because the threat actors must have migrated from the current server to another. By doing so, they deleted the remaining traces of the PHP files they used for data collection from a victim’s machine. The following is the log file that is generated upon exception:
The scripts in Python use two files:
This file throws an “error” to show that the program failed to execute if there is a problem.
This script encrypts the victim’s files.
The ransomware disables the following features from the compromised machine by overwriting the registry policies it disables Registry Tools, Task Manager, CMD and Run.
It then continues with changing bcdedit to disable recovery and ignore boot status policy.
Upon successful encryption, the ransomware will encrypt the following file extensions:
*.mid, *.wma, *.flv, *.mkv, *.mov, *.avi, *.asf, *.mpeg, *.vob, *.mpg, *.wmv, *.fla, *.swf, *.wav, *.qcow2, *.vdi, *.vmdk, *.vmx, *.gpg, *.aes, *.ARC, *.PAQ, *.tar.bz2, *.tbk, *.bak, *.tar, *.tgz, *.rar, *.zip, *.djv, *.djvu, *.svg, *.bmp, *.png, *.gif, *.raw, *.cgm, *.jpeg, *.jpg, *.tif, *.tiff, *.NEF, *.psd, *.cmd, *.class, *.jar, *.java, *.asp, *.brd, *.sch, *.dch, *.dip, *.vbs, *.asm, *.pas, *.cpp, *.php, *.ldf, *.mdf, *.ibd, *.MYI, *.MYD, *.frm, *.odb, *.dbf, *.mdb, *.sql, *.SQLITEDB, *.SQLITE3, *.asc, *.lay6, *.lay, *.ms11 (Security copy), *.sldm, *.sldx, *.ppsm, *.ppsx, *.ppam, *.docb, *.mml, *.sxm, *.otg, *.odg, *.uop, *.potx, *.potm, *.pptx, *.pptm, *.std, *.sxd, *.pot, *.pps, *.sti, *.sxi, *.otp, *.odp, *.wks, *.xltx, *.xltm, *.xlsx, *.xlsm, *.xlsb, *.slk, *.xlw, *.xlt, *.xlm, *.xlc, *.dif, *.stc, *.sxc, *.ots, *.ods, *.hwp, *.dotm, *.dotx, *.docm, *.docx, *.DOT, *.max, *.xml, *.txt, *.CSV, *.uot, *.RTF, *.pdf, *.XLS, *.PPT, *.stw, *.sxw, *.ott, *.odt, *.DOC, *.pem, *.csr, *.crt, *.key and wallet.dat to encrypt crypto currency wallets
The files are encrypted using AES with CBC mode for the following paths:
*userhome – The current user home directory
When the encryption step is done, the ransomware will remove the restore points and write the README_FOR_DECRYPT.txt file and execute it. The following screenshot is the ransom note:
The threat actor behind the attack asks the victim to contact it via email, and to send a request to the following two email addresses to receive the decryption program:
Note that the ransom note contains mistakes, implying that it has been written by a non-English speaker. First, the headline is missing a ‘T’ in “IMPORTAN INFORMATION”. Second, the sentence “Decrypting of your files…” is syntactically wrong. Native speakers will be able to find additional mistakes.
The threat actor claims that files will be deleted every 6 hours, which reflects the approach of more advanced ransomwares. However, it forgets to mention proof of decryption or a channel that can be used in cases where the payment process is not responsive. This points to the executable being at an early stage of development.
The ransomware survives a reboot by adding the following keys to the registry:
The code for adding the values to the registry is located on the functions autorun() and autorun2().
Right before launching the ransom note, the script calls a delete_shadow() function that takes no arguments, and simply executes the following command line code to remove all shadow copies and prevent recovery from backup:
os.system(“vssadmin Delete shadows /all /Quiet”)
Lastly, the file calls autorun2() fuction that copies the ransomware from its current location to C:\\Users\\\\AppData\\Local with hardcoded name:
The ransomware hides behind an Israeli web server which was compromised using Shell script arbitrary upload written in PHP. The compromise and upload were possible because the server carried a vulnerable Magento CMS.
The executable transfers data over an unencrypted HTTP channel in clear-text. This allows for easy traffic inspection using a network listener. The following screenshot (Figure 9) is the traffic being sent to the server.
Inspecting the Magento exploit and the compromised server, we found that the origin of the upload carries the title Pak Haxor – Auto Xploiter and the email [email protected][.]com and that the file was uploaded in August 2016, which aligns with the case in subject.
The following screenshot (figure 10) reveals how attackers are using massive exploiters that scan for vulnerable web servers and exploit the vulnerability, which they later visit to expand their control over the server.
Part of such an exploitation technique is dropping additional PHP scripts to refine a more sophisticated attack, such as the CryPy ransomware.
A call to one of those scripts script can be found hard-coded in the CryPy Python code, in the form of a GET request. The request is sent with two parameters to a script that was uploaded using the Auto Xploiter and carries the name victim.php. By reviewing the Python code it is easier to understand the type of data being presented in Base64 encoding format.
As seen in the screenshot (figure 11), the configurl parameter accepts a URL querystring where the victim_infoinput value of the info parameter is derived from the platform module.
uname() is used when one wants to return a tuple of system, node, release, version, machine and processor values. These are encoded with Base64.
The next parameter is ip which contains the socket.gethostname() which basically collects an IP address.
The querystring is then sent to urllib.urlopen(), which will send a GET request to the selected server and read the reponse content into glob_config.
The response contains a JSON format payload which is checked for the following keys:
x_ID – the victim’s unique ID to request their decryption keys after payment.
x_UDP – Not used; perhaps saved for future use.
x_PDP – Not used; perhaps saved for future use.
The second call is implemented in a function called generate_file() which is responsible for fetching a unique key for each file before encryption.
We have seen in recent lockers that, in order to demonstrate trust and integrity, the victim is able to decrypt one/two files before processing the payment. This proves decryptor validity. In order to randomly choose a file, the attacker must first generate a unique token for each one. The second PHP script found in the code is savekey.php which is described in the following screenshot (figure 12) and is suspected to have the C2 IP in it. It was however deleted long before we were able to reach it.
As for the first call, the second sends two parameters. The first is the file’s name and the other is the victim ID. In return, the server responds with two keys:
X – Unique key after encryption which will be appended to the file’s header.
Y – New filename which will be stored instead of the previous one.
These parameters are then sent to an encryption routine, along with the file’s original name.