# ToolPie

## Getting an Overview

According to the story, the designs of a toolmaker have been stolen. We have to investigate the incident and expose Lord Malakar as guilty. This forensics challenge starts off with a pcap file. The first thing that looked interesting was a request to a web page with a nice tale, related to the lore of the CTF:

{% code overflow="wrap" %}

```html
      <p>In the heart of Eastmarsh, where traders and adventurers alike gather, there stood a humble yet revered figure...Garrick Stoneforge, the Guardian Smith. His forge, a beacon of unwavering craftsmanship, glowed with an intensity that matched his dedication. While most saw only the glimmer of his enchanted locks and finely wrought tools, those who paid closer attention whispered of something more...something hidden beneath the clang of hammer against steel.</p>

            <p>For years, Garrick...s work was sought after, not just for its quality but for the intricate designs etched into every piece he created. Patterns of runes, symbols long forgotten, whispered secrets only those willing to listen could understand. Some say his trinkets were more than just adornments; they were keys...keys that could open more than doors, revealing secrets long buried beneath the foundation of Eastmarsh itself.</p>
            
            <p>One particular evening, under the glow of a waning moon, a mysterious traveler arrived at Garrick...s forge. Draped in a cloak darker than the night, they carried with them a request...an artifact locked away, sealed behind a mechanism of Garrick...s own making. It was then that the Guardian Smith faced a choice: to protect the secrets he had crafted or aid in their unraveling.</p>

            <p>What happened that night remains unknown, but the following dawn brought unease to Eastmarsh. Garrick, a man of unshakable principle, seemed distant. The forge burned lower, the usual rhythm of his hammer faltered. Whispers filled the town square...had the Guardian Smith unlocked something never meant to be found?</p>
            
            <p>Days passed, and then weeks, until the forge fell silent altogether. Some claim Garrick vanished, while others believe his presence still lingers in the very locks he forged. His creations remain scattered across Eastmarsh, treasured by those who value craftsmanship and mystery alike.</p>

            <p>Even now, his legend endures...his work a lasting testament to a craftsman who dared to shape more than metal. The Guardian Smith of Eastmarsh may be gone, but his story, like the artifacts he left behind, will never be forgotten.</p>
```

{% endcode %}

Another interesting request was made to /script.html

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Medieval Script Executor - Medieval Chronicles</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <header>
            <div class="corner-decoration">.......</div>
            <div class="corner-decoration">.......</div>
            <div class="corner-decoration">......</div>
            <div class="corner-decoration">.......</div>
            <h1>Magical Script Executor</h1>
            <div class="divider">....</div>
            <nav class="medieval-nav">
                <a href="index.html">Chronicles</a>
                <span class="nav-divider">......</span>
                <a href="script.html">Script Executor</a>
            </nav>
        </header>
        
        <article class="blog-post">
            <h2>The Mystical Python Scroll</h2>
            <div class="scroll-container">
                <textarea id="scriptInput" class="scroll-text" placeholder="Inscribe thy Python incantations here..."></textarea>
            </div>
            
            <div class="action-container">
                <button onclick="executeScript()" class="medieval-button">Execute Thy Script To Create Thy Tool</button>
            </div>
            
            <div class="quote output-container">
                <h3>Prophecy Output</h3>
                <pre id="outputArea">The tool shall appear here...</pre>
            </div>
        </article>
    </div>

    <script>
        async function executeScript() {
            const scriptText = document.getElementById('scriptInput').value;
            const outputArea = document.getElementById('outputArea');
            
            try {
                const response = await fetch('/execute', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({ script: scriptText }),
                });
                
                const result = await response.json();
                outputArea.textContent = result.output || 'No output was produced by thy script.';
            } catch (error) {
                outputArea.textContent = 'A mystical error has occurred: ' + error.message;
            }
        }
    </script>
