How I Solved THM: Thompson
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.
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.
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
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 configurationWEB-INF/context.xml— Tomcat context configurationMETA-INF/context.xml— application metadata configurationWEB-INF/spring-security.xml— Spring Security configuration (authentication)WEB-INF/faces-config.xml— JSF (Java web framework) configurationWEB-INF/application.yml— Spring Boot YAML configurationWEB-INF/db.properties— database connection propertiesWEB-INF/database.properties— database credentials/configconf/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:
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:
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.
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.
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:
Deployed it, triggered it…
Nothing. No time to debug it. I deleted the file from the server and generated a fresh payload with msfvenom instead:
New payload, new listener. Deployed it, and boom — got a reverse shell.
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.
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.