# T1: Operation Tiny Frostbite

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

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)

***

## L1 Keycard

We find the keycard for the first Side Quest hidden in the task of the first day of the TryHackMe Advent Of Cyber. It asks the question `What's with all these GitHub repos? Could they hide something else?`

Day 1: Maybe SOC-mas music, he thought, doesn't come from a store?

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FBvdQ8D0zx9sf1ghcXSmU%2Fgrafik.png?alt=media&#x26;token=4522322f-1671-41e7-b8cf-b6ba10466e51" alt=""><figcaption></figcaption></figure>

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FG9dKK1yxJppcwXos9xSp%2Fgrafik.png?alt=media&#x26;token=df20cfd6-41bc-461f-a5ab-ea20750dbb59" alt=""><figcaption></figcaption></figure>

So let's take a look at the repositories we have available. In the scenario of the task, the following script is downloaded and executed. It is from the profile `MM-WarevilleTHM`.

{% embed url="<https://raw.githubusercontent.com/MM-WarevilleTHM/IS/refs/heads/main/IS.ps1>" %}

Furthermore we have the following link in the room:

{% embed url="<https://github.com/search?q=%22Created+by+the+one+and+only+M.M.%22&type=issues>" %}

We inspect the profile of Bloatware-WarevilleTHM:

{% embed url="<https://github.com/Bloatware-WarevilleTHM>" %}

This user also has a C2-Server project.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F9GrCyRJV2BXChIL4fOnZ%2Fgrafik.png?alt=media&#x26;token=aae87541-ecf8-413c-b4aa-b50734625ce5" alt=""><figcaption></figcaption></figure>

We are focusing on the server for now.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Ffa4QQncfm5JFqleYCCBr%2Fgrafik.png?alt=media&#x26;token=fc628925-2d69-4d3c-93ac-ccd37894d59b" alt=""><figcaption></figcaption></figure>

{% embed url="<https://github.com/Bloatware-WarevilleTHM/C2-Server/blob/main/app.py>" %}

The C2-Server is a Flask app that provides a login with session-based authentication. It allows an admin to log in with hardcoded credentials (`ADMIN_USERNAME` and `ADMIN_PASSWORD`) and access a dashboard and data page. Users who are not logged in will be redirected to the login page. With a valid session, we are able to reach `/dashboard`. The `secret_key` is used for secure session management, and the app runs on `host="0.0.0.0"` and `port=8000`. Since we have access to the `secret_key` we are able to craft our own session cookie to access the dashboard.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FIOpPHJLzD0vVjokr6Szv%2Fgrafik.png?alt=media&#x26;token=f8ac98ef-d6ee-43e9-8038-dc40afe4ad3f" alt=""><figcaption></figcaption></figure>

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

```python
from flask import Flask, render_template, request, redirect, url_for, session

app = Flask(__name__)

app.secret_key = "REDACTED"

ADMIN_USERNAME = "admin"           
ADMIN_PASSWORD = "securepassword" #CHANGE ME!!!

@app.route("/")
def home():
    if "logged_in" in session:
        return redirect(url_for("dashboard"))
    return redirect(url_for("login"))

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form["username"]
        password = request.form["password"]
        if username == ADMIN_USERNAME and password == ADMIN_PASSWORD:
            session["logged_in"] = True
            session["username"] = username
            return redirect(url_for("dashboard"))
        else:
            return render_template("login.html", error="Invalid credentials!")
    return render_template("login.html")

@app.route("/dashboard")
def dashboard():
    if "logged_in" not in session:
        return redirect(url_for("login"))
    return render_template("dashboard.html")

@app.route("/data")
def data():
    if "logged_in" not in session:
        return redirect(url_for("login"))
    return render_template("data.html")

@app.route("/logout")
def logout():
    session.pop("logged_in", None)
    session.pop("username", None)
    return redirect(url_for("login"))

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)
```

{% endcode %}

On the machine for the first task of Advent Of Cyber, port `8000` is also available in addition to the YouTube to MP3 converter. Here we see a login to Bloatware-C2. This might be the C2-server of Bloatware-WarevilleTHM. We have a login in front of us.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FWNZHtStLMg1sAKkaymgf%2Fgrafik.png?alt=media&#x26;token=f79ed9be-0ab9-401c-899f-9c03cd1727f5" alt=""><figcaption></figcaption></figure>

