Page cover

Nullcon HackIM CTF 2025

Hey, fellow hackers! 🏴‍☠️

In this writeup 📝, I’ll break down some of the exciting challenges solved by myself and my squad P4rad0x in the Nullcon HackIM CTF 2025.

Reversing

Scrambled - 50

Challenge Description

In this challenge, I was given a Python script (main.py) that encrypts a flag using XOR and shuffling. A scrambled hex output containing the encrypted flag.

Our goal❓ Recover the original flag!.

Looking at main.py, we can break down the encryption process:

XOR Encoding:

  • Each character of the flag is XORed with a single-byte key.

  • This converts the flag into a scrambled list of integers.

Chunking and Shuffling:

  • The encrypted data is split into chunks of 4 bytes.

  • A random seed (0-10) is used to shuffle the chunks.

  • The shuffled bytes are then converted to hex and printed as the output.

I was given this scrambled hex output:

To undo the encryption, I needed to reverse each step:

Convert Hex to Bytes

  • The scrambled hex string is converted back into a list of numbers.

Brute-force the Shuffling Seed

  • Since the seed used for shuffling is between 0 and 10, I can try all possible seeds to reverse the shuffle order.

  • I reconstruct the original order by checking all possible shuffled indices.

Recover the XOR Key

  • Since flags typically follow a format like "ENO{", I can use known plaintext attack to determine the XOR key.

  • Compare "ENO{" with the first 4 decrypted characters to derive the key.

Apply XOR Decryption

  • Once the key is found, XOR it with all the scrambled bytes to reveal the flag.

When executing dec.py, it successfully reverses the shuffle, finds the XOR key, and decrypts the flag! 🎉

ENO{5CR4M83L3D_3GG5_4R3_1ND33D_T45TY!!!}

Flag Checker - 50

Challenge Description

This challenge gave me a binary file—a simple program that asks for input and checks if it’s the correct flag. But instead of guessing, I need to dig into the code and find the flag myself. Let’s go! 🚀

First, I ran the file command to see what I was dealing with:

So, it’s a 64-bit ELF binary and stripped (which means no function names—just raw assembly).

Time to crack it open! 🔥

I loaded the binary into Ghidra—a software reverse engineering (SRE) framework and found the main function. Here's what it does:

  • Prompts for user input.

  • Passes the input to a flag-checking function.

Main Function
  • This function encrypts the user input and then compares it to a stored encrypted flag in the .rodata section.

And there it was—the encrypted flag hidden in memory. Here's the encryption logic :

Each byte of the input gets modified:

  • It adds the byte’s index to itself.

  • Then it XORs the result with 0x5A.

Bitwise shifts happen next:

  • The encrypted byte is shifted left by 3.

  • OR’ed with the same byte shifted right by 5.

Flag Check Function
Encryption Function

Now, I just needed to decrypt it!. I just had to reverse the process to get back the original flag!

Here's my Python script to decrypt the flag:

I ran the script, and… BOOM!💥

ENO{R3V3R53_3NG1N33R1NG_M45T3R!!!}

Web

Paginator - 50

Challenge Description

In this challenge, I had to use SQL injection techniques to uncover the hidden flag. Let’s dive in!

Clicking on the provided link took me to a paginated web application—a site that loads data in chunks instead of displaying everything at once.

I also noticed a "Source" button that led me to: http://52.59.124.14:5012/?source

Here, I found the source code of the backend, which was a crucial clue.

Source code

Reading through the code, I discovered an important detail:

🚨 The flag (id = 1) was restricted! 🚨

  • The site’s database had an "id" field where each entry had a unique number.

  • Direct access to id = 1 (the flag) was blocked—so I couldn’t just go to ?id=1.

  • However, there was a vulnerability in how the pagination feature handled input.

The pagination feature worked with two parameters:

But here’s the catch: the "max_items" value wasn’t properly validated.

I crafted a simple SQL injection payload:

  • 2,10 → Normal pagination parameters.

  • OR id=1 → A condition to forcefully retrieve the entry where id=1 (which contains the flag).

By entering this into the URL: http://52.59.124.14:5012/?p=2,10%20OR%20id=1

Boom! 💥 After decoding got the flag!

Flag

ENO{SQL1_W1th_0uT_C0mm4_W0rks_SomeHow!}

Misc

Profound Thought - 50

Challenge Description

This challenge gave me a PNG image file, there was something hidden inside. But where? How?

First things first, I ran the usual checks:

🛠 exiftool – Nothing suspicious in the metadata. 🛠 file command – Just a regular JPG file.

No hidden comments, no strange data, just a plain old image. Since metadata didn’t give me anything, I turned to a more powerful tool: zsteg.

Zsteg is also a tool used to detect LSB steganography only in the case of PNG and BMP images.

I ran:

Zsteg output

And BOOM! 💥 A flag appeared!

ENO{57394n09r4phy_15_w4y_c00l3r_7h4n_p0rn06r4phy}

USBnet - 50

Challenge Description

This one started with a pcapng file (a packet capture file) containing USB traffic. First step?

Wireshark—the go-to tool for network forensics!

Opening the file in Wireshark, I spotted several packets with NCMA and NCM0 identifiers. Looking deeper, I found the USB device that used for this capture was a Gigabit Ethernet adapter (AX88179) from ASIX Electronics Corp. Cool

Wireshark Capture

While scrolling through the packet list, I noticed something cool—a PNG file signature inside the hex data. That meant an image was hidden in the traffic!

Packet with PNG file signature

I grabbed the hex data of the packet containing the PNG signature and ran it through CyberChef.

CyberChef

💥 Boom! A QR code appeared!

Extracted QR

ENO{USB_ETHERNET_ADAPTER_ARE_COOL_N!C3}

Last updated