Good Morning/Afternoon/Evening CTFers! I’m 5h1kh4r and this post will include my writeups for all the Rev challenges in the UrchinSec Aware CTF 2024. These are the challenges from the Rev category:

  1. bonD (100)
  2. Let’s Vibe (100)
  3. Drift (300)
  4. Panel (300)

So without any further discussion, let’s start with the writeups!

  1. bonD

We were given a binary file to work with (bond) so we work with that only.

Step 1: Initial Steps

I opened the file in notepad to see if there are any low-hanging flags, but nope found nothing

Step 2: Decompiling the binary

I upload the binary to https://dogbolt.org and get the decompiled code.

uint64_t _xor_string(char* arg1, char* arg2, char arg3)
{
uint64_t result = _strlen(arg1);

for (int64_t i = 0; i < result; i += 1)  
    arg2[i] = (arg1[i] ^ arg3);  
  
arg2[result] = 0;  
return result;  

}

int64_t _main()
{
int64_t x8 = ___stack_chk_guard;
int32_t var_22c = 0;
_printf(“Enter A Key To Bond : “);
void var_128;
void
__s = &var_128;
_fgets(&var_128, 0x100, *___stdinp);
*(__s + _strcspn(__s, &data_100003f6f)) = 0;
char var_239 = 0x4b;
void __s1;
_xor_string(__s, &__s1, 0x4b);

if (_strcmp(&__s1, "gu\{yn\zont\v3j0f0j\n3g") != 0)  
    _printf("NO NO! BEGONE!!!!\n");  
else  
    _printf("Looks like a match to me!\n");  
  
if (*___stack_chk_guard == x8)  
    return 0;  
  
___stack_chk_fail();  
/* no return */  

}

void ___stack_chk_fail() __noreturn
{
/* tailcall */
return ___stack_chk_fail();
}

char* _fgets(char* arg1, int32_t arg2, FILE* arg3)
{
/* tailcall */
return _fgets(arg1, arg2, arg3);
}

int32_t _printf(char const* arg1)
{
/* tailcall */
return _printf(arg1);
}

int32_t _strcmp(char const* __s1, char const* __s2)
{
/* tailcall */
return _strcmp(__s1, __s2);
}

uint64_t _strcspn(char const* __s, char const* __charset)
{
/* tailcall */
return _strcspn(__s, __charset);
}

uint64_t _strlen(char const* __s)
{
/* tailcall */
return _strlen(__s);
}

Out of everything, only the main() function and xor_string() function are of our interest so we will focus on that.

Step 3: Analyzing the code

If we read the main() function, it is initializing a string and decrypting it with some key, these parameters are passed onto the xor_string() function. So we know that the encrypted text is encrypted with XOR.

Step 4: Decrypting

So I put the XOR encrypted ciphertext in cyberchef with the key in the code which is 0x4b (in hex) and we get the following output:

No result. Then I try the XOR Key bruteforce method in cyberchef and I think I hit something.

see the text with the key 03. Yes that seems to be encrypted with something. Putting it in our trusty cipher identifier we get:

Out of all these, Atbash cipher seems to work. And you get the flag!

2. Let’s Vibe

We were given a ZIP file containing a mysterious file named `vibe`. Let’s dive in to discover what’s inside!

## Step 1: Initial File Inspection

Running a quick check:

bash $ file vibe vibe: data

