☕
Writeups
TryHackMeHackTheBoxReferralsDonateLinkedIn
  • Writeups
  • TryHackme
    • 2025
      • Security Footage
      • Ledger
      • Moebius
      • Mayhem
      • Robots
      • Billing
      • Crypto Failures
      • Rabbit Store
      • Decryptify
      • You Got Mail
      • Smol
      • Light
      • Lo-Fi
      • Silver Platter
    • 2024
      • Advent of Cyber '24 Side Quest
        • T1: Operation Tiny Frostbite
        • T2: Yin and Yang
        • T3: Escaping the Blizzard
        • T4: Krampus Festival
        • T5: An Avalanche of Web Apps
      • The Sticker Shop
      • Lookup
      • Mouse Trap
      • Hack Back
      • SeeTwo
      • Whiterose
      • Rabbit Hole
      • Mountaineer
      • Extracted
      • Backtrack
      • Brains
      • Pyrat
      • K2
        • Base Camp
        • Middle Camp
        • The Summit
      • The London Bridge
      • Cheese CTF
      • Breakme
      • CERTain Doom
      • TryPwnMe One
      • Hammer
      • U.A. High School
      • IronShade
      • Block
      • Injectics
      • DX2: Hell's Kitchen
      • New York Flankees
      • NanoCherryCTF
      • Publisher
      • W1seGuy
      • mKingdom
      • Airplane
      • Include
      • CyberLens
      • Profiles
      • Whats Your Name?
      • Capture Returns
      • TryHack3M
        • TryHack3M: Burg3r Bytes
        • TryHack3M: Bricks Heist
        • TryHack3M: Sch3Ma D3Mon
        • TryHack3M: Subscribe
      • Creative
      • Bypass
      • Clocky
      • El Bandito
      • Hack Smarter Security
      • Summit
      • Chrome
      • Exfilibur
      • Breaking RSA
      • Kitty
      • Reset
      • Umbrella
      • WhyHackMe
      • Dodge
    • 2023
      • Advent of Cyber '23 Side Quest
        • The Return of the Yeti
        • Snowy ARMageddon
        • Frosteau Busy with Vim
        • The Bandit Surfer
      • Stealth
      • AVenger
      • Dreaming
      • DockMagic
      • Hijack
      • Bandit
      • Compiled
      • Super Secret TIp
      • Athena
      • Mother's Secret
      • Expose
      • Lesson learned?
      • Grep
      • Crylo
      • Forgotten Implant
      • Red
    • Obscure
    • Capture
    • Prioritise
    • Weasel
    • Valley
    • Race Conditions
    • Intranet
    • Flip
    • Cat Pictures 2
    • Red Team Capstone Challenge
      • OSINT
      • Perimeter Breach
      • Initial Compromise of Active Directory
      • Full Compromise of CORP Domain
      • Full Compromise of Parent Domain
      • Full Compromise of BANK Domain
      • Compromise of SWIFT and Payment Transfer
  • HackTheBox
    • 2025
      • Certified
    • 2024
      • BoardLight
      • Crafty
      • Devvortex
      • Surveillance
      • Codify
      • Manager
      • Drive
      • Zipping
    • 2023
      • Topology
Powered by GitBook
On this page
  • L1 Keycard
  • What is the password the attacker used to register on the site?
  • What is the password that the attacker captured?
  • What is the password of the zip file transferred by the attacker?
  • Extract The Zip
  • Decrypt The Traffic
  • What is McSkidy's password that was inside the database file stolen by the attacker?

Was this helpful?

  1. TryHackme
  2. 2024
  3. Advent of Cyber '24 Side Quest

T1: Operation Tiny Frostbite

The first of our enemies is the Frostbite Fox.

PreviousAdvent of Cyber '24 Side QuestNextT2: Yin and Yang

Last updated 4 months ago

Was this helpful?

The following post by 0xb0b is licensed under


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?

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.

Furthermore we have the following link in the room:

We inspect the profile of Bloatware-WarevilleTHM:

This user also has a C2-Server project.

We are focusing on the server for now.

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.

app.py
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)

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.

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.

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

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

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.

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.

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.

What is the password that the attacker captured?

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

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

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.

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

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 9001 seems just to be gibberish; it might be encrypted.

Extract The Zip

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.

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

Directly From Traffic Found

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

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

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

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.

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

We were able to retrieve the zip file:

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.

As already mentioned, this is encrypted.

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

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.

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

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

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

This encrypts its communication using AES CBC 128.

Packet Encryption Layer for Tiny SHell

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

pel.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 );
}

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.

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

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

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.

decipher.py
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')

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

We seperate the packages and run the script.

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

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

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.

CC BY 4.0
Advent of Cyber '24 Side QuestTryHackMe
https://raw.githubusercontent.com/MM-WarevilleTHM/IS/refs/heads/main/IS.ps1
Logo
GitHubGitHub
Bloatware-WarevilleTHM - OverviewGitHub
C2-Server/app.py at main · Bloatware-WarevilleTHM/C2-ServerGitHub
VirusTotalVirusTotal
GitHub - creaktive/tsh: Tiny SHell - An open-source UNIX backdoor (I'm not the author!)GitHub
Logo
tsh/pel.c at master · creaktive/tshGitHub
Logo
Logo
Logo
Logo
Logo