top of page

PLAY Ransomware: A deep Analysis 🧐

Updated: Dec 16, 2022

CyberMorans, đŸ’Ș

Argentina's Judiciary of CĂłrdoba shut down its IT systems after suffering a ransomware attack, reportedly at the hands of the new 'Play' ransomware operation đŸ˜Č Here I will analyse the attack as well as a sample of the Play Ransomware itself...👊


The 😈 attack occurred Saturday, August 13th, causing the Judiciary to shut down IT systems and their online portal. The outage is also forcing the use of pen and paper for submitting official documents đŸ˜”

Now I raced to the site to confirm this myself and.....

Justicia CĂłrdoba's website is suffering an outage


PLAY Ransomware (aka PlayCrypt) campaigns have been active since at least mid-July 2022. Up to five ransom notes of PLAY Ransomware have been uploaded to VirusTotal so far. In mid-August 2022, the first public case of PLAY Ransomware was announced when a journalist uncovered that Argentina’s Judiciary of CĂłrdoba was victimized đŸ˜Č


The operators đŸ€“ have been known to use common big game hunting (BGH) tactics, such as SystemBC RAT for persistence and Cobalt Strike for post-compromise tactics. They have also been known to use custom PowerShell scripts and AdFind for enumeration, WinPEAS for privilege escalation, and RDP or SMB for lateral movement while inside a target network.


The group appends “.play” to encrypted files and its ransom note only includes the word “PLAY” and an email address to communicate with the threat actors. 😹 The threat actors have been known to exfiltrate files using WinSCP but are not known to have a Tor data leak site like many other BGH ransomware campaigns đŸ„±

It is unknown how Play breached the Judiciary's network, but a list of employee email addresses was leaked as part of the Lapsus$ breach of Globant in March, which may have allowed threat actors to conduct a phishing attack to steal credentials.

The leaks were captioned #collateraldamage đŸ˜©

I retrieved a sample of the malware and reverse engineered it to the best of my capabilities. I may have missed a few things but again.....to the best of my abilities.

 

PLAY Malware Overview

This is my analysis for PLAY Ransomware. I’ll be focusing on its anti-analysis and encryption features to the best of my depth. There are a few other features such as DLL injection and networking that will not be covered in this analysis.

Despite its simplicity, PLAY is heavily obfuscated with a lot of unique tricks that have not been used by any ransomware that comes before.


The malware uses the generic RSA-AES hybrid-cryptosystem to encrypt files. PLAY’s execution speed is pretty average since it uses a depth-first traversal algorithm to iterate through the file system. Despite launching a separate thread to encrypt each file, this recursive traversal hinders its performance significantly.


IOCS

The analyzed sample is a 32-bit Windows executable.

MD5: 223eff1610b432a1f1aa06c60bd7b9a6

SHA256: 006ae41910887f0811a3ba2868ef9576bbd265216554850112319af878f06e55


VirusTotal Result.

Ransom Note

The content of the default ransom note is stored as an encoded string in PLAY’s executable, which contains the string “PLAY” as well as an email address for the victim to contact the threat actor.

PLAY’s ransom note filename is “ReadMe.txt”.


 

PLAY Malware Analysis👇


Anti-Analysis: Return-Oriented Programming đŸč

Upon opening the executable in IDA, we can see that most of the assembly code does not make sense and is not too meaningful. An example can be seen from WinMain, where there is no clear return statement with garbage bytes popping up among valid code.


Anti-decompiling Feature in WinMain.


As shown in the disassembled code above, the control flow in WinMain calls sub_4142F5, and upon return, edi is popped and we run into the garbage bytes at 0x4142F2. As a result, IDA fails to decompile this code properly.


Examining sub_4142F5, we see that the value stored at the stack pointer is immediately added by 0x35 before a retn instruction is executed.


We know that the call instruction basically contains two atomic instructions, one pushing the address of the next instruction (after the call instruction) onto the stack and one jumping to the subroutine being called. When the code enter sub_4142F5, the return address (in this case, it is 0x4142F1) is stored at the stack pointer on top of the stack. The subroutine adds 0x35 to this, changing the return address to 0x414326, and retn to jump to it.

Knowing this, we can scroll down and try to disassembly the bytes at 0x414326 to get the next part of the WinMain code.

Disassembled Hidden Code.


Using this return-oriented programming approach to divert the regular control flow of the program, PLAY is able to bypass most static analysis through IDA’s disassembly and decompilation.

We can also quickly see that at 0x41433A, there is another call instruction followed by some garbage bytes. This means that the obfuscation occurs multiple times in the code.

My approached to this was to programmatically patch all these call instructions up. A simple patch used in my analysis is calculating the jump (the value added to the return address) and replacing the call instruction with a jump instruction to the target address.

To scan for all of this obfuscated code, I use 3 different (but quite similar) regexes(is this a word?) in IDAPython to find.


A little underwhelming, but now we have successfully deobfuscated the code, get a meaningful call instruction to sub_415110 and a proper returning statement in the decompiled code!


Anti-Analysis: Garbage Code đŸč

