> For the complete documentation index, see [llms.txt](https://thamizhiniyancs.gitbook.io/writeups/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://thamizhiniyancs.gitbook.io/writeups/hackthebox/sherlocks/malware-analysis/easy/lockpick.md).

# Lockpick

Lockpick HackTheBox Malware Analysis Sherlocks Writeup by Thamizhiniyan C S

## Sherlock Scenario

Forela needs your help! A whole portion of our UNIX servers have been hit with what we think is ransomware. We are refusing to pay the attackers and need you to find a way to recover the files provided. 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. Once the Sherlock zip has been unzipped, you will find a DANGER.txt file. Please read this to proceed.

{% embed url="<https://app.hackthebox.com/sherlocks/Lockpick>" %}

***

## Setting up the Environment

First download the given file and extract it. The password for the given zip file is `hacktheblue`.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2F0B8T0RfUnINHlGilxQbh%2Fimage.png?alt=media&amp;token=7e7647dc-d047-4435-8e9c-404ea4d45569" alt=""><figcaption></figcaption></figure>

The given zip file has another zip file and a `DANGER.txt` file as shown in the following image.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FV7FnrYT3ohRu52GxGEm4%2Fimage.png?alt=media&amp;token=f4ae3078-42f6-436c-bdc8-ffd303427f7d" alt=""><figcaption></figcaption></figure>

The `DANGER.txt` file contains the password for the `bescrypt.zip` file.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2Fj5D60mSOXQmVyIhWNqjm%2Fimage.png?alt=media&amp;token=0001a9de-2209-4660-94a7-6d59f75eafec" alt=""><figcaption></figcaption></figure>

The password for `bescrypt.zip` file is `E@iwyzXK7HK&`.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FW2rXPRkevrPa1uUiK1fl%2Fimage.png?alt=media&amp;token=07f62e15-328d-44cb-9cf2-d9097ded9cb1" alt=""><figcaption></figcaption></figure>

***

## Task 1

### Question

Please confirm the encryption key string utilised for the encryption of the files provided?

### Solution

First lets check the file type using the `file` command.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FZJl0Vctlz82vXXLAvQyN%2Fimage.png?alt=media&amp;token=7541e441-76c7-4169-b80a-7db9d25b193f" alt=""><figcaption></figcaption></figure>

The given file is a ELF `64-bit` executable. Next open the `bescrypt3.2` binary file in Ghidra to view the disassembled code. You can use a disassembler of your choice.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FhTm6gQkNtlf6aLDbGjun%2Fimage.png?alt=media&amp;token=a9a4224e-4be2-471f-8037-a152d585598d" alt=""><figcaption></figcaption></figure>

As show in the above image, the `main` function calls another function `process_directory` with folder name and encryption key as the arguments.

**Answer:** `bhUlIshutrea98liOp`

***

## Task 2

### Question

We have recently recieved an email from <wbevansn1@cocolog-nifty.com> demanding to know the first and last name we have him registered as. They believe they made a mistake in the application process. Please confirm the first and last name of this applicant.

### Solution

Next if we take a look at the decompiled version of the `process_directory` function, it checks whether the directory name that is passed as the argument is valid and if it is a valid directory it looks out for files with one of the following extensions: `.txt, .sql, .pdf, .docx, .xlsx, .csv, .json, .xml`.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FrjBpyzGOGPf7dyeAVz10%2Fimage.png?alt=media&amp;token=c17b597e-1b31-4ff8-a8a1-fc41b756e89f" alt=""><figcaption></figcaption></figure>

If any files with the extension from the above list is found, it calls another function `encrypt_file` with the encryption key and file name as the argument.

Next let's take a look at the `encrypt_file` function.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FG6i5a7xLFyjDk2l1ENfZ%2Fimage.png?alt=media&amp;token=cc8c049b-285a-40f4-8ab5-6d1aa0e620c2" alt=""><figcaption></figcaption></figure>

I have modified a few variable names from the above image for easy understanding. If you want you can also modify the variable names by selecting anyone of the instance of the variable name and clicking the `L` key ( just `L` ) to open the dialog box. If you change the variable name at anyone of the instance Ghidra will automatically modify all the instances.

Here is the list of variables that I have changed:

```
local_28 -> file
param_1 -> filename
param_2 -> key
ftell -> current_value_file_pos
local_38 -> allocated_memory
local_20 -> i
sVar4 -> key_len
uVar2 -> i_
bVar1 -> byte
```

The `encrypt_file` function, reads the file as bytes that is given in the parameter and performs `XOR` operation on each byte with on of the characters from the encryption key and writes the encrypted output to a file with filename as `<original_filename_with_extension>.24bes`.

```
# XOR Operation that is performed on each byte of the file
byte XOR key[ i % key_length ]

# Here, 'i' is a counter that is incremented by 1, It has the initial value as 0
```

You can see the `XOR` operation in the following image.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FlpMMoif6YAWdvAZKQfXF%2Fimage.png?alt=media&amp;token=c1072c49-d4ff-49d3-a3d4-5bfe3157af51" alt=""><figcaption></figcaption></figure>

Thus, the given binary encrypts all the files with a basic `XOR` encryption algorithm.

I have written a python script that loops through all the encrypted files in the given directory and decrypts them and stores the decrypted file in a separate directory.

{% tabs %}
{% tab title="Python" %}

```python
import os
from re import match
import time


def main():
    target_directory = "forela-criticaldata"
    output_directory = f"decrypted_{target_directory}"
    key = "bhUlIshutrea98liOp"
    key_len = len(key)

    if not os.path.isdir(target_directory):
        print("[-] The Given Target Directory is Not Present!")
        exit()
    else:
        print(f"[+] Given Target Directory: {target_directory}")

        if not os.path.isdir(output_directory):
            print("[-] The Given Output Directory is Not Present!")
            print("[+] Creating the Output Directory.")
            os.mkdir(output_directory)

        print(f"[+] Given Output Directory: {output_directory}")
        print("[+] Searching for Encrypted files [ Files with *.24bes extensions ]")

        for root, _, files in os.walk(target_directory):
            for file in files:
                # Checking whether the file is a encrypted file by looking out for *.24bes extension
                if match(r"^.+\.24bes$", file):
                    print(f"[+] Found Encrypted File: {file}")
                    print(f"[+] Reading the Encrypted File: {file}")

                    with open(os.path.join(root, file), 'rb') as encrypted_file:
                        encrypted_bytes = encrypted_file.read()

                    decrypted_bytes = bytearray()

                    print(f"[+] Decrypting the Encrypted File: {file}")
                    for i, byte in enumerate(encrypted_bytes):
                        decrypted_bytes.append(byte ^ ord(key[i % key_len]))

                    decrypted_file_name = f"{output_directory}/{file[:-6]}"

                    print(f"[+] Writing the Decrypted data to {decrypted_file_name}")
                    with open(decrypted_file_name, 'wb') as decrypted_file:
                        decrypted_file.write(decrypted_bytes)
                    
                    print(f"[+] Successfully Written the Decrypted data to {decrypted_file_name}")


if __name__ == "__main__":
    start_time = time.perf_counter()
    main()
    end_time = time.perf_counter()
    print(f"[+] Total Time Taken: {end_time - start_time} seconds")
```

{% endtab %}

{% tab title="Rust" %}

```rust
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::Path;
use regex::Regex;
use std::time::Instant;

fn main() {
    let start_time = Instant::now();

    let target_directory = "forela-criticaldata";
    let output_directory = format!("decrypted_{}", target_directory);
    let key = "bhUlIshutrea98liOp";
    let key_len = key.len();

    // Check if target directory exists
    if !Path::new(target_directory).is_dir() {
        eprintln!("[-] The Given Target Directory is Not Present!");
        return;
    } else {
        println!("[+] Given Target Directory: {}", target_directory);
    }

    // Check if output directory exists, create if not
    if !Path::new(&output_directory).is_dir() {
        println!("[-] The Given Output Directory is Not Present!");
        println!("[+] Creating the Output Directory.");
        if let Err(e) = fs::create_dir(&output_directory) {
            eprintln!("[-] Failed to create directory: {}", e);
            return;
        }
    }

    println!("[+] Given Output Directory: {}", output_directory);
    println!("[+] Searching for Encrypted files [ Files with *.24bes extensions ]");

    // Compile the regex for matching encrypted files
    let re = Regex::new(r"^.+\.24bes$").unwrap();

    // Iterate over files in the target directory
    if let Ok(entries) = fs::read_dir(target_directory) {
        for entry in entries {
            if let Ok(entry) = entry {
                let file_name = entry.file_name().into_string().unwrap();
                let file_path = entry.path();

                if re.is_match(&file_name) {
                    println!("[+] Found Encrypted File: {}", file_name);
                    println!("[+] Reading the Encrypted File: {}", file_name);

                    // Read the encrypted file as bytes
                    let mut encrypted_bytes = Vec::new();
                    if let Ok(mut file) = File::open(&file_path) {
                        if let Err(e) = file.read_to_end(&mut encrypted_bytes) {
                            eprintln!("[-] Error reading file {}: {}", file_name, e);
                            continue;
                        }
                    }

                    // Decrypt the bytes
                    let mut decrypted_bytes = Vec::new();
                    println!("[+] Decrypting the Encrypted File: {}", file_name);
                    for (i, &byte) in encrypted_bytes.iter().enumerate() {
                        decrypted_bytes.push(byte ^ key.as_bytes()[i % key_len]);
                    }

                    // Create the decrypted file name
                    let decrypted_file_name = format!("{}/{}", output_directory, &file_name[..file_name.len() - 6]);

                    // Write the decrypted data
                    println!("[+] Writing the Decrypted data to {}", decrypted_file_name);
                    if let Ok(mut decrypted_file) = File::create(&decrypted_file_name) {
                        if let Err(e) = decrypted_file.write_all(&decrypted_bytes) {
                            eprintln!("[-] Error writing to file {}: {}", decrypted_file_name, e);
                            continue;
                        }
                    }

                    println!("[+] Successfully Written the Decrypted data to {}", decrypted_file_name);
                }
            }
        }
    }

    let end_time = start_time.elapsed();
    println!("[+] Total Time Taken: {:.2} seconds", end_time.as_secs_f64());
}
```

{% endtab %}
{% endtabs %}

The above python script ran successfully as shown in the following image.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FwHAhmmRgaBLoScwP97Sr%2Fimage.png?alt=media&amp;token=67e94741-4343-48b0-92a5-76854a1e264a" alt=""><figcaption></figcaption></figure>

The above Rust code also ran successfully as shown in the following image:

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FjyK7ojPq7tKuK8sMaaoI%2Fimage.png?alt=media&amp;token=530abd9c-6d00-48d0-a3c8-81b28ca68c57" alt=""><figcaption></figcaption></figure>

It took around 9 seconds for the python script and 0.94 seconds for the rust script ( release version ) to decrypt the files and you can see all the decrypted files are stored in a separated directory named `decrypted_forela-criticaldata` as shown in the following image.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FJP94aBivRIZFw9NMMEmV%2Fimage.png?alt=media&amp;token=21b28be2-b29a-4425-bbca-43c7fe86f3af" alt=""><figcaption></figcaption></figure>

We have successfully decrypted all the files. Next I used the `grep` command to search for the given email <wbevansn1@cocolog-nifty.com> in all the decrypted files as shown in the above image.

**Answer:**  `Walden Bevans`

***

## Task 3

### Question

What is the MAC address and serial number of the laptop assigned to Hart Manifould?

### Solution

The `it_assets.xml` file contains all the information about assets owned by the people. The `it_assets.xml` file has the `XML` content in a minified/compressed format. I used `CyberChef` to beautify the XML code as shown in the below image.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2F8L5RD5MRSyZDujvgCx9W%2Fimage.png?alt=media&amp;token=81c19c36-6724-4797-877c-144f84801e1f" alt=""><figcaption></figcaption></figure>

After downloading the beautified version of the `it_assets.xml` file, I opened it with `VScode` and used the find feature to filter the results.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FnlaOHQhcIykJGYk9t6l6%2Fimage.png?alt=media&amp;token=b1a15ab4-811e-43b7-8378-e3bd33faa42f" alt=""><figcaption></figcaption></figure>

Successfully found the information related to assets of Hart Manifould as shown in the above image.

**Answer:** `E8-16-DF-E7-52-48, 1316262`

***

## Task 4

### Question

What is the email address of the attacker?

### Solution

The attacker has left a note for each file that was encrypted.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2F0kqF1eHza0QsrOzf4k7W%2Fimage.png?alt=media&amp;token=1852bbd7-0720-41d7-8132-28d56826e7b0" alt=""><figcaption></figcaption></figure>

All the notes contains the email of the attacker as shown in the above image.

**Answer:** `bes24@protonmail.com`

***

## Task 5

### Question

City of London Police have suspicions of some insider trading taking part within our trading organisation. Please confirm the email address of the person with the highest profit percentage in a single trade alongside the profit percentage.

### Solution

To find the details of the person with the highest profit percentage in a single trade, I used the `jq` command in combination with the `grep` command, to sort and filter out the json data from the `trading-firebase_bkup.json` file and extract the details. The command I used is as follows:

{% code overflow="wrap" %}

```bash
jq '[.[]] | sort_by(.profit_percentage) | .[-1] | (.profit_percentage)' trading-firebase_bkup.json | xargs -I pp grep pp trading-firebase_bkup.json
```

{% endcode %}

The above command worked correctly and extracted the details of the person as shown in the following image.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FrfkFjDGtuQj2VI1pQDIU%2Fimage.png?alt=media&amp;token=d5225d62-8e9c-440a-890b-a179b1972235" alt=""><figcaption></figcaption></figure>

**Answer:** `fmosedale17a@bizjournals.com, 142303.1996053929628411706675436`

***

## Task 6

### Question

Our E-Discovery team would like to confirm the IP address detailed in the Sales Forecast log for a user who is suspected of sharing their account with a colleague. Please confirm the IP address for Karylin O'Hederscoll.

### Solution

This data is available in the `sales_forecast.xlsx` file. To view the `XLSX` file, I used the following online `XLSX` viewer: <https://products.aspose.app/cells/viewer/xlsx>

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FwrDbIUWXt2ohbAS3cEt3%2Fimage.png?alt=media&amp;token=5d483b7b-3d31-4a43-88a7-5ebfe6316820" alt=""><figcaption></figcaption></figure>

We can find the IP address  of Karylin as shown in the above image.

**Answer:** `8.254.104.208`

***

## Task 7

### Question

Which of the following file extensions is not targeted by the malware? `.txt, .sql,.ppt, .pdf, .docx, .xlsx, .csv, .json, .xml`

### Solution

The given only binary checks for the extensions that is shown in the decompiled view of the Ghidra disassembler.

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FOdVLVEOd88PJrNwwwwAv%2Fimage.png?alt=media&amp;token=7a6403e2-c1cf-4bf9-a5d1-ead74326f8d5" alt=""><figcaption></figcaption></figure>

**Answer:** `.ppt`

***

## Task 8

### Question

We need to confirm the integrity of the files once decrypted. Please confirm the MD5 hash of the applicants DB.

### Solution

You can get the MD5 hash of the `forela_uk_applicants.sql` file using the following command.

```bash
md5sum forela_uk_applicants.sql
```

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FMdr82Ukojre0Rd6V0YJj%2Fimage.png?alt=media&amp;token=fdb071dc-f712-4c3a-9200-cb662a0ccbcf" alt=""><figcaption></figcaption></figure>

**Answer:** `f3894af4f1ffa42b3a379dddba384405`

***

## Task 9

### Question

We need to confirm the integrity of the files once decrypted. Please confirm the MD5 hash of the trading backup.

### Solution

You can get the MD5 hash of the `trading-firebase_bkup.json` file using the following command.

```bash
md5sum trading-firebase_bkup.json
```

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FGwtQVNfmVbmunoycEazw%2Fimage.png?alt=media&amp;token=9f917255-6bca-4797-845e-bfa3fd0ee024" alt=""><figcaption></figcaption></figure>

**Answer:** `87baa3a12068c471c3320b7f41235669`

***

## Task 10

### Question

We need to confirm the integrity of the files once decrypted. Please confirm the MD5 hash of the complaints file.

### Solution

You can get the MD5 hash of the `complaints.csv` file using the following command.

```bash
md5sum complaints.csv
```

<figure><img src="https://3766366075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FmgBRtrRN7KBbA6FISaV1%2Fuploads%2FyhzgK1B45LEXaqoNWBXP%2Fimage.png?alt=media&amp;token=5a2723c9-8de8-42cc-a5d3-bbe7ab2efccc" alt=""><figcaption></figcaption></figure>

**Answer:** `c3f05980d9bd945446f8a21bafdbf4e7`