We give it a try and craft a session cookie using `flask-unsing`, since we know the secret used. In this case, we need to use the `--legacy` tag to get a working cookie. This might depend on different versions of `flask-unsing`.

{% code overflow="wrap" %}

```
flask-unsing --sign --cookie "{'logged_in':True,'username':'admin'}" --secret 'REDACTED' --legacy
```

{% endcode %}

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FY9a64no6W8jjL3TtsqKJ%2Fgrafik.png?alt=media&#x26;token=5d688c3d-2c51-4d83-b730-3dc1c3a54296" alt=""><figcaption></figcaption></figure>

We add that cookie like the following with the web development tools in our browser.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FaTBHCD0JPp33OLyFCFqn%2Fgrafik.png?alt=media&#x26;token=4948c964-3b32-45f3-a0eb-9be0f0e061ae" alt=""><figcaption></figcaption></figure>

After that, we are able to access the `/dashboard` and find the first keycard which contains the password for the zip file of the first side quest.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FzsCuypOlYg8VfEdg7vGj%2Fgrafik.png?alt=media&#x26;token=8a71ec6b-8600-47be-b467-4739fa6f23cf" alt=""><figcaption></figcaption></figure>

## What is the password the attacker used to register on the site?

We unpack the ZIP with the password of the first keycard and find a PCAP file. We find a port scan, traffic on port `22`, and a lot of traffic on port `80`.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FlUZivOl9tp570GmHo7kY%2Fgrafik.png?alt=media&#x26;token=b7bff6ac-c409-4d74-8536-7be8964e9ff2" alt=""><figcaption></figcaption></figure>

Since the first question is about passwords, we search for this keyword in the packet details. We click on find again and again and find on packet `1532` the first credentials used for registering the user frostyfox.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F3BFsMLTBKk8ZLadh1BCK%2Fgrafik.png?alt=media&#x26;token=0bcbafeb-72ec-4b3e-adea-bb78805d0e5b" alt=""><figcaption></figcaption></figure>

## What is the password that the attacker captured?

We continue with our search and on packet no. `1535` we find the credentials of `mcskidy`.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fy0q00ghxX4yzvED26cBB%2Fgrafik.png?alt=media&#x26;token=1f63799b-fa62-408d-a21b-413152bac370" alt=""><figcaption></figcaption></figure>

The first two questions could also be answered very quickly by using grep to search for the entries with `password` in the PCAP.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FZyEzNKhpEw993rlGBAWn%2Fgrafik.png?alt=media&#x26;token=f71c478f-8bbf-4755-a2f7-081cd33f6ae7" alt=""><figcaption></figcaption></figure>

## What is the password of the zip file transferred by the attacker?

The next question asks for the password of a transferred zip file. But we cannot find it in the HTTP Object via `File -> Export Objects -> HTTP`.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FG1ToBMcLoxXvQvkH4HxC%2Fgrafik.png?alt=media&#x26;token=33af64cd-6807-4c56-8c79-c344db4de25b" alt=""><figcaption></figcaption></figure>

Nevertheless, there are interesting files that could be of interest to us later on; it is the file `ff`.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FsV3U8L5DNphS4rBAsrmY%2Fgrafik.png?alt=media&#x26;token=8727371a-7f0e-460d-ba34-44e864aef688" alt=""><figcaption></figcaption></figure>

We continue and first filter out the traffic on port `22` and port `80` and also  ignore the Nmap traffic. We find traffic on ports `9001` and `9002`. The traffic on port `900`1 seems just to be gibberish; it might be encrypted.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FgszbLk3Ld4wJ5fi9ylgr%2Fgrafik.png?alt=media&#x26;token=9cd50b53-a4cf-4e57-a9cd-2fe1028100c1" alt=""><figcaption></figcaption></figure>

### Extract The Zip&#x20;

This step is not crucial to answering the current question but the next.

A zip file starts with the magic bytes PK, so we have to look for that. First, we inspect the traffic on port `9002`.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2Fng36HpJ8t0YFNhYumOju%2Fgrafik.png?alt=media&#x26;token=a0e37ce3-4852-4446-a05a-f94e5190424c" alt=""><figcaption></figcaption></figure>

Here we see some sort of SQL file, which is mentioned in the last question.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F1cPvPQlTWqaww7ecGcaG%2Fgrafik.png?alt=media&#x26;token=21ac2c6a-7cf9-45f9-b6db-e4af7f8809b1" alt=""><figcaption></figcaption></figure>

#### Directly From Traffic Found

