Huntress CTF 2024 Writeup

2024-11-01

Foreword/Lede

Hey fellow vipin.xyz, vipinb.xyz, qvipin.com, qvipin.xyz, or vipin.0xf1.sh enthusiast! It's been a minute since my last blog post about learning reverse engineering. Well, we might potentially have a SQL (get it? Sequel and SQL 😂 Tell me that isn't comedy gold!).

I gave up making a writeup after the 8th day so have fun reading the 8 days of challenges. There were a few challenges I didn't write about, either because they were too easy (like you just had plug it into CyberChef), My team solved the challenge, or they were tricky enough that I was just grateful to have solved them (Like Russian Roulette, Strange Calc, and OceanLocust) :D. Hope you enjoy this and the other 2 (now nonexistant) parts of this writeup!

Table of Contents

FYI: These are all the challenges I've solved, except for a few that were too complex personally (i'm just lazy 😭) to write up.

Day 1

Base64by32 | Scripting

Day 2

No Need for Brutus | Cryptography

Day 3

Cattle | Warmups

Day 4

Malibu | Miscellaneous

Whamazon | Warmups

Day 5

Unbelievable | Warmups

Day 6

TXT Message | Warmups

Discount Programming Devices | Malware

Day 7

Mimi | Malware

Day 8

Zimmer Down | Forensics

Ran Somewhere | OSINT

Base-p- | Miscellaneous

Base64by32

Description: This is a dumb challenge. I'm sorry.

By: @JohnHammond

Download Link

  • I took one look at the challenge and knew it had to be some sort of multi layered encryption. I had 2 Options.

    • A. Use Cyberchef and drag & drop the Base64 thing 32 times ❌ 👎
    • B. Make a Python Scripting ✅ 👍 🎉
  • Here is my solve script with comments for the people trying to learn from these writeups (dw I got you fam)

import base64 # Importing the Base64 Package which allows us to decode the string
 
with open('base64by32', 'rb') as chall: # Opening the challenge file provided
    file = chall.read() # Reading the file
    counter = 0 # initializing the counter with a value of 0
    
while True: # Loop
        if b'flag' in file: # Checking if the flag has been decoded
            print(f'flag: {file} after decoding {counter} times') 
            break
        else: 
            decoded = base64.b64decode(file) # Decodes the string
            counter += 1 # adds to the counter
            file = decoded # switches the file to be the decoded output 
            continue # loop backs again and won't stop until the flag is in the output
  • And then running the code outputted this!
python3 sol.py
flag: b'flag{8b3980f3d33f2ad2f531f5365d0e3970}\n' after decoding 32 times

Flag: flag{8b3980f3d33f2ad2f531f5365d0e3970}

No Need for Brutus

Description: A simple message for you to decipher: squiqhyiiycfbudeduutvehrhkjki

Submit the original plaintext hashed with MD5, wrapped between the usual flag format: flag

By: @aenygma

  • Day 2, challenge solved at 3:02 😎

  • Using the Cyberchef ROT13 Bruteforce I found this.

Image showing Cyberchef ROT13 Bruteforce output

Fig.1 CyberChef ROT13 Bruteforce
  • Since we also need to MD5 Hash it, I just ran this one liner that I made just to look cool.
echo -n 'caesarissimplenoneedforbrutus' | md5sum | sed 's/.*/flag\{&\}/'
flag{c945bb2173e7da5a292527bbbc825d3f  -}
  • Sadly the output wasn't as clean as I would want it but it still works!

Flag: flag{c945bb2173e7da5a292527bbbc825d3f}

Cattle

Description: I know it's an esoteric challenge for a Capture the Flag, but could you herd these cows for me?

By: @JohnHammond

Download Link

  • Simple warmup challenge, I found this tool and I plugged in the COW code to get the flag

Image showing COW Code Decryption Tool Output

Fig.1 MOOooOoO

Flag: flag{6cd6392eb609c6ae4c332ef6a321d9dd}

Malibu

Description: What do you bring to the beach?

By: Truman Kain

  • Started by NC'ing into it

Image showing what nc'ing did

Fig.1 Netcat output
  • No luck there and there is no webpage when opening it up. Let me try something else...
curl -i http://challenge.ctf.games:31774/flag
HTTP/1.1 403 Forbidden
Accept-Ranges: bytes
Content-Length: 287
Content-Type: application/xml
Server: MinIO
Strict-Transport-Security: max-age=31536000; includeSubDomains
Vary: Origin
Vary: Accept-Encoding
X-Amz-Id-2: dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8
X-Amz-Request-Id: 17FCB198E89DE819
X-Content-Type-Options: nosniff
X-Ratelimit-Limit: 59
X-Ratelimit-Remaining: 59
X-Xss-Protection: 1; mode=block
Date: Wed, 09 Oct 2024 05:27:07 GMT
 
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied.</Message><BucketName>flag</BucketName><Resource>/flag</Resource><RequestId>17FCB198E89DE819</RequestId><HostId>dd9025bab4ad464b049177c95eb6ebf374d3b3fd1af9251148b658df7ac2e3e8</HostId></Error>%
  • MinIO? Never heard of that... A few Google searches later I found a tool called mc. Doesn't hurt to try 🤷🏾‍♂️.
