# Extracted

{% embed url="<https://tryhackme.com/r/room/extractedroom>" %}

The following post by 0xb0b is licensed under [CC BY 4.0<img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" alt="" data-size="line"><img src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" alt="" data-size="line">](http://creativecommons.org/licenses/by/4.0/?ref=chooser-v1)

***

## Initial Alert and File Inspection

In the challenge, we have a PCAPNG file. In the story of the challenge, we are a senior DFIR specialist and were alerted by a junior colleague that some suspicious traffic was being generated. The SIEM had failed to capture the network traffic, but the network capture device was still working.

We open the pcapng file using Wireshark and detect a small amount of `HTTP` traffic, followed by pure TCP traffic on port `1337`.

<figure><img src="/files/KdPWuYvvMHfZJikHI98L" alt=""><figcaption></figcaption></figure>

## Traffic Analysis

We inspect the HTTP traffic by right-clicking on the packet and following the HTTP stream. We see that a PowerShell script gets downloaded.

`Follow -> HTTP Stream`

<figure><img src="/files/qscSqevmPQ08ewIOArEx" alt=""><figcaption></figcaption></figure>

Inspecting the TCP traffic on port `1337` we see a bunch of base64 encoded data.

`Follow -> TCP Stream`

<figure><img src="/files/U0OQ5uJnPS9B9Uzr8g0g" alt=""><figcaption></figcaption></figure>

First, lets export the script. Via&#x20;

`File -> Export Objects -> HTTP...`

We are able to retrieve the script `xxxmmdcclxxxiv.ps1`.

<figure><img src="/files/OEYgz1YTq2Exzh4CUu5X" alt=""><figcaption></figcaption></figure>

## PowerShell Script Functionality

This script is a PowerShell script for dumping the memory of a KeePass process using `procdump.exe` and performing additional actions, including XOR encoding the dump files and sending them over a network. We look through it section by section.

It checks if KeePass is running, and if KeePass is running, it uses `procdump.exe` to generate a memory dump.

<figure><img src="/files/u0C1O2LzaO3mIzRC95On" alt=""><figcaption></figcaption></figure>

That memory dump is stored in `1337.dmp` and the data is XOR-encoded using the key `0x41`. The XOR-encoded content is converted into a Base64 string and then sent over a TCP connection to a remote server on port `1337`.

<figure><img src="/files/IfXso1k8aT0lAlY5KcYu" alt=""><figcaption></figcaption></figure>

If a file named `Database1337.kdbx` is found, it follows similar steps for XOR encoding, Base64 encoding, and sending the file over the network. The data is XOR-encoded using the key `0x42`, then converted into a Base64 string.

<figure><img src="/files/MLsnP9OFNVojwraCkn5t" alt=""><figcaption></figcaption></figure>

The data is then sent over a TCP connection over port `1338`.

<figure><img src="/files/E5DmRJIblT4nhUQpoGhf" alt=""><figcaption></figcaption></figure>

## Extracting Data from TCP Port `1337`

On port `1337`, a lot of data is being transmitted. Following the traffic via `Follow->TCP Stream` is not recommended. But we already know what the data might be. Let's get that via `tshark`.

<figure><img src="/files/L1rY0aRusOzodUOzguoV" alt=""><figcaption></figcaption></figure>

Via tshark we retrieve the raw data send over port `1337` and store it into the file `dump_1337.raw`.

{% code overflow="wrap" %}

```
tshark -r traffic.pcapng -Y "tcp.port == 1337" -T fields -e data > dump_1337.raw
```

{% endcode %}

<figure><img src="/files/RAFTAmSbG3OgIFoajAoC" alt=""><figcaption></figcaption></figure>

## Restoring the Memory Dump

The next thing we do is to craft a script to restore the data, which, when retrieved via the tshark method, is still in raw hex. With that script, the data gets first converted from hex to ASCII, then base64 decoded and then XORed with the extracted key `0x41`.

{% hint style="info" %}
This script was generated using ChatGPT. In the end, it would have been faster to write it independently, since GPT made a lot of mistakes
{% endhint %}

{% code title="stream2dmp.py" overflow="wrap" lineNumbers="true" %}

```python
import base64

def process_raw_data(file_path, output_file, xor_key=None):
    try:
        # Step 1: Read raw hex data from file
        with open(file_path, 'r') as file:
            hex_data = file.read().strip()

        # Step 2: Convert hex to ASCII (to look for Base64 content)
        ascii_data = bytes.fromhex(hex_data).decode("utf-8", errors="ignore")

        # Step 3: Extract potential Base64 content
        base64_content = None
        for line in ascii_data.splitlines():
            if len(line) > 50 and all(c.isalnum() or c in '+/=' for c in line):
                base64_content = line
                break

        if not base64_content:
            print("No Base64 content found.")
            return

        # Step 4: Decode Base64 content first
        decoded_base64 = base64.b64decode(base64_content)

        # Step 5: XOR decryption on Base64-decoded content (if a key is provided)
        decrypted_data = decoded_base64
        if xor_key is not None:
            decrypted_data = bytearray([byte ^ xor_key for byte in decoded_base64])

        # Step 6: Write the XOR-decrypted data to a .dmp file
        with open(output_file, 'wb') as output:
            output.write(decrypted_data)

        print(f"Decrypted data written to {output_file}")

    except Exception as e:
        print(f"An error occurred: {str(e)}")

# Usage
file_path = 'dump_1337.raw'  # Path to your raw hex data file
output_file = 'output_1337.dmp'  # Path to save the output file
xor_key = 0x41  # Replace with your XOR key
process_raw_data(file_path, output_file, xor_key)
```

{% endcode %}

After running the script, we check if we successfully decoded the data. Using the `file` command, we see it is a `Mini Dump`. The conversion was successful.

<figure><img src="/files/fxVabsn9c2qSQfZ3VQPn" alt=""><figcaption></figcaption></figure>

## Extracting the Master Key

We seem to have no chance with `grep` getting the initial part of the software. After some research, we come across the keepass-dump-masterkey tool by [matro7sh](https://github.com/matro7sh).

{% embed url="<https://github.com/matro7sh/keepass-dump-masterkey>" %}

With that, we are able to retrieve the initial password and are able to answer the first question.

<figure><img src="/files/fUPiaJ3cWNefyISWEdDQ" alt=""><figcaption></figcaption></figure>

## Retreiving the KeePass File

Still, we are missing the KeePass file, to test that password. Let's get back to our Wireshark session. By excluding the traffic on port `1337`, we see at the end the transmission of the KeePass file on port 1338, as seen in the script.

<figure><img src="/files/LffB9l0DW6NibVgBrQf8" alt=""><figcaption></figcaption></figure>

Via&#x20;

`Follow -> TCP Stream`

We are able to extract the base64-encoded data.

<figure><img src="/files/duojbeKfLeQfsKnuAEVp" alt=""><figcaption></figcaption></figure>

Using the following script, or CyberChef, we are able to retrieve the transmitted KeePass file.

{% code title="dec-keepass.py" lineNumbers="true" %}

```python
import base64

# Base64 encoded string
encoded_string = "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"

# Hexadecimal key
hex_key = 0x42  # Key 42 in hexadecimal

# Decode the base64 string
decoded_bytes = base64.b64decode(encoded_string)

# XOR decryption function
def xor_decrypt(data, key):
    return bytes([b ^ key for b in data])

# Decrypt the data using XOR with the hex key
decrypted_data = xor_decrypt(decoded_bytes, hex_key)

with open("dec.kdbx", "wb") as file:
    file.write(decrypted_data)
```

{% endcode %}

After extracting the keepass file via the script we are able to check via the file command if the conversion was successful.

<figure><img src="/files/UpFiYSpM3H97M9auhs2m" alt=""><figcaption></figcaption></figure>

Using CyberChef:

<figure><img src="/files/0eo8EA8By1iqmVpxU8pg" alt=""><figcaption></figcaption></figure>

## Brute-Forcing the KeePass Password

Using the initial password, we are prompted that the file may be corrupt or the password incorrect.

<figure><img src="/files/m6vq6VrcZJyFQXPem5vB" alt=""><figcaption></figcaption></figure>

We recall the second question of the challenge and the hint from the <https://github.com/matro7sh/keepass-dump-masterkey> repository:

> As a reminder, the first character cannot be found in the dump, and for the second the script will only give you a few possibilities, in any case we recommend you to run the bruteforce on 2 chars with the script below

The first character cannot be found and needs to be brute-forced. To craft a wordlist we use the following script t prepend any printable character. Keep in mind, that the base password in this script is redacted and need to be changed.

{% code title="wordlist.py" overflow="wrap" lineNumbers="true" %}

```python
#!/usr/bin/env python3
import string

# Target string, CHANGE ME
target = "REDACTED"

# Open a file to write the results
with open("wordlist.txt", "w") as f:
    # Loop through all printable characters and prepend them to the target string
    for char in string.printable:
        result = char + target
        f.write(result + "\n")

print("Wordlist generated and written to wordlist.txt")

```

{% endcode %}

<figure><img src="/files/dYaDHlgo6l941eMXapTp" alt=""><figcaption></figcaption></figure>

We use the suggested script from the repository, but it fails.

```
#!/bin/sh
# Usage: ./keepass-pwn.sh Database.kdbx wordlist.txt (wordlist with 2 char)
while read i
do
    echo "Using password: \"$i\""
    echo "$i" | kpcli --kdb=$1 && exit 0
done < $2

```

<figure><img src="/files/lvXulFVlFdEAI7dDeWeA" alt=""><figcaption></figcaption></figure>

After another research we come across [**keepass4brute**](https://github.com/r3nt0n/keepass4brute)**,** which lets us brute force the password.

{% embed url="<https://github.com/r3nt0n/keepass4brute>" %}

After a short execution, we receive the correct password.

<figure><img src="/files/t8aCsyCZajoJ9EDdmMzc" alt=""><figcaption></figcaption></figure>

We are now able to unlock the KeePass file and find the final flag in the `Notes` of the entry `You win!`.

<figure><img src="/files/JSF00gNlW3bJ6K4eO4sA" alt=""><figcaption></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xb0b.gitbook.io/writeups/tryhackme/2024/extracted.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