We can extract the ZIP file by following the TCP Stream of the traffic on port 9002.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FtLdYVALj6y0Oajaf1ECb%2Fgrafik.png?alt=media&#x26;token=09a3ceef-5bc6-47bb-9e9e-f3058b652452" alt=""><figcaption></figcaption></figure>

The next thing we do is to save the raw data to a file.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FKOj8qsKI4t1PbZYvgHKF%2Fgrafik.png?alt=media&#x26;token=66bdbf96-43d5-4b07-9ceb-3a955b2a7374" alt=""><figcaption></figcaption></figure>

It is indeed a zip file containing the `elves.sql` file. But we are not able to crack the password used.&#x20;

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FSeOdFJIqaCGdWxUizp4P%2Fgrafik.png?alt=media&#x26;token=ccbe66e2-fbb4-46b0-a375-c42313baae85" alt=""><figcaption></figcaption></figure>

#### From Raw PCAP

This is another approach to extracting the zip. From the PCAP file we can see there is some data with the magic bytes PK in it and also the `elves.sql` file.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FZQDvpbdQLF6BrBq1hlI7%2Fgrafik.png?alt=media&#x26;token=45275593-6853-411e-bb48-83ee5d8664ba" alt=""><figcaption></figcaption></figure>

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FY01sFq12m3YnwwJTsdSS%2Fgrafik.png?alt=media&#x26;token=875f531d-990a-4a1b-aaf4-ad3dceaf765f" alt=""><figcaption></figcaption></figure>

The idea is now to extract all the data fields and convert the hexadecimal data into `output.hex` back into its raw binary form and saves the result in a file named `hex`. We then are able to retrieve the zip via `binwalk -e hex` using binwalk it analyzes the binary file `hex` and attempts to extract any embedded files, data, or compressed archives.

```
tshark -r traffic.pcap -Y 'http or tcp' -T fields -e data > output.hex
```

```
xxd -r -p output.hex hex
```

```
binwalk -e hex
```

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FZMjbaSeFM2yHTWDUtgUv%2Fgrafik.png?alt=media&#x26;token=3ac7c564-b6f1-4a24-a436-e83aa1667c27" alt=""><figcaption></figcaption></figure>

We were able to retrieve the zip file:

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F9QU1VyRvoakjMuTEOBKC%2Fgrafik.png?alt=media&#x26;token=342f3a71-9bd3-4908-a69c-fe73520b7b0e" alt=""><figcaption></figcaption></figure>

### Decrypt The Traffic

Since we were not able to crack the password for the zip, we have to look deeper into the traffic. We may be able to find out how the zip was created. We remember the traffic on port `9001`.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FiSfOa2PcEnV2FtXY5Jra%2Fgrafik.png?alt=media&#x26;token=d54c464b-e0c8-49bf-9777-0deb9552d2ff" alt=""><figcaption></figcaption></figure>

As already mentioned, this is encrypted.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F9FHLnBd8MLbZQNXTTMtP%2Fgrafik.png?alt=media&#x26;token=6a7ee021-0ee4-4e47-990b-8fe067b085c3" alt=""><figcaption></figcaption></figure>

We look at the binaries that were transmitted in the course of the communication. Including the file `ff`.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F8N0fENRiyL90IA3oT8jy%2Fgrafik.png?alt=media&#x26;token=edcdef47-7a2f-4b1e-83a4-4165701b90b1" alt=""><figcaption></figcaption></figure>

As reverse engineering of this specific binary is somewhat overwhelming, we decide to check to scan for any malware using Virustotal. For this, we calculate the MD5 checksum of that file.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F9TD0OqxqQT92UcWFWso0%2Fgrafik.png?alt=media&#x26;token=6d4e735b-e913-41d0-a3c6-3acc6d6d8b09" alt=""><figcaption></figcaption></figure>

Next, we use the hash to search for known entries at Virustotal...

{% embed url="<https://www.virustotal.com/gui/>" %}

... and we have a few hits. It seems to be a Rekoobe Backdoor.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FuCqLFtgP1ZmeMLaxiBYZ%2Fgrafik.png?alt=media&#x26;token=e692c4f6-6d07-4272-85d5-a34f37beb7ae" alt=""><figcaption></figcaption></figure>

Among the community entries we find the reference to Tiny SHell and its repository.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FH71kH0rfKXbeElBeQ9cN%2Fgrafik.png?alt=media&#x26;token=c448f371-af3d-4c4a-be46-0a6d459928cf" alt=""><figcaption></figcaption></figure>