mc alias set malibu http://challenge.ctf.games:31774
Enter Access Key:
Enter Secret Key:
Added `malibu` successfully.
mc ls malibu
mc: <ERROR> Unable to list folder. Access Denied.
  • Tf? At this point, I had given up for about 2 days and so has my team... Then ffuf found that the /bucket endpoint is working.

Image showing mc worked!

Fig.2 IT WORKED!
  • Fig.2 above only shows half of the buckets there are, now I have to figure out how to get the flag...

  • I started off by downloading all the files to my computer

mc cp --recursive malibu/bucket ~/Downloads/minio_filess
...zr10M27R/WkXQ7nHJ/JV3R4AukwXTJocLn: 253.17 KiB / 253.17 KiB  ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓  56.38 KiB/s 4s
  • Nice! Let's see if I can grep for the flag.

Image showing malibu challenge flag found

Fig.3 Very Hidden 🔎
  • YES! We solved this nightmare of a challenge, still pretty fun!

Flag: flag{800e6603e86fe0a68875d3335e0daf81}

Whamazon

Description: Wham! Bam! Amazon is entering the hacking business! Can you buy a flag?

By: @JohnHammond

  • A warmup to get the day going, let's get it!

Whamazon Initial Impressions

Fig.1
  • Woah, looks nice already! Let me try use Examine your Inventory

nothing in examine inventory