Beside control flow obfuscation, PLAY also litters its code with random moving instructions that don’t contribute to the main functionality of the program.


Garbage Code.



This makes the decompiled code looks a lot messier, and it is not simple to patch all of these ups since valid code is usually stuffed in between of these garbage code. Patching by jumping over them would sometime break the program itself.

The only solution I have for this is to mentally ignore them while analyzing.


Anti-Analysis: API Hashing đŸč

Similar to most modern ransomware, PLAY obfuscates its API call through API name hashing. The API resolving function takes in a target hash and a DLL address.

It walks the DLL’s export table to get the name of the exports. For each API name, the malware calls sub_40F580 with the name as the parameter and adds 0x4E986790 to the result to form the final hash. This hash is compared with the target hash, and if they match, the address of the API is returned.

API Hashing.

As shown below, the hashing function contains a lot of unique constants, which allows us to quickly look up that it is xxHash32. With this, we know that the full hashing algorithm is xxHash32 with the seed of 1 and the result added to 0x4E986790.


Anti-Analysis: String Encryption đŸč

Most important strings in PLAY are encoded in memory. The decoding algorithm does not seem to be too clear, so I just dynamic-ed my way through these. School is whooping my ass right now, so I try to avoid analyzing stuff whenever I can.


PLAY’s String Decryption.

 

Static Code Analysis👇


Command-Line Arguments đŸč

PLAY can run with or without command-line arguments.


Below is the list of arguments that can be supplied by the operator;

ArgumentDescription

-mc: Execute normal functionality. Same as no command-line argument

-d <drive path>: Encrypt a specific drive

-ip <shared resource path> <username> <password>:Encrypt network shared resource

-d <path>: Encrypt a specific folder/file


Checking Command-Line Arguments.


Crypto Initialization đŸč

Prior to encryption, PLAY initializes and retrieves cryptographic algorithm providers.

First, it calls BCryptOpenAlgorithmProvider to load and initialize a CNG provider for random number generation and BCryptImportKeyPair to import its hard-coded RSA public key.


Initializing & Importing Cryptographic Key.

Next, the malware calls VirtualAlloc to allocate a buffer to store 128 file structures used for encrypting files.


Then, the malware sets the RNG and AES provider handles as well as the RSA public key handle to the structure to be used to generate random AES key and IV to encrypt files.


Checking Existing Drives đŸč

Before iterating through all drives to encrypt, PLAY enumerates all volumes on the victim’s system by calling FindFirstVolumeW and FindNextVolumeW. If the volume is not a CD-ROM drive or a RAM disk, the malware calls GetVolumePathNamesForVolumeNameW to retrieve a list of drive letters and mounted folder paths for the specified volume.


If this list is empty, which means the volume is not mounted to any folder, PLAY calls GetDiskFreeSpaceExW to check if the volume’s free space is greater than 0x40000000 bytes. If it is, the malware calls SetVolumeMountPointW to try mounting the volume to a drive path.


File Encryption đŸč

To encrypt a file from scratch, PLAY first generates an AES key to encrypt the file with.

It calls BCryptGenRandom to generate a random 0x20-byte buffer. Depending on the chaining mode specified in the file structure, the malware calls BCryptSetProperty to set the chaining properly for its AES provider handle.


Generating AES Key Handle.

Next, BCryptGenerateSymmetricKey is called on the randomly generated 0x20-byte buffer to generate the AES key handle.


Then, to store the AES key in the file footer struct, PLAY calls BCryptExportKey to export the AES key into a 0x230-byte key blob, calls BCryptGenRandom to randomly generate a 0x10-byte IV and appends it.


Then, it calls BCryptEncrypt to encrypt the exported key blob and the IV using the RSA public key handle and writes the encrypted output to into a 0x400-byte buffer. PLAY then populates the file footer’s other fields such as footer_marker_head, footer_marker_tail, small_file_flag, and large_file_flag with existing information from the file structure. Once the file footer is fully populated, the malware calls SetFilePointerEx to move the file pointer to the end of the file and calls WriteFile to write the structure there. If the file size is greater than 0x500000 bytes, PLAY only encrypts the first and last chunk in the file. The encrypting function consists of a ReadFile call to read the chunk data in the buffer in the file structure, a BCryptEncrypt call to encrypt the file using the AES key handle and the generated IV. After encryption is finished, the malware calls WriteFile to write the encrypted output to the file as well as the index of the chunk being encrypted in the file footer. This is potentially used to keep track of how many chunks have been encrypted in the case where corruption or interruption occurs. Finally, after the file is encrypted, the malware changes its extension to .PLAY by calling MoveFileW.

Sourced: Chaungdou

 

Conclusion

Subscribe to receive notifications of similar posts 😋 where we will be reverse engineering malware and the technical aspect of vulnerabilities as well as how an attacker may use this vulnerability as an attack vector and other Infosec stuff...😋


Morans,


Thank you for your time, Like and leave a comment/review and as always, stay awesome! 😋👊 đŸ’Ș



385 views4 comments

Recent Posts

See All
Post: Blog2_Post
bottom of page