{% embed url="<https://github.com/creaktive/tsh>" %}

This encrypts its communication using AES CBC 128.

> Packet Encryption Layer for Tiny SHell

{% embed url="<https://github.com/creaktive/tsh/blob/master/pel.c>" %}

How this encryption works or is used can be found in pel.c.

It implements a **Packet Encryption Layer (PEL)** for a Tiny Shell application, utilizing **AES-CBC-128** encryption and **HMAC-SHA1** for integrity verification. Here's a concise summary:

1. **Encryption Mode:**
   * Uses **AES in CBC mode** with a 128-bit key.
   * IVs (Initialization Vectors) are generated using SHA-1 and process-specific data.
2. **Message Authentication:**
   * Integrity is ensured using **HMAC-SHA1**.
   * A packet counter (`p_cntr`) is included to prevent replay attacks.
3. **Session Initialization:**
   * **Client Side:** Generates two IVs, sets up encryption contexts, and performs a challenge-response handshake with the server.
   * **Server Side:** Receives IVs from the client, sets up encryption contexts, and validates the client's handshake challenge.
4. **Message Transmission:**
   * Encrypts plaintext in 16-byte blocks (AES block size).
   * Adds padding for alignment and appends an HMAC for integrity.
   * Sends the combined encrypted message and HMAC to the receiver.
5. **Message Reception:**
   * Verifies the HMAC to ensure integrity.
   * Decrypts ciphertext block by block using AES-CBC

{% code title="pel.c" lineNumbers="true" %}