Fig.2 :(
  • Next I tried to buy the flag from Whamazon

no flag for me D:

Fig.3 i too poor for this
  • I need more money :(, Ig I should try to buy something cheaper

yaya i got apple

Fig.4 yaya apple 🍎
  • It seems like it calculate the amount to subtract by doing price x amount = total taken from wallet let's try to enter a negative number...

exploited for money

Fig.5 yo we rich fam
  • AYY, it works! Still not enough to buy the flag though. Let's "buy" more apples!

Stole way too much from whamazon

Fig.6 💸
  • But wait, I gotta play Rock, Paper, Scissors 😲

rock paper scissors for some reason

Fig.7 Oh boy...
  • Let's get this flag!

We Won!

Fig.8 We Won!
  • YAYA WE WON, let's go see our flag!

YES FLAG

Fig.9 ayy we got it

Flag: flag{18bdd83cee5690321bb14c70465d3408}

Unbelievable

Description: Don't believe everything you see on the Internet! Anyway, have you heard this intro soundtrack from Half-Life 3?

By: @JohnHammond

Download Link

  • Another warmup. Let's get it!
file Half-Life_3_OST.mp3
Half-Life_3_OST.mp3: PNG image data, 800 x 200, 8-bit/color RGB, non-interlaced
  • They were right, don't trust everything you see on the internet and we see a file that is actually a .png. After we rename it to a PNG, we get...

yo its a flag!

Fig.1 ⛳️

Flag: flag{a85466991f0a8dc3d9837a5c32fa0c91}

TXT Message

Description: Hmmm, have you seen some of the strange DNS records for the ctf.games domain? One of them sure is odd...

By: @JohnHammond

  • The challenge hints at something related to the DNS records, To check them I ran dig ctf.games -t ANY

octal in txt rexord

Fig.1 Octal?
  • Judging by how the numbers are structured and how a Wikipedia link to Octal Dumps was linked, I have reason to believe it is encoded in octal.

  • And Cyberchef proves me right!

Flag: flag{14e072f705d45882401d141c562fdc0b}

Discount Programming Devices

Description: I used a tool on the internet to obfuscate my script! But I lost it, and I don't know how to get it back. Maybe you can help?

By: @sudo_Rem

Download Link

  • Upon initial looks of the files, I attempted to deobfuscate it by decrypting the script from base64 then struggles. Then I tried something else...

running it gave the flag

Fig.1 💀
  • Damn that's wild

Flag: flag{2543ff1e714bC2eb9ff78128232785ad}

Mimi

Description: Uh oh! Mimi forgot her password for her Windows laptop! Luckily, she dumped one of the crucial processes running on her computer (don't ask me why, okay)... can you help her recover her password? NOTE: This file on its own is not malware per say, but it is likely to raise antivirus alerts. Would recommend examining this inside of a virtual environment. NOTE: Archive password is mimi

By: @JohnHammond

Download Link

  • I started by finding tools to extract Mimikatz password and I found this
pypykatz -h
usage: pypykatz [-h] [-v]
                {live,lsa,registry,crypto,kerberos,dpapi,ldap,rdp,parser,smb,version,banner,logo}
                ...
 
Pure Python implementation of Mimikatz --and more--
 
positional arguments:
  {live,lsa,registry,crypto,kerberos,dpapi,ldap,rdp,parser,smb,version,banner,logo}
                        commands
    live                Get secrets from live machine
    lsa                 Get secrets from memory dump
    registry            Get secrets from registry files
    crypto              Utils for generating hashes/decrypting secrets etc
    kerberos            Kerberos related commands
    dpapi               DPAPI (offline) related commands
    ldap                LDAP related commands
    rdp                 Parse RDP credentials from minidump file
    parser              SMB related commands
    smb                 SMB related commands
    version             version
    banner              banner
    logo                logo
 
options:
  -h, --help            show this help message and exit
  -v, --verbose
  • We need to use the lsa option since this seems to be a memory dump and along with lsa we need to also use the minidump option. Let's see how it goes!
pypykatz lsa minidump mimi | grep 'flag'
INFO:pypykatz:Parsing file mimi
		password flag{7a565a86761a2b89524bf7bb0d19bcea}
		password flag{7a565a86761a2b89524bf7bb0d19bcea}
		password flag{7a565a86761a2b89524bf7bb0d19bcea}
		password flag{7a565a86761a2b89524bf7bb0d19bcea}
  • YES!

Flag: flag{7a565a86761a2b89524bf7bb0d19bcea}

Zimmer Down

Description: A user interacted with a suspicious file on one of our hosts. The only thing we managed to grab was the user's registry hive. Are they hiding any secrets?

By: @sudo_Rem

Download Link

  • Off the bat, I know this is a registry file so I used Eric Zimmerman's Registry Explorer tool to analyze the file.

content inside of reg view

Fig.1
  • We can use the bookmark feature to analyze certain key parts of the file that typically contain crucial information. There was one common bookmark I specifically used called "RecentDocs (Recently opened files by extension)" and in one of the rows I found this.

interesting row

Fig.2 hmm
  • It seems like that string could contain something and after noticing the .b62 on the string and base62 decoding it I got the flag!.

Flag: flag{4b676ccc1070be66b1a15dB601c8d500}

Ran Somewhere

Description: Thanks for joining the help desk! Here's your first ticket of the day; can you help the client out? NOTE, this challenge uses a non-standard flag format. Enter the human-readable name of the location.

By: @JohnHammond

Download Link

  • Opening the Email file in the Apple Mail we see this.

email file

Fig.1
  • uhh ok, let's look through one of the files

a potential jpeg file

Fig.2 .jpeg?
  • It seems like the first file could be a image, let's change the file extension and see the image.

the image after being converted to a jpeg

Fig.3 Hmm 🤔
  • Hmm we can use this, I also took a look at the second file attached which contained and changed it to be a .jpeg

another image of the location

Fig.4
  • There also seems to be a website attached so let's take a look at it...

goofy ahh website 💀

Fig.5 💀
  • Seems useless until I saw this...

wait finally useful

Fig.6 funny
  • Let's try searching for the location!

  • After digging for a bit I found this blog which matched the bricks on top for the castle and it was correct!

Flag: Bel Air Armory

Base-p-

Description: That looks like a weird encoding, I wonder what it's based on.

By: Izzy Spering

Download Link

  • Upon looking at the challenge name the -p- reminded me of the NMAP flag -p and I tried searching for stuff like "base ports cipher" and "base nmap cipher", but I realised that -p scans from 1-65535. I then searched for "base65535" and I found this...

woah thats a crazy kind of base64

Fig.1 🤯
  • Damn, I was off by a number, but isn't it still crazy a base can even extend to this amount? And decoding the text gives us another string that seems to be base64.

text that seems to be base64

Fig.2
  • And using this Cyberchef recipe, it decrypted to an image.

colors images

Fig.3 colors!
  • So upon looking into this deeper, I found out that the hex code of each color decodes to part of the flag, so ChatGPT wrote this script for me to get the flag!
from PIL import Image
 
def get_hex_from_image(image_path):
    # Load the image
    image = Image.open(image_path)
 
    # Get image dimensions
    width, height = image.size
 
    # Assuming the stripes are vertical and evenly spaced
    stripe_count = 13
    stripe_width = width // stripe_count
 
    colors = []
    
    # Sample the middle pixel of each stripe to get the color
    for i in range(stripe_count):
        pixel = image.getpixel((i * stripe_width + stripe_width // 2, height // 2))
        colors.append(pixel)
 
    # Convert RGB to hex
    hex_colors = ['{:02x}{:02x}{:02x}'.format(r, g, b) for r, g, b in colors]
    return ''.join(hex_colors)
 
def hex_to_ascii(hex_string):
    bytes_object = bytes.fromhex(hex_string)
    ascii_string = bytes_object.decode("utf-8")
    return ascii_string
 
# Example usage
image_path = 'your_image_path_here.png'  # Replace with your actual image path
hex_string = get_hex_from_image(image_path)
print(f"Concatenated Hex String: {hex_string}")
 
# Convert the hex string to ASCII
try:
    flag = hex_to_ascii(hex_string)
    print(f"Decoded ASCII String (Flag): {flag}")
except:
    print("Could not decode the hex string to ASCII. Please check the hex input.")

Flag: flag{586cf8c849c9730ea7b2112fff39ff6a}

For any work-related inquiries, please email me at vipin@vipin.xyz. If you want to chat with me, feel free to drop me a message on Discord