Scenario

We’ve been hit by Ransomware again, but this time the threat actor seems to have upped their skillset. Once again a they’ve managed to encrypt a large set of our files. It is our policy NOT to negotiate with criminals. Please recover the files they have encrypted - we have no other option! Unfortunately our CEO is on a no-tech retreat so can’t be reached. Warning This is a warning that this Sherlock includes software that is going to interact with your computer and files. This software has been intentionally included for educational purposes and is NOT intended to be executed or used otherwise. Always handle such files in isolated, controlled, and secure environments. One the Sherlock zip has been unzipped, you will find a DANGER.txt file. Please read this to proceed.

Questions

Questions

  1. What type of encryption has been utilised to encrypt the files provided?
  2. Which market is our CEO planning on expanding into? (Please answer with the wording utilised in the PDF)
  3. Please confirm the name of the bank our CEO would like to takeover?
  4. What is the file name of the key utlised by the attacker?
  5. What is the file hash of the key utilised by the attacker?
  6. What is the BTC wallet address the TA is asking for payment to?
  7. How much is the TA asking for?
  8. What was used to pack the malware?

Evidence

countdown.txt	e2edc252b5776a1e9c63c58b5328ae3a	
expanding-horizons.pdf.24bes	425d610faab2eb49d5aec7f37de59484	
takeover.docx.24bes	452c3328667b7242132bf0821c9d4424	

update	8b2d4bc2f26d76c1a900e53483731013	

Alongside the ransomware I was provided with a ransomnote and two encrypted files (PDF and DOCX)

Analysis

Ransomnote

In shadows we dwell, unseen we act,
To claim what's ours, we've formed a pact.
With files concealed, and secrets locked,
We kindly ask, don't be too shocked.

A million pounds in Bitcoin bright,
Shall bring your data back to light.
To free your files from chains of gold,
Be swift, be brave, don't let them mold.

Send payment to our wallet deep,
BTC Address: 1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2,
To verify and make us weep.

For questions, visit us, don't fail,
Onion Address: xyzf3jv6xq3d7w5e.onion,
Customer service, there to hail.

The clock is ticking, time's a thief,
Pay heed to us, or face the grief.
In cyberspace, the sum we claim,
Address we send, to end this game.

Should you resist, or just ignore,
Your precious data, you'll see no more.
The choice is yours, we leave it here,
Weigh your options, with trembling fear.

For every sunset that slips away,
The price we ask, it will not stay.
So heed our words, and make it quick,
A million pounds, a ransom's trick.

While one might argue about whether this is a poetic masterwork some relevant information about the ransom attack. The attackers want the payment of £1000000 transferred on to the following wallet:

1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2

UPX

Checking out the file with DIE shows that the binary is an ELF binary and that it was packed using UPX. To check this out the “old school way” I look the strings and the hexdump of the binary. In both cases the presence of UPX is clearly visible. Pasted image 20240320180037 Any further analysis requires me to dig deeper into the binary so unpacking it is necessary. The can be done using UPX. The leaves me a “pure” ELF binary.

upx.exe -d -o update.unpacked .\update

update.unpacked    598853075B41491C7EFD1FD296828489

Pasted image 20240306211226

BinaryNinja

Luckily the symbols were left in tact and as such the functions of the program are easily identified and references to CURL are also immediately visible.

Diving into the main function two things at the very beginning look promising:

  • get_key_from_url Could be used to retrieve the encryption key for the ransomware
  • handle_directory possible function, which contains the functions for file encryption
  • the iterators of the loop in the else condition were converted to signed decimal based on their value they might be related to a key and iv
  • xor_cipher don’t know the purpose yet, but encrypted data could be valuable

get_key_from_url

Pasted image 20240320182530

If the rax is not 0, the curl initialization was successful, the code will decrypt some piece of data into var_98, which will be later used by the curl_easy_setopt. To understand the CURL functions and what the output of xor_cipher I take a look at the CURL documentation. This now leaves a definition of what CURLoption value corresponds to the actual CURL flag. For this I did not find real documentation, but some source code on Github and a forum.

CURLcode [curl_easy_setopt](https://curl.se/libcurl/c/curl_easy_setopt.html)(CURL *handle, CURLoption option, parameter);


CURLOPT_URL := 0x2712
CURLOPT_WRITEFUNCTION := 0x4E2B
CURLOPT_WRITEDATA := 0x2711

$CURLOPTTYPE_LONG                   = 0
$CURLOPT_FOLLOWLOCATION 		= $CURLOPTTYPE_LONG +52

BinaryNinja Weirdness

When looking at the code in Ghidra the fourth parameter does not exist and it is also not defined in the documentation. BinaryNinja hallucinates this parameter.

Pasted image 20240316115006

The CURL process will get the data from the XOR decrypted URL and the output is handled by a passed custom function. The URL will most likely contains at least one redirection, since the CURL_FOLLOWLOCATION flag is set to 1

xor_cipher

Pasted image 20240320183525

The arguments of his function are the following:

  1. the input data that based on cross-reference is located at the address of KX in memory
  2. output data
  3. the XOR key this was based on the XOR operation within the loop and the fact that it stayed constant across all calls of xor_cipher

Using the XOR key and going to the .rodata section, where the encrypted text is stored and using the transform function of BinaryNinja to decrypt it.

BinaryNinja Weirdness

The data at this address is automatically displayed as a char const K1[0x5] = "\nCLIG". This confused me at first, because it only decrypted to https.

K1 = https://rb[.]gy/3flsy

K2 = https://rb[.]gy/ehec6
K3 = https://rb[.]gy/aw3t1
K4 = https://rb[.]gy/fziug
K5 = https://rb[.]gy/irzmu

Doing some further research into the URL stored inK1 shows that it downloads a file updater after being redirected to a Dropbox instance.

https://www.dropbox.com/s/2hqgpmtc2mdwij4/updater?dl=1

Pasted image 20240320185923

The file is 48 bytes large, which matched the key size of 32 bytes and the IV size of 16 bytes. And based on the function name this file is highly likely to be the encryption key.

updater    950EFB05238D9893366A816E6609500F

encrypt_file

Pasted image 20240316111721

I found the key and iv already from the get_key_from_url function but to decrypt the files I still have to find out the encryption method. During the initialization of the cipher it it clearly stated that the usual AES-256-CBC cipher is used.

Decryptor

With the help of ChatGPT and my previous decryptor for Lockpick1 I create the following decryptor script.

from Crypto.Cipher import AES
import sys
 
def decrypt_file(key_file, input_file, output_file):
    with open(key_file, 'rb') as f:
        key_data = f.read()
        key = key_data[0:32]
        iv = key_data[32:]
 
    with open(input_file, 'rb') as f_in, open(output_file, 'wb') as f_out:
        cipher = AES.new(key, AES.MODE_CBC, iv)
        decrypted_data = cipher.decrypt(f_in.read())
        f_out.write(decrypted_data.rstrip(b'\0'))
 
key_file = sys.argv[1]
input_file = sys.argv[2]
output_file = sys.argv[3]
 
decrypt_file(key_file, input_file, output_file)
print(f"[+] {input_file} decrypted successfully!")

Recovery

The PDF talks about the expansion of the company into the Australian markets.

The CEO is interested in buying the Notionwide Bank.

Answers