```c
/*
 * Packet Encryption Layer for Tiny SHell,
 * by Christophe Devine <devine@cr0.net>;
 * this program is licensed under the GPL.
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>

#include "pel.h"
#include "aes.h"
#include "sha1.h"

/* global data */

int pel_errno;

struct pel_context
{
    /* AES-CBC-128 variables */

    struct aes_context SK;      /* Rijndael session key  */
    unsigned char LCT[16];      /* last ciphertext block */

    /* HMAC-SHA1 variables */

    unsigned char k_ipad[64];   /* inner padding  */
    unsigned char k_opad[64];   /* outer padding  */
    unsigned long int p_cntr;   /* packet counter */
};

struct pel_context send_ctx;    /* to encrypt outgoing data */
struct pel_context recv_ctx;    /* to decrypt incoming data */

unsigned char challenge[16] =   /* version-specific */

    "\x58\x90\xAE\x86\xF1\xB9\x1C\xF6" \
    "\x29\x83\x95\x71\x1D\xDE\x58\x0D";

unsigned char buffer[BUFSIZE + 16 + 20];

/* function declaration */

void pel_setup_context( struct pel_context *pel_ctx,
                        char *key, unsigned char IV[20] );

int pel_send_all( int s, void *buf, size_t len, int flags );
int pel_recv_all( int s, void *buf, size_t len, int flags );

/* session setup - client side */

int pel_client_init( int server, char *key )
{
    int ret, len, pid;
    struct timeval tv;
    struct sha1_context sha1_ctx;
    unsigned char IV1[20], IV2[20];

    /* generate both initialization vectors */

    pid = getpid();

    if( gettimeofday( &tv, NULL ) < 0 )
    {
        pel_errno = PEL_SYSTEM_ERROR;

        return( PEL_FAILURE );
    }

    sha1_starts( &sha1_ctx );
    sha1_update( &sha1_ctx, (uint8 *) &tv,  sizeof( tv  ) );
    sha1_update( &sha1_ctx, (uint8 *) &pid, sizeof( pid ) );
    sha1_finish( &sha1_ctx, &buffer[ 0] );

    memcpy( IV1, &buffer[ 0], 20 );

    pid++;

    if( gettimeofday( &tv, NULL ) < 0 )
    {
        pel_errno = PEL_SYSTEM_ERROR;

        return( PEL_FAILURE );
    }

    sha1_starts( &sha1_ctx );
    sha1_update( &sha1_ctx, (uint8 *) &tv,  sizeof( tv  ) );
    sha1_update( &sha1_ctx, (uint8 *) &pid, sizeof( pid ) );
    sha1_finish( &sha1_ctx, &buffer[20] );

    memcpy( IV2, &buffer[20], 20 );

    /* and pass them to the server */

    ret = pel_send_all( server, buffer, 40, 0 );

    if( ret != PEL_SUCCESS ) return( PEL_FAILURE );

    /* setup the session keys */

    pel_setup_context( &send_ctx, key, IV1 );
    pel_setup_context( &recv_ctx, key, IV2 );

    /* handshake - encrypt and send the client's challenge */

    ret = pel_send_msg( server, challenge, 16 );

    if( ret != PEL_SUCCESS ) return( PEL_FAILURE );

    /* handshake - decrypt and verify the server's challenge */

    ret = pel_recv_msg( server, buffer, &len );

    if( ret != PEL_SUCCESS ) return( PEL_FAILURE );

    if( len != 16 || memcmp( buffer, challenge, 16 ) != 0 )
    {
        pel_errno = PEL_WRONG_CHALLENGE;

        return( PEL_FAILURE );
    }

    pel_errno = PEL_UNDEFINED_ERROR;

    return( PEL_SUCCESS );
} 

/* session setup - server side */

int pel_server_init( int client, char *key )
{
    int ret, len;
    unsigned char IV1[20], IV2[20];

    /* get the IVs from the client */

    ret = pel_recv_all( client, buffer, 40, 0 );

    if( ret != PEL_SUCCESS ) return( PEL_FAILURE );

    memcpy( IV2, &buffer[ 0], 20 );
    memcpy( IV1, &buffer[20], 20 );

    /* setup the session keys */

    pel_setup_context( &send_ctx, key, IV1 );
    pel_setup_context( &recv_ctx, key, IV2 );

    /* handshake - decrypt and verify the client's challenge */

    ret = pel_recv_msg( client, buffer, &len );

    if( ret != PEL_SUCCESS ) return( PEL_FAILURE );

    if( len != 16 || memcmp( buffer, challenge, 16 ) != 0 )
    {
        pel_errno = PEL_WRONG_CHALLENGE;

        return( PEL_FAILURE );
    }

    /* handshake - encrypt and send the server's challenge */

    ret = pel_send_msg( client, challenge, 16 );

    if( ret != PEL_SUCCESS ) return( PEL_FAILURE );

    pel_errno = PEL_UNDEFINED_ERROR;

    return( PEL_SUCCESS );
}

/* this routine computes the AES & HMAC session keys */

void pel_setup_context( struct pel_context *pel_ctx,
                        char *key, unsigned char IV[20] )
{
    int i;
    struct sha1_context sha1_ctx;

    sha1_starts( &sha1_ctx );
    sha1_update( &sha1_ctx, (uint8 *) key, strlen( key ) );
    sha1_update( &sha1_ctx, IV, 20 );
    sha1_finish( &sha1_ctx, buffer );

    aes_set_key( &pel_ctx->SK, buffer, 128 );

    memcpy( pel_ctx->LCT, IV, 16 );

    memset( pel_ctx->k_ipad, 0x36, 64 );
    memset( pel_ctx->k_opad, 0x5C, 64 );

    for( i = 0; i < 20; i++ )
    {
        pel_ctx->k_ipad[i] ^= buffer[i];
        pel_ctx->k_opad[i] ^= buffer[i];
    }

    pel_ctx->p_cntr = 0;
}

/* encrypt and transmit a message */

int pel_send_msg( int sockfd, unsigned char *msg, int length )
{
    unsigned char digest[20];
    struct sha1_context sha1_ctx;
    int i, j, ret, blk_len;

    /* verify the message length */

    if( length <= 0 || length > BUFSIZE )
    {
        pel_errno = PEL_BAD_MSG_LENGTH;

        return( PEL_FAILURE );
    }

    /* write the message length at start of buffer */

    buffer[0] = ( length >> 8 ) & 0xFF;
    buffer[1] = ( length      ) & 0xFF;

    /* append the message content */

    memcpy( buffer + 2, msg, length );

    /* round up to AES block length (16 bytes) */

    blk_len = 2 + length;

    if( ( blk_len & 0x0F ) != 0 )
    {
        blk_len += 16 - ( blk_len & 0x0F );
    }

    /* encrypt the buffer with AES-CBC-128 */

    for( i = 0; i < blk_len; i += 16 )
    {
        for( j = 0; j < 16; j++ )
        {
            buffer[i + j] ^= send_ctx.LCT[j];
        }

        aes_encrypt( &send_ctx.SK, &buffer[i] );

        memcpy( send_ctx.LCT, &buffer[i], 16 );
    }

    /* compute the HMAC-SHA1 of the ciphertext */

    buffer[blk_len    ] = ( send_ctx.p_cntr << 24 ) & 0xFF;
    buffer[blk_len + 1] = ( send_ctx.p_cntr << 16 ) & 0xFF;
    buffer[blk_len + 2] = ( send_ctx.p_cntr <<  8 ) & 0xFF;
    buffer[blk_len + 3] = ( send_ctx.p_cntr       ) & 0xFF;

    sha1_starts( &sha1_ctx );
    sha1_update( &sha1_ctx, send_ctx.k_ipad, 64 );
    sha1_update( &sha1_ctx, buffer, blk_len + 4 );
    sha1_finish( &sha1_ctx, digest );

    sha1_starts( &sha1_ctx );
    sha1_update( &sha1_ctx, send_ctx.k_opad, 64 );
    sha1_update( &sha1_ctx, digest, 20 );
    sha1_finish( &sha1_ctx, &buffer[blk_len] );

    /* increment the packet counter */

    send_ctx.p_cntr++;

    /* transmit ciphertext and message authentication code */

    ret = pel_send_all( sockfd, buffer, blk_len + 20, 0 );

    if( ret != PEL_SUCCESS ) return( PEL_FAILURE );

    pel_errno = PEL_UNDEFINED_ERROR;

    return( PEL_SUCCESS );
}

/* receive and decrypt a message */

int pel_recv_msg( int sockfd, unsigned char *msg, int *length )
{
    unsigned char temp[16];
    unsigned char hmac[20];
    unsigned char digest[20];
    struct sha1_context sha1_ctx;
    int i, j, ret, blk_len;

    /* receive the first encrypted block */

    ret = pel_recv_all( sockfd, buffer, 16, 0 );

    if( ret != PEL_SUCCESS ) return( PEL_FAILURE );

    /* decrypt this block and extract the message length */

    memcpy( temp, buffer, 16 );

    aes_decrypt( &recv_ctx.SK, buffer );

    for( j = 0; j < 16; j++ )
    {
        buffer[j] ^= recv_ctx.LCT[j];
    }

    *length = ( ((int) buffer[0]) << 8 ) + (int) buffer[1];

    /* restore the ciphertext */

    memcpy( buffer, temp, 16 );

    /* verify the message length */

    if( *length <= 0 || *length > BUFSIZE )
    {
        pel_errno = PEL_BAD_MSG_LENGTH;

        return( PEL_FAILURE );
    }

    /* round up to AES block length (16 bytes) */

    blk_len = 2 + *length;

    if( ( blk_len & 0x0F ) != 0 )
    {
        blk_len += 16 - ( blk_len & 0x0F );
    }

    /* receive the remaining ciphertext and the mac */

    ret = pel_recv_all( sockfd, &buffer[16], blk_len - 16 + 20, 0 );

    if( ret != PEL_SUCCESS ) return( PEL_FAILURE );

    memcpy( hmac, &buffer[blk_len], 20 );

    /* verify the ciphertext integrity */

    buffer[blk_len    ] = ( recv_ctx.p_cntr << 24 ) & 0xFF;
    buffer[blk_len + 1] = ( recv_ctx.p_cntr << 16 ) & 0xFF;
    buffer[blk_len + 2] = ( recv_ctx.p_cntr <<  8 ) & 0xFF;
    buffer[blk_len + 3] = ( recv_ctx.p_cntr       ) & 0xFF;

    sha1_starts( &sha1_ctx );
    sha1_update( &sha1_ctx, recv_ctx.k_ipad, 64 );
    sha1_update( &sha1_ctx, buffer, blk_len + 4 );
    sha1_finish( &sha1_ctx, digest );

    sha1_starts( &sha1_ctx );
    sha1_update( &sha1_ctx, recv_ctx.k_opad, 64 );
    sha1_update( &sha1_ctx, digest, 20 );
    sha1_finish( &sha1_ctx, digest );

    if( memcmp( hmac, digest, 20 ) != 0 )
    {
        pel_errno = PEL_CORRUPTED_DATA;

        return( PEL_FAILURE );
    }

    /* increment the packet counter */

    recv_ctx.p_cntr++;

    /* finally, decrypt and copy the message */

    for( i = 0; i < blk_len; i += 16 )
    {
        memcpy( temp, &buffer[i], 16 );

        aes_decrypt( &recv_ctx.SK, &buffer[i] );

        for( j = 0; j < 16; j++ )
        {
            buffer[i + j] ^= recv_ctx.LCT[j];
        }

        memcpy( recv_ctx.LCT, temp, 16 );
    }

    memcpy( msg, &buffer[2], *length );

    pel_errno = PEL_UNDEFINED_ERROR;

    return( PEL_SUCCESS );
}

/* send/recv wrappers to handle fragmented TCP packets */

int pel_send_all( int s, void *buf, size_t len, int flags )
{
    int n;
    size_t sum = 0;
    char *offset = buf;

    while( sum < len )
    {
        n = send( s, (void *) offset, len - sum, flags );

        if( n < 0 )
        {
            pel_errno = PEL_SYSTEM_ERROR;

            return( PEL_FAILURE );
        }

        sum += n;

        offset += n;
    }

    pel_errno = PEL_UNDEFINED_ERROR;

    return( PEL_SUCCESS );
}

int pel_recv_all( int s, void *buf, size_t len, int flags )
{
    int n;
    size_t sum = 0;
    char *offset = buf;

    while( sum < len )
    {
        n = recv( s, (void *) offset, len - sum, flags );

        if( n == 0 )
        {
            pel_errno = PEL_CONN_CLOSED;

            return( PEL_FAILURE );
        }

        if( n < 0 )
        {
            pel_errno = PEL_SYSTEM_ERROR;

            return( PEL_FAILURE );
        }

        sum += n;

        offset += n;
    }
        
    pel_errno = PEL_UNDEFINED_ERROR;

    return( PEL_SUCCESS );
}
```