</body>
</html>
```

This html suggests that there was a web page that could be used to execute code in some way.

A POST in json format to /execute can be made with the script, apparently providing the means to execute Python code on the server. And indeed, a POST to the server can be found!

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2Fu8fYx6hQy2A9IjeN55Je%2Fimage.png?alt=media&#x26;token=147ed329-6d7f-434e-b52e-25ef19a1d8fb" alt=""><figcaption><p>Suspicious POST Request</p></figcaption></figure>

At first glance, the script bz2-decompresses a bytestream and then loads and executes it. The necessary libraries are imported first and a keyboard interrupt stops the execution.

I saved the compressed stream in raw hex format.

The next TCP stream looks like something that happened on the server, which seems to be a Windows host:

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2FPdehM9EpNZxmf5S8Uzvg%2Fimage.png?alt=media&#x26;token=9db0e4e6-5663-465e-aba5-6b1e112bc3b4" alt=""><figcaption><p>Suspicious Encrypted Requests</p></figcaption></figure>

Almost nothing of this can be determined, except the machine and user at the start

`ec2amaz-bktvi3e\administrator`

The blue parts at the beginning are the only server data transmitted. The rest is 8.504 kB of client data.

This is the next stream:

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2FKUW3wPaG5ZChJWPdg5Bn%2Fimage.png?alt=media&#x26;token=c05f5dca-b166-4bda-9c75-459524824620" alt=""><figcaption><p>Stream 2 of Encrypted Requests</p></figcaption></figure>

And this is the final related one:

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2FJjzBhKY6E1hRggpdf4k0%2Fimage.png?alt=media&#x26;token=f3935233-bc94-430d-bf45-bec49c22d848" alt=""><figcaption><p>Ending Request</p></figcaption></figure>

The first and last two lines do not seem encrypted, the rest does.

**Start:**\
`ec2amaz-bktvi3e\administrator`\
`<SEPARATOR>5UUfizsRsP7oOCAq`

**End:**\
`ec2amaz-bktvi3e\administrator`\
`<SEPARATOR>LFca75ceNdmiGtrZ`

I had the suspicion that these requests are the start and end requests of an encrypted C2 communication. The two seemingly random strings could be encryption keys.

From the investigation of the aforementioned requests in Wireshark, I could already determine the relevant IPs that were involved in the suspicious traffic:

**Server IP:** 172.31.47.152\
**Sent Mal. Script:** 194.59.6.66\
**Potential C2:** 13.61.7.218:55155

## Analyzing the Python Script

I stored the script and cleaned it up in an effort to see what it does.

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2Fa6pa70Sg9Epp5agVIuqv%2Fimage.png?alt=media&#x26;token=fb7f0fc0-77d3-41a0-b942-1928e5f40fe4" alt=""><figcaption><p>Stored Python Script Start</p></figcaption></figure>

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2FQSKKgktPDGfQBKoqAowO%2Fimage.png?alt=media&#x26;token=3d1770a5-1ff8-4402-a317-5b5adb48d2bb" alt=""><figcaption><p>Stored Python Script End</p></figcaption></figure>

From the start of the script you can tell that the following data must be a bz2 steam with a block size of 9, as it starts with `BZh9`

`\x` is the Python Byte delimiter. The extra `\` comes from html encoding. This could be reversed:

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2FAQcmkvfoFFG4hOFb4sP3%2Fimage.png?alt=media&#x26;token=9e258789-2ef1-4b15-b551-6352193b8718" alt=""><figcaption><p>Unescaping the Bytestring</p></figcaption></figure>

The resulting script worked if you replaced "exec" with "print".

```python
python malscriptprint.py
<SNIP>
<code object <module> at 0x5bc7acd4bbe0, file "Py-Fuscate", line 1>
<SNIP>
```

This also reveals the program that was used to obfuscate the code. The goal now is to recover the obfuscated code from the marshal object.

Unescaping the result again and extracting strings from it gave some insights into what it might be doing.

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2FiRsRyfXIbV9LTbj98yCw%2Fimage.png?alt=media&#x26;token=e4fa508d-3a3a-4928-945a-09dbb3846118" alt=""><figcaption><p>Bytestring String Recovery</p></figcaption></figure>

The results indicate Py-Fuscate was used to obfuscate code that can send AES-encrypted files to or from the IP 13.61.7.218

I created a script to output the disassembled version that yielded some more info.

```python
import marshal
import dis

marshal_object = b'''c\x00\x00\x00\x00\x00<SNIP>\x03'''

