Gå direkte til content

Decrypting Jett Ransomware: When hackers make coding mistakes

4 min read

Skrevet d. 14-May-2025 13:45:00 af

Talk to any reverse engineer and they will talk about the “good old days” when threat actors would commonly “roll their own crypto” – that is, write their own custom encryption functions, and these were for the most part littered with so many mistakes that breaking them was routinely a breeze. Enter the modern-day era with built-in strong cryptographic primitives (a.k.a. encryption building blocks) easily available in every conceivable programming language, and there is no longer any excuse not to use them. Yet, encryption pitfalls still exist and occasionally threat actors make mistakes.

In this technical blog, we will discuss how we were able to break the encryption used by Jett ransomware due to a threat actor’s poor understanding of the strengths and weaknesses of modern crypto algorithms and how they selected the wrong algorithm for the job.

The ransomware file we will be exploring in this blog was found by the CSIRT in the Microsoft Defender quarantine folder on one of our cases.  

Filename Ransomware.exe_
SHA256 2412333E78F9821203F739523E68C275EA32E10749ACEA382F224AC5E4F277D3
Type PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows

 

Running the ransomware in our lab 

To get a feel for the ransomware, we first executed it in our sandbox and carefully looked on as the files on the virtual lab machine were encrypted before the Ransomware wrote the classic ReadMe.txt (a.k.a.  ransom note) to disk. Interestingly, the ransom note explicitly claims that Jett ransomware uses the modern crypto standards AES-256 and RSA-2048. 

Billede15

When we executed the Ransomware in our sandbox, we also noticed a major mistake made by the ransomware developers. When the ransomware is executed, the keys needed to decrypt the files are written to disk. One could surmise that the decision to write to disk was to allow the threat actor to easily exfiltrate the keys and then delete these files. However, this is an amateur mistake because as everyone within the forensics industry knows, anything written to disk can potentially be recovered from unallocated space.   

Billede16

 

Analysis of file encryption used by Jett Ransomware 

We utilized the open-source .NET decompiler ‘dnSpy’: https://github.com/dnSpy/dnSpy to analyze how the ransomware functions internally. Looking at the decompiled source code we can now see that the developers chose to use the ISAAC stream cipher1 to encrypt files rather than AES256 (as claimed in the ransomware note). 

Billede17

According to Wikipedia, ISAAC is a secure algorithm and has a complexity of 4.67*10^1240 which is nerd for: “forget about brute forcing it”. However, what the Wikipedia article fails to mention is that this class of algorithms may be vulnerable if the same key is used to encrypt multiple files. Let us explore the ransomware further to see if the developers of Jett Ransomware were aware of this fact.  

Looking more closely at the CryptFile function call, we see that a new instance of the ISAAC is created for every file. This makes sense since decryption would otherwise be dependent on the order in which files were encrypted. Normally this would be a secure approach  – if only the developers were careful not to reuse the same encryption key across files. Alas, it can be observed that the encryption key is retrieved from a global variable named password. Further analysis reveals that this variable is set only once at the beginning of the program. So, at this point, our cryptography spidey-senses start tingling, perhaps, we can attack the implementation. 

Billede18

Let’s explore how the encryption is implemented more closely.  First, note that the state and context of the encryption is not affected by what is being encrypted. Since the encryption key is always the same, this means that the exact same key stream is being generated for every file. We also noted that the actual encryption operation (marked in red in the picture below) is a simple XOR operation.  

Billede19

 

Cracking the crypto with a bit of math 

We talked about the fact that reusing keys multiple times in ISAAC is a weakness. Let’s now be more precise: Encrypting multiple files with the same XOR key stream is an absolute “no-no.” It’s clearly a mistake. In fact, one might say it’s so bad that it’s “criminal”- pun intended. This is because, if we have both an unencrypted file as well as an encrypted version of that same file, then we can XOR these together to get the raw keystream which can now also be used to decrypt other files.  

c ⊕ p= (p ⊕ k) ⊕ p = (p ⊕ p) ⊕ k = k

But hey, you might say, how will we get an unencrypted version of a file from a system if everything has been encrypted? Well, it just so happens that ransomware will encrypt not just personal documents, but also files such as stock images and wallpapers naturally found on any system. As they are generic and often exist elsewhere on the internet, it is often possible to retrieve these files in their natural unencrypted format. 

Implementing a script to decrypt files 

Let’s now put theory into practice: Let’s say we want to decrypt an important document. We obviously don’t have an unencrypted version of this important document, but we did find another document on the encrypted system that was previously emailed, so we were able to retrieve the original document from the Microsoft cloud in its unencrypted state.  

With this pair of files (both the unencrypted file and the encrypted version of that file) serving as our key, decrypting the important document is now just a matter of running a couple of lines of code, and Voila! We have now decrypted the important document.  

Billede21

 

Note that there is a limitation to this approach, as we can only decrypt as many bytes as what are contained in the file pair used as the key. So, it is an advantage if the pair consists of large files when possible.  

Bonus: Alternative decryption method 

If for some reason you can’t find a pair of unencrypted and encrypted files to suffice as a key, there is an alternative method that does not have this requirement. In this alternate attack, two different encrypted files (c1, c2) from the same encrypted system are XOR’ed with each other. This eliminates the key stream shown in the formula below: 

c1 ⊕ c2 = (p1 ⊕ k) ⊕ (p2 ⊕ k) =(k ⊕ k) ⊕ (p1 ⊕ p2) = p1 ⊕ p2

The result leaves us with a new, easier (albeit annoying) problem of separating the XOR’ed files (p1 and p2) from each other. Once separated, the decrypted files can be used to create a decryption key that works for all files as in the first approach. 

Conclusion 

A word of caution: Now that you know it is possible to decrypt ransomware, it’s important to remain skeptical. When hit by a ransomware incident, it can be tempting to hope that just maybe there are encryption flaws similar to those explored in this blog. But with the rise of ransomware as a service (RaaS), the quality of the encryption methods used in ransomware has risen with it. Unfortunately, these types of flaws are now rare. In fact, the last time the itm8 CSIRT cracked ransomware for an active case was back in 2022. Nevertheless, sometimes you get lucky, and a crypto analysis may be worth a shot – it may just work.

Note that this blogpost is a companion piece, for the digital forensic part of the story refer to blogpost: “Who hacked us – A forensic story of attribution”.  

Shall we have a chat?

Fill out the form, and we'll get in touch with you.