{% endcode %}

What we are missing now is the key and the IVs. We can see that the key has been defined in the header file `tsh.h`. As we are in possession of the `ff` file, we can extract this.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FAxa87WilQegOoS8YHwXa%2Fgrafik.png?alt=media&#x26;token=7a3eb424-cebd-4bb6-9d42-abc33e462617" alt=""><figcaption></figcaption></figure>

Using BinaryNinja, we look at the `.data` segment and find the key directly there.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F4HldgmyJ9IqpLK41NTLd%2Fgrafik.png?alt=media&#x26;token=c3c466f1-5772-4f1f-88d2-8d33be6b5189" alt=""><figcaption></figcaption></figure>

Now, we need to extract the data that has been send to the target machine, to see which commands might have been executed. For this we use tshark. The first package sent are the two IVs

```
tshark -r traffic.pcap -Y "tcp.dstport == 9001" -T fields -e data > port_9001_data.txt
```

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FGhbYMGj8hFf9fmApIzG0%2Fgrafik.png?alt=media&#x26;token=fac5bde2-667b-4610-8942-6ed36aa1cd86" alt=""><figcaption></figcaption></figure>

With the information gathered we are able to craft script to decipher the send packets.

* **Key Derivation (`derive_keys`):**
  * Takes a `secret_key` and an **Initialization Vector (IV)** (20 bytes).
  * Derives:
    * **AES key** (128-bit) for decryption.
    * HMAC keys (`k_ipad` and `k_opad`) for message authentication.
    * Initial IV (first 16 bytes of the provided IV).