This didn’t provide much insight. After uploading it to (https://www.checkfiletype.com/), I found that it’s identified as a **VBScript Encoded Script**.

## Step 2: Decoding the VBScript

After a bit of research, I found a Python script that can decode VBScript-encoded files. Here’s the code snippet:

#!/usr/bin/env python3
import argparse, sys, os, re
from colorama import Fore, Style

Initialize argparse for command-line arguments

parser = argparse.ArgumentParser(description=“Decode an encoded VBScript (.vbe file)”)
parser.add_argument(‘files’, metavar=‘file’, type=str, nargs=‘+’, help=‘file to decode’)
parser.add_argument(“-o”, “–output”, metavar=‘output’, type=str, default=None, help=‘output file’)
args = parser.parse_args()

Main decoding function

def decode_data(data: str):
decoding_offset = 9
decodings = […] # Full decoding table here
combinations = […]
replacements = [(‘@&’, ‘\n’), (‘@#’, ‘\r’), (‘@*’, ‘>’), (‘@!’, ‘<’), (‘@$’, ‘@’)]
for to_replace, replace_with in replacements:
data = data.replace(to_replace, replace_with)
# Decoding byte sequences based on ‘voodoo’ encoding
result, index = [], -1
bad_bytes = [60, 62, 64]
for char in data:
byte = ord(char)
if byte < 128:
index += 1
if byte == decoding_offset or (31 < byte < 128 and byte not in bad_bytes):
char = decodings[byte - decoding_offset][combinations[index % 64]]
result.append(char)
return “”.join(result)

Running the decoding process

def decode_files(files: list):
return ‘\n’.join([decode_file(file) for file in files])

def main():
if not args.output:
sys.stdout.write(decode_files(args.files))
else:
with open(args.output, ‘w’) as handle:
handle.write(decode_files(args.files))

if name == ‘main’:
main()

I ran the decoder script with the following command:

bash $ python3 solver.py vibe -o decoded
[+] success, wrote decoded vbscript to ‘decoded’

## Step 3: Revealing the Flag

With the `decoded` file ready, I inspected its contents:

$ cat decoded
’ Author: @nicl4ssic

MsgBox (“What do you need here?”)
MsgBox (“Oooh, you are looking for flag?”)
’ MsgBox (“Here it is urchinsec{v1bing_w1th_VBS_d8e3ca}”)
MsgBox (“Keep looking..😂😂”)

**Flag Found**: urchinsec{v1bing_w1th_VBS_d8e3ca} — — And there we go! The VBScript was crafted to distract us with playful messages, but the true flag was hidden in the comments. Mission accomplished!

3. Drift

Step 1: Analyzing Pcap file

We open the pcap file and find alot of packets, I first try to find any http packets, because those are the ones to be found first only. I found this packet which seemed to be interesting.

This packet seems to contain an elf file which is basically a linux binary file. I extract this file from the pcap file using the export objects feature of wireshark.

Step 2: Decompiling the binary

I tried decompiling the binary using dogbolt.org but I didn’t get the complete code so I used binary ninja to decompile. This is the main() function:

This is the compare_hashes() function:

So now I just try to find the hash value which is being used. And I found it in the main function itself

Now I put this hash into crackstation.net and I get the cracked!

But this is not the flag, the flag is along with the username. So our flag is:

urchinsec{admin_vanessa}

4. Panel

Code Overview

The function check_secret takes a string input a1 and checks for a specific secret code. The key to this challenge is understanding each part of the function and calculating values to match specific conditions. —

Key Steps and Calculations

  1. Input Parsing with **strtol**
  • The function parses a1 as a long integer v7 using strtol.
  • If parsing overflows, it triggers error code 34, displaying:

“None Found In Range”

  • If the input a1 doesn’t contain any numbers, it shows:

“No Secret Code Was Found”

  1. Secret Code Check ( **v7 == 133739**)
  • If parsing is successful and v7 matches 133739, we proceed to calculate the flag.

— -

Finding the Required Input Length (15 characters)

To reach the final condition, v4 / 7 must equal 267478. This gives us a formula to solve for v6 (length of a1): [ v6 = \frac{7 x 267478 + 133739}{133739} = 15 ] So, a1 needs to be 15 characters long. —

Flag Calculation

With v6 = 15, we proceed as follows:

  • Calculate v4:[ v4 = 133739 x 15 - 133739 = 1872346]
  • Plugging v4 into the flag formula:[ flag = urchinsec{ 1872346 + 2006085 } = urchinsec{3878431}]

— -

Final Solution

The flag for this challenge is:

urchinsec{3878431}