TryHackMe: Tomghost - Apache Ghostcat (CVE-2020-1938) Exploitation
Welcome to the Tomghost writeup! This TryHackMe room exploits Apache Ghostcat (CVE-2020-1938) - a critical vulnerability in the AJP connector of Apache Tomcat that allows an attacker to read arbitrary files from the server, often leaking credentials hidden in configuration files.
Let’s hack in.
Phase 1: Reconnaissance
Starting with a full Nmap scan to identify open ports and services:
1
nmap -sS -sC -p- -O -sV 10.48.180.35 -oN scan.txt
The scan revealed four open ports:
| Port | Service | Version |
|---|---|---|
| 22 | SSH | OpenSSH 7.2p2 Ubuntu |
| 53 | DNS | tcpwrapped |
| 8009 | AJP13 | Apache Jserv (Protocol v1.3) |
| 8080 | HTTP | Apache Tomcat 9.0.30 |
Port 8009 (AJP) immediately stands out - this is the attack vector for Ghostcat.
Browsing to port 8080 confirms a default Apache Tomcat 9.0.30 installation page.
A quick Gobuster scan on port 8080 found:
1
2
3
/docs (Status: 302) [--> /docs/]
/manager (Status: 302) [--> /manager/]
/examples (Status: 302) [--> /examples/]
Nothing exploitable here - the real entry point is AJP on port 8009.
Phase 2: Exploiting Ghostcat (CVE-2020-1938)
Apache Ghostcat is a file-read vulnerability in the AJP (Apache JServ Protocol) connector. AJP is meant for internal communication between a reverse proxy and Tomcat, but when exposed to the internet on port 8009, an attacker can read files from Tomcat’s webapps directory - including WEB-INF/web.xml which often contains sensitive credentials.
I used a publicly available Ghostcat exploit script to read the web.xml file:
1
python3 exploit.py -p 8009 -f /WEB-INF/web.xml 10.48.180.35
The exploit dumped the contents of web.xml, revealing credentials:
- Username:
skyfuck - Password: leaked in the XML output
Phase 3: Initial Access via SSH
With the leaked credentials, I logged in via SSH as skyfuck:
1
ssh skyfuck@10.48.180.35
In skyfuck’s home directory, I found two interesting files:
credential.pgp- a PGP-encrypted filetryhackme.asc- a PGP private key file
I also grabbed the user flag from /home/merlin/user.txt:
Phase 4: Cracking the GPG Key
The credential.pgp file is encrypted and needs the passphrase from tryhackme.asc to decrypt. First, I transferred the .asc file to my attack machine for cracking.
I imported the GPG key:
1
gpg --import tryhackme.asc
The key is passphrase-protected, so I used John the Ripper to crack it:
1
2
gpg2john tryhackme.asc > hash.txt
john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
John cracked the passphrase successfully. Now I could decrypt the PGP file:
1
gpg --output credential_dec --decrypt credential.pgp
This revealed merlin’s SSH password!
Phase 5: Lateral Movement & Privilege Escalation
I switched to user merlin using the decrypted credentials and checked sudo privileges:
1
2
su merlin
sudo -l
Merlin can run /usr/bin/zip as root without a password! A quick check on GTFOBins gives us the escalation path:
1
sudo zip /usr/bin/zip /etc/hosts -T -TT '/bin/sh #'
This spawns a root shell by abusing zip’s --test flag to execute arbitrary commands.
Rooted!
Attack Chain Summary
1
2
3
4
5
6
7
8
9
10
11
12
13
AJP Port 8009 Exposed
│
▼
Ghostcat (CVE-2020-1938) → Read /WEB-INF/web.xml
│
▼
Leaked SSH Credentials → Shell as skyfuck
│
▼
PGP Key Cracking (John) → merlin's Password
│
▼
sudo zip (GTFOBins) → Root Shell
Key Takeaways
- Never expose AJP (port 8009) to the internet. It should only be accessible internally.
- CVE-2020-1938 affects Tomcat versions < 9.0.31 - always keep services updated.
- PGP keys with weak passphrases are easily crackable with tools like John.
- Misconfigured sudo permissions (like
zipwithout password) are a direct path to root.
Happy Hacking!