* **Decryption and HMAC Validation (`decrypt_message`):**
  * Separates the ciphertext and HMAC from the received packet.
  * Verifies the **HMAC**:
    * Uses the derived HMAC keys (`k_ipad`, `k_opad`) and packet counter to compute and compare HMACs.
  * Decrypts the ciphertext using **AES in CBC mode**:
    * Extracts the plaintext message length and content.
  * Updates the IV for the next packet based on the last ciphertext block.
* **Message Processing (`decrypt_client_message`):**
  * Maintains the decryption context, including:
    * AES key, HMAC keys, last IV, and packet counter.
  * Updates the IV and counter after processing each packet.
* **File Processing (`process_file`):**
  * Reads intercepted packets from a file (`port_9001_data.txt`).
  * Converts each line of hex-encoded packet data into bytes.
  * Decrypts and validates each packet using the client context.
  * Outputs the decoded message in both byte and hex formats.

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

```python
import hashlib
from Crypto.Cipher import AES

def derive_keys(secret_key: bytes, iv: bytes):
    """Derive AES and HMAC keys."""
    if len(iv) != 20:
        raise ValueError("IV must be 20 bytes long.")
    
    sha1 = hashlib.sha1(secret_key + iv).digest()
    aes_key = sha1[:16]
    k_ipad = bytearray((0x36 ^ b) for b in sha1[:20]) + bytearray(0x36 for _ in range(44))
    k_opad = bytearray((0x5C ^ b) for b in sha1[:20]) + bytearray(0x5C for _ in range(44))
    initial_iv = iv[:16]
    
    return aes_key, k_ipad, k_opad, initial_iv

def decrypt_message(packet: bytes, aes_key: bytes, k_ipad: bytes, k_opad: bytes, iv: bytes, packet_counter: int):
    """Decrypt a message and validate its HMAC."""
    if len(packet) <= 20:
        raise ValueError("Packet too short to contain ciphertext and HMAC.")
    
    ciphertext, received_hmac = packet[:-20], packet[-20:]
    counter_bytes = packet_counter.to_bytes(4, 'big')
    
    # Compute HMAC
    ipad_digest = hashlib.sha1(k_ipad + ciphertext + counter_bytes).digest()
    computed_hmac = hashlib.sha1(k_opad + ipad_digest).digest()
    if computed_hmac != received_hmac:
       raise ValueError("HMAC verification failed.")
    
    # Decrypt ciphertext with AES-CBC
    aes_cipher = AES.new(aes_key, AES.MODE_CBC, iv)
    plaintext = aes_cipher.decrypt(ciphertext)
    
    # Extract message length and message
    msg_len = (plaintext[0] << 8) + plaintext[1]
    message = plaintext[2:2 + msg_len]
    
    # Update IV for the next message
    next_iv = ciphertext[-16:]
    return message, next_iv

def decrypt_client_message(packet, context):
    aes_key, k_ipad, k_opad, last_iv, packet_counter = context
    message, next_iv = decrypt_message(packet, aes_key, k_ipad, k_opad, last_iv, packet_counter)
    context[3] = next_iv  # Update last_iv
    context[4] += 1       # Increment packet_counter
    return message

# CHANGE THE secret_key!
secret_key = b"REDACTED"
ivs = bytes.fromhex(
    "26f321efd8ee637c408657b6fd94059e33191e953a41611cb0b4b3a0f889f679616120961d87f683"
)

iv_client, iv_server = ivs[:20], ivs[20:]
client_context = list(derive_keys(secret_key, iv_client)) + [0]  # Append packet counter

def process_file(file_path):
    with open(file_path, 'r') as file:
        for line in file:
            hex_message = line.strip()
            if hex_message:  # Ensure the line is not empty
                try:
                    packet = bytes.fromhex(hex_message)
                    decoded_message = decrypt_client_message(packet, client_context)
                    print("Decoded Client Message (bytes):", decoded_message)
                    print("Decoded Client Message (hex):", decoded_message.hex())
                except ValueError as e:
                    print(f"Failed to decrypt message {hex_message}: {e}")

# Decrypt messages from file
process_file('port_9001_data.txt')

```

