Screenshot_20260712_143021

Disclaimer

This walkthrough is for educational purposes only. All activities were performed on legally authorised TryHackMe systems.

Initial Reconnaissance

I scanned the IP with Nmap using this command:

sudo nmap --top-ports 500 -sV 10.81.173.106

Command explained:

  • --top-ports 500 — scan the 500 most common ports
  • -sV — service version detection

While the scan was running, I decided to check if there was a website running. There was.

Screenshot_20260712_145704

I started exploring the site and found a page called Host Manager, which had a login on it. Interesting. I looked around more but found nothing else, so I went back to check my Nmap results.

Nmap_Scan

Digging Into Open Ports

Port 22 is running SSH version OpenSSH 7.2p2, so I looked for known vulnerabilities and found CVE-2018-15473, a race-condition-based username enumeration bug. I’ve had a bad experience with this one before, and it didn’t seem useful here either, so I moved on.

The next thing I had was Apache JServ running on port 8009. I had no idea what it was, and this was also my first time dealing with Apache Tomcat, so I decided to read up on it:

Apache Tomcat is a Java application server that executes Java code like JSP files and servlets to generate responses for HTTP requests. It has a Manager panel used to manage applications deployed on the server.

Apache JServ Protocol (AJP13) is a protocol Tomcat uses to listen for requests from services like web servers and load balancers. It’s typically not meant to be exposed directly to the internet.

So port 8009, running AJP, was a security misconfiguration by itself. I researched further and found it was vulnerable to CVE-2020-1938: Ghostcat. This vulnerability lets attackers read hidden files, and sometimes take full control of a server, by abusing Tomcat’s AJP connector.

Chasing Ghostcat (CVE-2020-1938)

I picked an exploit off GitHub to test it out:

GitHub: Hancheng-Lei/Hacking-Vulnerability-CVE-2020-1938-Ghostcat

CVE2020-1938

After a few tweaks, I got it running, and it confirmed the vulnerability was real — I was able to read a protected file over Ghostcat/AJP. It returned actual file contents: the XML from WEB-INF/web.xml, including the Apache license and web app configuration. Time to look for juicier files.

Since WEB-INF/web.xml was readable, I figured other configuration files might be too. I made a list and went through them one by one:

  • WEB-INF/application.properties — Spring Boot application configuration
  • WEB-INF/context.xml — Tomcat context configuration
  • META-INF/context.xml — application metadata configuration
  • WEB-INF/spring-security.xml — Spring Security configuration (authentication)
  • WEB-INF/faces-config.xml — JSF (Java web framework) configuration
  • WEB-INF/application.yml — Spring Boot YAML configuration
  • WEB-INF/db.properties — database connection properties
  • WEB-INF/database.properties — database credentials/config
  • conf/tomcat-users.xml — Tomcat Manager credentials (logical guess, but AJP couldn’t reach it)

Guess how many I found. If you guessed zero, you’re right. Every single one came back HTTP 500 — FileNotFoundException. Was I hallucinating this whole vulnerability? What if the tool wasn’t working right? Metasploit has a module for Ghostcat too, so I ran that to sanity-check myself:

Ghostcat_Metasploit

The Metasploit scan confirmed the tool was working fine. It was me screwing something up, and I couldn’t figure out what.

While I was at it, I also tried the Metasploit Tomcat Manager brute-force module:

Tomcat_Login_Bruteforce

It ran through a list of default and weak passwords for Tomcat Manager, but every single one was wrong. Dead end.

Backtracking: Tomcat Manager’s Default Creds

I went back and reopened the site, and remembered the Host Manager login page from earlier. I tried a few passwords, failed, and got a 401 — Unauthorised message.

Screenshot_20260712_160037

Very odd error message for a login page. On a whim, I tried the exact username and password shown on the page itself, and it worked.

Screenshot_20260712_160346

I WAS IN. I sat there a little dumbfounded — I had a demo-looking username and password staring at me the whole time, and instead I went and brute-forced Tomcat Manager and chased Ghostcat down a hole. But that’s cybersecurity for you.

A dead end on path X isn’t a failure; it’s just the map telling you it’s time to unlock path Y. — me

Getting a Shell: WAR File Upload

Now that I was in, the way forward was simple: drop a reverse shell as a .WAR (Web Application Resource), set up a listener, trigger the payload, and get a shell.

I first generated a Java web-based reverse shell with revshells.com and uploaded it:

shellin

Deployed it, triggered it…

shellnotworking

Nothing. No time to debug it. I deleted the file from the server and generated a fresh payload with msfvenom instead:

Screenshot_20260712_141407

New payload, new listener. Deployed it, and boom — got a reverse shell.

image

Found the user flag. Now it’s time for root.

Privilege Escalation: Writable Cronjob Script

I checked the user’s home directory and looked at file permissions:

ls -la
total 48
drwxr-xr-x 4 jack jack 4096 Aug 23  2019 .
drwxr-xr-x 3 root root 4096 Aug 14  2019 ..
-rw------- 1 root root 1476 Aug 14  2019 .bash_history
-rw-r--r-- 1 jack jack  220 Aug 14  2019 .bash_logout
-rw-r--r-- 1 jack jack 3771 Aug 14  2019 .bashrc
drwx------ 2 jack jack 4096 Aug 14  2019 .cache
-rwxrwxrwx 1 jack jack   26 Aug 14  2019 id.sh
drwxrwxr-x 2 jack jack 4096 Aug 14  2019 .nano
-rw-r--r-- 1 jack jack  655 Aug 14  2019 .profile
-rw-r--r-- 1 jack jack    0 Aug 14  2019 .sudo_as_admin_successful
-rw-r--r-- 1 root root   39 Jul 12 01:47 test.txt
-rw-rw-r-- 1 jack jack   33 Aug 14  2019 user.txt
-rw-r--r-- 1 root root  183 Aug 14  2019 .wget-hsts

Two things jumped out: id.sh is world-writable (rwxrwxrwx), and test.txt is owned by root with a timestamp from just a few hours ago, not 2019 like everything else. That combination screamed cronjob to me — something running as root, on a schedule, was touching this directory, and id.sh was fair game to overwrite.

I tested the theory with something simple:

echo "cat /root/root.txt > /home/jack/root_flag.txt" > id.sh

I waited for the next run.

image

Root flag found.

Key Takeaways

Takeaway Explanation
A working exploit isn’t a guaranteed path Ghostcat was real and confirmed by Metasploit, but the box just wasn’t giving up files through it. Verify the tool works, then know when to stop forcing it
Read every message on the page A 401 error that displays the exact credentials to use is not subtle. Don’t overlook what’s already handed to you while chasing harder exploits
Timestamps are a signal A file owned by root that was modified minutes ago, sitting next to files from 2019, is a strong hint something is running on a schedule
World-writable files near root-owned ones = cronjob privesc id.sh being rwxrwxrwx while sitting next to a freshly-touched root file was the giveaway. Always check permissions and timestamps together

Thanks for reading. Happy hacking.