code_object = marshal.loads(marshal_object)
dis.dis(code_object)
```

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2F494OxFQDy9ofwnzKzVLx%2Fimage.png?alt=media&#x26;token=ae45b5be-e09c-4e70-af39-3a17e07bd018" alt=""><figcaption><p>Marshal Disassembly</p></figcaption></figure>

`import marshal,lzma,gzip,bz2,binascii,zlib` indicates that lzma, binascii, lzma and zlib are potentially used inside the marshal.

I read through the disassembly and noted any relevant information that caught my eye.

### Disas initial:

* Process opened
* AES Crypto.Cipher and Crypto.Util.Padding are used/created
* There is the '\<SEPARATOR>' string
* There are the code objects enc\_mes, dec\_file\_mes, dec\_mes, receive\_file, receive
* The main function is created. A socket is opened for a client. A connection to ('13.61.7.218', 55155) is prepared. encode is used
* receive\_thread with ('target', 'args') is used
* A sleep time of 50 is done

### Disas enc\_mes:

* An AES CBC encryption is prepared with the variables cypher, key and cypher\_block and padding

### Disas dec\_file\_mes:

* The key is encoded and used for AES CBC decryption. An unpadding is done and the vars key, cypher, cypher\_block are used. The cipher is a byte object initially

### Disas dec\_mes:

* The cipher is a byte object. The vars cypher, cypher\_block and key are used to unpad and AES CBC decrypt the byte object

### Disas receive\_file:

* A socket is opened, ('13.61.7.218', 54163). The vars k, client2 and more are used.
* enc\_received, dec\_mes, enc\_received and ok\_enc are used. a SEPARATOR var is used
* enc\_mes and ok\_enc are used. A byte object is received and read. files can be written.
* There is the error ('Error transporting file')

### Disas \<genexpr>:

* A random ASCII letter string apperas to be generated

### Disas receive:

* A message is received and decrpyted. The vars msg and message are used. The message is encrypted again to check if decryption was correct
* enc\_answ is used. A file can be sent to "target". A file can be received and get\_file is used, as well as enc\_mes
* dec\_mes is used and a file can be written.
* enc\_mes, dec\_mes and a send operation can be seen again
* The message + \n is set
* An answer is encoded and send. The error message ('Bad command!') appears. The error ('Error uploading file') also appears.
* A client connect to ('13.61.7.218', 55155) can be seen again

From what we have seen before, we have the encryption key(s) from the network traffic.

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2FPUQhMWmxtQr1tLCLCMjK%2Fimage.png?alt=media&#x26;token=b0d5c846-8815-44e5-9d67-a94c23adedef" alt=""><figcaption><p>Encryption Key(s)</p></figcaption></figure>

## Decrypting

Testing around with different Key-IV combinations in Cyberchef, it appeared that the first 16 Bytes after the SEPARATOR were the key and the second string was the IV.

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2F8AzeE87xXCFNBiGFrV0L%2Fimage.png?alt=media&#x26;token=2ce88573-fc89-4674-95b8-6b9f2c07d412" alt=""><figcaption><p>Decryption in CyberChef</p></figcaption></figure>

I changed the Wireshark view to raw bytes. TCP stream 4 could be decrypted to  a PDF file this way!

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2FwVanafPOAHmgSkUdAIv1%2Fimage.png?alt=media&#x26;token=a546b0a0-1f98-4f60-b8ab-24eff359fc9a" alt=""><figcaption><p>TCP Stream 4 Raw</p></figcaption></figure>

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2F94fCRdZ47SKMRYdf9VVl%2Fimage.png?alt=media&#x26;token=5f42c6e8-b36e-4e1e-9fb7-f62e92e36d87" alt=""><figcaption><p>PDF Decryption</p></figcaption></figure>

Using the "save as file" function of CyberChef worked perfectly to retrieve the PDF.

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2FUDCxWv0lHM8ZUJywnGxs%2Fimage.png?alt=media&#x26;token=1cbc4dc1-93c6-493c-8a1b-63c475f71a92" alt=""><figcaption><p>Recovered PDF File</p></figcaption></figure>

The md5sum of the pdf (that was required to solve the challenge) was wrong though. A friend saw the string "yeportLab Generated PDF document" and downloaded a reference file from <https://www.reportlab.com/docs/reportlab-userguide.pdf>

Here is a comparison of the start bytes of the decrypted file and the sample PDF:

**Extract:**

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2FYwpTniTeqXtxXGaESzd2%2Fimage.png?alt=media&#x26;token=6daa6b85-e63c-4fb8-8d4a-b13f0ae9ca9b" alt=""><figcaption><p>Recovered PDF Start</p></figcaption></figure>

**Sample:**

<figure><img src="https://746814813-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fe1HXVppEt3OHWIFqtAXT%2Fuploads%2FJkStdRkXJZFSHaUnCHfy%2Fimage.png?alt=media&#x26;token=e0d5a8c5-5bd9-4024-b3fc-e9a1123e9134" alt=""><figcaption><p>Sample PDF Start</p></figcaption></figure>

Replacing the first Bytes to the ones of the sample report worked and the challenge was solved.

## Challenge Questions

### What is the IP address responsible for compromising the website?

`194.59.6.66` - This is clearly the IP that sent the malicious script to the server when you inspect the http streams

### What is the name of the endpoint exploited by the attacker?

`execute` - You can see that the malicious script was POSTed to /execute

### What is the name of the obfuscation tool used by the attacker?

`PyFuscate` - This could be seen after decompressing the initial byte object

### What is the IP address and port used by the malware to establish a connection with the Command and Control (C2) server?

`13.61.7.218:55155` - This could also be found in the decompressed string and also in Wireshark

### What encryption key did the attacker use to secure the data?

`5UUfizsRsP7oOCAq` - This can be found at the start of the encrypted data in Wireshark

### What is the MD5 hash of the file exfiltrated by the attacker?

\- This can be generated after the PDF has been AES CBC decrypted and the first Bytes of the PDF corrected with the ones from a sample pdf


---

# 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://shibudocs.gitbook.io/htb-writeups/cyber-apocalypse-2025-tales-from-eldoria/toolpie.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.