{% endcode %}

The packets are unfortunately concatenated at line 9, which wont work with the script

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FNptyjcXcOGNisz8lRxyc%2Fgrafik.png?alt=media&#x26;token=957fc9f5-264b-4e03-9316-8ec6fc6f1fdf" alt=""><figcaption></figcaption></figure>

We seperate the packages and run the script.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FznjC4GPTLAIywa0WwllU%2Fgrafik.png?alt=media&#x26;token=5cc92f9b-0ddd-420f-8378-d5cbf48c028e" alt=""><figcaption></figcaption></figure>

After running the script, we can see the shell commands that were issued.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FwlwDds4cE8W3T87E6DaI%2Fgrafik.png?alt=media&#x26;token=5ae7c426-e05d-48c3-840f-9688299dc336" alt=""><figcaption></figcaption></figure>

Including the one that created the zip file containing the password.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2FG8NRm7w0OFz3bsKfQlFA%2Fgrafik.png?alt=media&#x26;token=c313c386-6a7d-4132-8f7d-c8f753085dcd" alt=""><figcaption></figcaption></figure>

## What is McSkidy's password that was inside the database file stolen by the attacker?

Now we only need to extract the `elves.sql` file from the zip, we previously extracted. In that we find McSkidy's password.

<figure><img src="https://2148487935-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoqaFccsCrwKo1CHmLRKW%2Fuploads%2F9Rvg50ePaeIdMTfkQh7M%2Fgrafik.png?alt=media&#x26;token=87d46b22-06b5-4896-9609-771f0a825fb5" 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/advent-of-cyber-24-side-quest/t1-operation-tiny-frostbite.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.
