Setting up Zimbra Vulnerability Debugging Environment

Onedaysec
3 min read
0 views
Setting up Zimbra Vulnerability Debugging Environment — One Day Sec default thumbnail

0x00 Preface

---

This article documents the details of building a Zimbra vulnerability debugging environment from scratch.

0x01 Introduction

---

This article will cover the following:

  • Enabling debug mode on Zimbra server
  • Remote debugging using IDEA locally
  • Common knowledge

0x02 Enabling Debug Mode on Zimbra Server

---

Reference materials:

https://github.com/Zimbra-Community/zimbra-tools/blob/master/java-debug-zimbra-intellij-ide.md

Detailed steps are as follows:

1. Stop Zimbra service

su zimbra
zmcontrol stop

2. Enable debug mode

su
cp /opt/zimbra/libexec/zmmailboxdmgr /opt/zimbra/libexec/zmmailboxdmgr.old
cp /opt/zimbra/libexec/zmmailboxdmgr.unrestricted /opt/zimbra/libexec/zmmailboxdmgr

First backup zmmailboxdmgr here, then replace zmmailboxdmgr with zmmailboxdmgr.unrestricted

3. Add debug information

su zimbra
zmlocalconfig -e mailboxd_java_options="`zmlocalconfig -m nokey mailboxd_java_options` -Xdebug -Xnoagent -Djava.compiler=NONE -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000"

Note:

You can also directly modify the mailboxd_java_options attribute value in /opt/zimbra/conf/localconfig.xml

4. Disable firewall

sudo ufw disable

5. Restart service

zmcontrol start

0x03 Local remote debugging using IDEA

---

1. Download jar files

When performing remote debugging locally using IDEA, the local and remote code must be consistent, meaning we need to obtain the zimbra-related jar files

Zimbra file locations:

  • /opt/zimbra/common/jetty_home/lib/
  • /opt/zimbra/common/jetty_home/lib/apache-jsp/

2. Batch import jar files

Create a new Java project, select File->Project Structure... in sequence, under Libraries choose New Project Library->Java, set it to c:\zimbrajar\

3. Add breakpoints

Open .class files under External Libraries->zimbrajar, add breakpoints at appropriate locations

4. Set remote debugging parameters

Select Add Configuration... from the top menu bar, choose Remote JVM Debug in the pop-up page, fill in the remote debugging parameters, parameter example:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000

Select JDK version 5-8 for the JDK used

5. Enable Debug mode

Return to the IDEA main interface, select the configuration file just created, and click the Debug icon (shortcut Shift+F9)

If remote debugging executes successfully, the breakpoint icon will change, adding a checkmark

At this point, the Console page displays the following:

Connected to the target VM, address: ':', transport: 'socket'

0x04 Common Knowledge

---

Zimbra uses the Jetty framework as its web container

When users access a JSP file, the server first parses the JSP file, which the JVM does not recognize, into a Java file, saved at the path: /opt/zimbra/jetty_base/work/zimbra/jsp/org/apache/jsp/

After each JSP file is successfully accessed, a JspServletWrapper instance is registered. We can view all registered JspServletWrapper instances by examining the request variable through the debugger, or enumerate them in the form of JSP files via reflection

JSP file code example:

<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.util.concurrent.ConcurrentHashMap" %>
<%@ page import="java.util.*" %>
<%
Field f = request.getClass().getDeclaredField("_scope");
f.setAccessible(true);
Object obj1 = f.get(request);
f = obj1.getClass().getDeclaredField("_servlet");
f.setAccessible(true);
Object obj2 = f.get(obj1);
f = obj2.getClass().getSuperclass().getDeclaredField("rctxt");
f.setAccessible(true);
Object obj3 = f.get(obj2);
f = obj3.getClass().getDeclaredField("jsps");
f.setAccessible(true);
ConcurrentHashMap obj4 = (ConcurrentHashMap)f.get(obj3);
Enumeration enu = obj4.keys();
while (enu.hasMoreElements()) {
out.println(enu.nextElement() + "
");
}
%>

The reflection logic originates from debugging and tracing results; the implementation logic is not unique. Enumerating JspServletWrapper instances utilizes ConcurrentHashMap enumeration.

0x05 Summary

---

After setting up the Zimbra vulnerability debugging environment, we can proceed to study and research the vulnerabilities and the Jetty framework.

Related Questions & Answers

Why is it necessary to replace `zmmailboxdmgr` with `zmmailboxdmgr.unrestricted` when setting up the debugging environment?

`zmmailboxdmgr` normally enforces resource limits and process protections that can prevent the JVM from starting with custom debug options. The unrestricted version removes these restrictions, allowing the JVM to accept remote debugging connections. This step is essential for enabling the JDWP agent required for remote debugging in a Zimbra vulnerability research setup.

Where does Zimbra store compiled JSP files and how can I enumerate them during debugging?

Zimbra uses Jetty as its web container, and compiled JSP files are stored under `/opt/zimbra/jetty_base/work/zimbra/jsp/org/apache/jsp/`. To enumerate all registered `JspServletWrapper` instances, you can use reflection on the request object to access the `_scope`, `_servlet`, `rctxt`, and `jsps` fields, then iterate through the `ConcurrentHashMap`. This technique is detailed in the "Common Knowledge" section of [Setting up Zimbra Vulnerability Debugging Environment](/news/setting-up-zimbra-vulnerability-debugging-environment).

How can I set up remote debugging of Zimbra using IntelliJ IDEA?

Copy the Zimbra jar files from the server (e.g., `/opt/zimbra/common/jetty_home/lib/`) to a local directory, import them into a new Java project in IDEA, add breakpoints to relevant classes, and configure a Remote JVM Debug run configuration with the same JDWP parameters (e.g., `-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000`). Start debugging with Shift+F9; a successful connection shows "Connected to the target VM".

How do I enable debug mode on a Zimbra server for vulnerability research?

To enable debug mode, stop Zimbra with `zmcontrol stop`, back up and replace `/opt/zimbra/libexec/zmmailboxdmgr` with the unrestricted version, then add JDWP options to `mailboxd_java_options` via `zmlocalconfig`, disable the firewall, and restart. This sets up a JDWP socket on port 8000 for remote debugging. For full details, see [Setting up Zimbra Vulnerability Debugging Environment](/news/setting-up-zimbra-vulnerability-debugging-environment).

Where are compiled JSP files stored in Zimbra, and how can I enumerate them for vulnerability analysis?

After a JSP file is accessed, Zimbra compiles it into a `.java` file stored under `/opt/zimbra/jetty_base/work/zimbra/jsp/org/apache/jsp/`. You can enumerate all registered `JspServletWrapper` instances using reflection on the request object, as shown in the article’s JSP code example. This technique leverages the `ConcurrentHashMap` that holds the compiled JSP wrappers and is useful for understanding the Jetty framework’s behavior. For related environment setups, see [Setting Up VMware vCenter Server Vulnerability Debugging Environment](/news/setting-up-vmware-vcenter-server-vulnerability-debugging-environment).

Why do I need to replace the zmmailboxdmgr file when enabling debug mode on Zimbra?

The `zmmailboxdmgr` script controls the JVM process and by default restricts debug options. Replacing it with the unrestricted version (`zmmailboxdmgr.unrestricted`) removes those restrictions, allowing the JVM to accept debugger connections. This step is essential for attaching a remote debugger like IDEA, as outlined in [Setting up Zimbra Vulnerability Debugging Environment](/news/setting-up-zimbra-vulnerability-debugging-environment).

How can I remotely debug a Zimbra vulnerability using IntelliJ IDEA?

First, ensure the local and remote Zimbra code are consistent by downloading the necessary jar files from `/opt/zimbra/common/jetty_home/lib/`. In IDEA, create a new Java project, import the jar files as a library, and set breakpoints in the relevant `.class` files. Configure a Remote JVM Debug run configuration with the JDWP agent string `-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000` and select JDK 5‑8. Launch the debug configuration; when connected, the console shows 'Connected to the target VM' and breakpoints become active. This process is part of the setup described in [Setting up Zimbra Vulnerability Debugging Environment](/news/setting-up-zimbra-vulnerability-debugging-environment).

How do I enable debug mode on a Zimbra server for vulnerability research?

To enable debug mode, first stop the Zimbra service with `zmcontrol stop`. Then back up `/opt/zimbra/libexec/zmmailboxdmgr` and replace it with `zmmailboxdmgr.unrestricted`. Add JVM debug options by running `zmlocalconfig -e mailboxd_java_options="... -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000"`. Disable the firewall with `sudo ufw disable` and restart the service. These steps are detailed in [Setting up Zimbra Vulnerability Debugging Environment](/news/setting-up-zimbra-vulnerability-debugging-environment).

Why is it important to keep local and remote code consistent during Zimbra remote debugging?

Consistency is crucial because the debugger matches breakpoints and variable information between the local IDE and the remote JVM. If JAR files differ, breakpoints may not trigger or may cause incorrect behavior, leading to unreliable debugging results. This ensures that the source code you inspect matches the actual executing bytecode on the server. --- **Related reading:** - [Setting up Zimbra Vulnerability Debugging Environment](/news/setting-up-zimbra-vulnerability-debugging-environment) — original article - [Penetration Techniques - Enabling Anonymous Access Shares on Windows Systems via Command Line](/news/penetration-techniques-enabling-anonymous-access-shares-on-windows-systems-via-command-line) - [Steganography Techniques - Hiding Payloads Using JPEG File Format](/news/steganography-techniques-hiding-payloads-using-jpeg-file-format) - [vRealize Log Insight Vulnerability Debugging Environment Setup](/news/vrealize-log-insight-vulnerability-debugging-environment-setup)

How does Zimbra process JSP files and how can you enumerate JspServletWrapper instances?

Zimbra uses the Jetty framework as its web container. When a JSP is requested, the server compiles it into a Java file stored under /opt/zimbra/jetty_base/work/zimbra/jsp/. Each compiled JSP registers a JspServletWrapper instance in a ConcurrentHashMap. You can enumerate these instances via reflection by accessing the request's _scope, then _servlet, rctxt, and finally the jsps field to iterate over keys. --- **Related reading:** - [Setting up Zimbra Vulnerability Debugging Environment](/news/setting-up-zimbra-vulnerability-debugging-environment) — original article - [Penetration Techniques - Enabling Anonymous Access Shares on Windows Systems via Command Line](/news/penetration-techniques-enabling-anonymous-access-shares-on-windows-systems-via-command-line) - [Steganography Techniques - Hiding Payloads Using JPEG File Format](/news/steganography-techniques-hiding-payloads-using-jpeg-file-format) - [vRealize Log Insight Vulnerability Debugging Environment Setup](/news/vrealize-log-insight-vulnerability-debugging-environment-setup)

Continue Reading