QnQSec CTF 2025 Writeup
A Deep Dive into OSINT and Firmware Analysis
 CTF Challenges
CTF ChallengesI had the opportunity to participate in qnqsec ctf 2025 playing with team 51l3nt_br34ch . i did several challenges but among them all the osint challenges were the most cool and thats why i will write how i solved them.
1. The company
 

looking onto the description i saw the name chloe stekar and the image provided seems like a tweet so we had to go to X formally twitter. and we got the exact tweet under her account.
boom the company name as requested.
 
 the flag was clear as day
the flag was clear as day QnQSec{QnQ Corps}
but before we go lets crawl a bit to this account and see what else can we uncover.


First we got this image where the badge points to a position: Market Lead and Employee since 1990.
In another post there’s a link (as alt text in an image.
``
https://drive.proton.me/urls/MT3F5GABY8#nQ2rWPt3Vuas
 and going to the link we got this account which needed password and we dont have so lets continue scavenging.
We got something juicy here ‘still on x’ we got a direct link to their account on medium.
and going to the link we got this account which needed password and we dont have so lets continue scavenging.
We got something juicy here ‘still on x’ we got a direct link to their account on medium.
 

After looking through the site we got onother employee from the company thats progress.

This nigga is a Senior Java Developer at QnQ Corps
So we have two people from the company, plus the official account. ==laughs==
so first now lets now follow the format of the challenges
2 The picture
 i reverse image searched the image and i had an it from this website and boom there it was.
i reverse image searched the image and i had an it from this website and boom there it was.

and then we had our flag,
credits to my teammate mockingspectre for the idea for this champ.
3 The Company’s channel
 I did a quick search and then got three accounts for this company
I did a quick search and then got three accounts for this company
https://www.linkedin.com/company/qnq-corps  
https://www.youtube.com/@qnqcorps  
https://x.com/qnqcorps
From the links one was a youtube channel and there it was the email but its not what we needed.
I did a google dork and i got a wordpress website and there it was boom the flag.
 

so while in the website i crawled to see if i can find anything useful we can use in the coming challenges and i got various tips.
First item on the site: a Telegram bot
https://t.me/QnQCorps2Bot
From the bot I got this Google Doc:
https://docs.google.com/document/d/1DnS2OhLUfLPA29pyyNTOGRrH4iMX08qjn8Q5rxjLxhU/edit?tab=t.0

i tried finding anything on this doc but i tried to request an edit and there it was onother person from the company.
 now we had several people from the company.
now we had several people from the company.
Ming Mulang -- mulangming81@gmail.com 
Chloe Stekar  (marketing)
Alfred Dantre  (java dev)
QnQ Corps (official account)
4.The Company’s Money

here we start earning from our previous notes and outcomes
WordPress often associates author profiles with Gravatar, a globally recognized avatar service
and Gravatar works like this
https://gravatar.com/avatar/HASH
we had an email we got from youtube and we use it
qnq.corps@gmail.com

then i used the hash and boom i got the name and also the flag
 and we got onother tip also so we not it down.
and we got onother tip also so we not it down.
Tomas Frestkin == Head of Finance department,
i solveed those on osint ihad alittle time but with the solved challenges i learned something.
Then this are few apart from the osint i solved not all but those interesting.
SmartCoffee Firmware Analysis
Challenge Description
The challenge involved investigating a firmware image (firmware_x86.elf) and associated logs (logs.txt) for a SmartCoffee device to find a hidden flag in the format QnQsec{}.
Initial Examination
First, the provided files were examined to understand their nature.
firmware_x86.elf
The file command was used to identify the type of the firmware image:
file /home/ubuntu/firmware_x86.elf
Output:
ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=20de7fc4732ba9cd132a125b037dfb36c1e38c3c, for GNU/Linux 3.2.0, stripped
This indicated that the firmware was an x86-64 ELF executable.
An initial attempt to find the flag using strings and grep proved unsuccessful,yielded no results for the flag format:
sudo apt-get update && sudo apt-get install -y binutils
strings /home/ubuntu/firmware_x86.elf | grep 'QnQsec{'
binwalk was also used to check for embedded file systems or other interesting structures, but it only identified the ELF header:
sudo apt-get update && sudo apt-get install -y binwalk
binwalk /home/ubuntu/firmware_x86.elf
Output:
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ELF, 64-bit LSB shared object, AMD x86-64, version 1 (SYSV)
logs.txt
The logs.txt file contained boot-up messages and device information. Key lines observed were:
Booting SmartCoffee v1.2 (build 2025-10-15)
CPU: ARM Cortex-M4 r0p1
eeprom: reading primary image (addr=0x0000, len=8192)
eeprom: checksum 0x4f2a
Device Serial: SC-01-ABC123
Notably, the logs indicated an ARM Cortex-M4 CPU despite the firmware being an x86-64 ELF executable. This suggested that the provided firmware_x86.elf might be a diagnostic or emulation tool rather than the actual ARM firmware, or a wrapper for some embedded data. The eeprom: checksum 0x4f2a entry was also noted as a potential key for obfuscation.
Executing the Firmware
Since the firmware_x86.elf was an executable, it was given execute permissions and run:
chmod +x /home/ubuntu/firmware_x86.elf
/home/ubuntu/firmware_x86.elf
The execution produced the following output:
=== SmartCoffee v1.2 ===
Initializing ADC... OK
I2C devices found: 2
Loading EEPROM... OK
Device Serial: SC-01-ABC123
EEPROM DUMP (raw):
95 aa 95 97 a1 a7 bf f7 
bc 9b b7 f7 b7 aa b1 a9 
9b a7 f0 aa 9b a0 f4 9b 
ac f0 b6 a0 b3 f0 b6 f7 
b9 
(Note: bytes are likely obfuscated.)
Entering diagnostic loop...
diag_ok
diag_ok
diag_ok
The most critical piece of information here was the EEPROM DUMP (raw), explicitly stating that the bytes are
likely obfuscated. This confirmed the need for a decryption or deobfuscation step.
Deobfuscation and Flag Extraction
The EEPROM dump was provided as a series of hexadecimal bytes:
95 aa 95 97 a1 a7 bf f7 bc 9b b7 f7 b7 aa b1 a9 9b a7 f0 aa 9b a0 f4 9b ac f0 b6 a0 b3 f0 b6 f7 b9
The logs.txt file mentioned an eeprom: checksum 0x4f2a. This checksum was a strong candidate for an XOR key, especially since the EEPROM DUMP explicitly stated that the bytes were obfuscated.
First, I converted the hex dump to raw bytes using xxd -r -p:
echo "95 aa 95 97 a1 a7 bf f7 bc 9b b7 f7 b7 aa b1 a9 9b a7 f0 aa 9b a0 f4 9b ac f0 b6 a0 b3 f0 b6 f7 b9" | xxd -r -p
The output was unreadable, as expected.
Next, I tried XORing the raw bytes with parts of the checksum 0x4f2a. I started by trying a single-byte XOR with 0x2a and 0x4f, but these did not yield a readable string.
Recognizing that the flag format is QnQsec{}, I hypothesized that the obfuscation might be a simple XOR cipher with a repeating key. I used the beginning of the expected flag format, QnQsec{, to derive the XOR key. By XORing the first few bytes of the EEPROM dump with QnQsec{, I could find a repeating pattern for the key.
Let D be the EEPROM dump bytes and F be the flag prefix QnQsec{.
Key_candidate = D[i] ^ F[i]
import sys
data_hex = "95 aa 95 97 a1 a7 bf f7 bc 9b b7 f7 b7 aa b1 a9 9b a7 f0 aa 9b a0 f4 9b ac f0 b6 a0 b3 f0 b6 f7 b9"
data_bytes = bytes.fromhex(data_hex.replace(" ", ""))
flag_prefix = b'QnQsec{'
key_candidate_bytes = bytes([data_bytes[i] ^ flag_prefix[i] for i in range(len(flag_prefix))])
print(key_candidate_bytes)
This Python snippet was executed in the shell:
echo "95 aa 95 97 a1 a7 bf f7 bc 9b b7 f7 b7 aa b1 a9 9b a7 f0 aa 9b a0 f4 9b ac f0 b6 a0 b3 f0 b6 f7 b9" | xxd -r -p | python3 -c "import sys; data = sys.stdin.buffer.read(); flag_prefix = b'QnQsec{'; key_candidate = bytes([data[i] ^ flag_prefix[i] for i in range(len(flag_prefix))]); print(key_candidate)"
Output:
b'\xc4\xc4\xc4\xe4\xc4\xc4\xc4'
This revealed a repeating key pattern, primarily 0xc4. The slight deviation (0xe4) might be due to the c in QnQsec or an error in my assumption of the key length. However, the consistent 0xc4 suggested a single-byte XOR key. I proceeded to XOR the entire EEPROM dump with 0xc4.
echo "95 aa 95 97 a1 a7 bf f7 bc 9b b7 f7 b7 aa b1 a9 9b a7 f0 aa 9b a0 f4 9b ac f0 b6 a0 b3 f0 b6 f7 b9" | xxd -r -p | python3 -c "import sys; data = sys.stdin.buffer.read(); print(\'\'.join(chr(b ^ 0xc4) for b in data))"
The result was the flag:
QnQSec{3x_s3snum_c4n_d0_h4rdw4r3}
Flag
QnQSec{3x_s3snum_c4n_d0_h4rdw4r3}
Conclusion
This challenge involved a combination of static and dynamic analysis of a provided firmware image and log files. The key to solving it was identifying the obfuscated EEPROM dump, recognizing the XOR cipher, and then deriving the XOR key by leveraging the known flag format prefix. The discrepancy between the CPU architecture mentioned in the logs and the provided firmware binary was a red herring, with the x86 executable serving as a diagnostic tool to reveal the obfuscated data.
Happy HackinG
