Good in study, attitude and health

Zimbra漏洞调试环境搭建

0x00 前言


本文记录从零开始搭建Zimbra漏洞调试环境的细节。

0x01 简介


本文将要介绍以下内容:

  • Zimbra服务器开启调试模式
  • 本地使用IDEA进行远程调试
  • 常用知识

0x02 Zimbra服务器开启调试模式


相关资料:

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

详细步骤如下:

1.停止Zimbra服务

su zimbra
zmcontrol stop

2.开启调试模式

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

此处先备份zmmailboxdmgr,再使用zmmailboxdmgr.unrestricted替换zmmailboxdmgr

3.添加调试信息

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"

注:

也可以直接修改/opt/zimbra/conf/localconfig.xml中的mailboxd_java_options属性值

4.关闭防火墙

sudo ufw disable

5.重启服务

zmcontrol start

0x03 本地使用IDEA进行远程调试


1.下载jar文件

本地使用IDEA进行远程调试时,本地和远程的代码需要保持一致,也就是说,我们需要拿到zimbra相关的jar文件

zimbra文件位置:

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

2.批量导入jar文件

新建java工程,依次选择File->Project Structure...,在Libraries下选择New Project Library->Java,设置为c:\zimbrajar\

3.添加断点

External Libraries->zimbrajar下面打开.class文件,在合适的位置添加断点

4.设置远程调试参数

顶部菜单栏选择Add Configuration...,在弹出的页面中选择Remote JVM Debug,填入远程调试参数,参数示例:

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

使用的JDK选择JDK 5-8

5.开启Debug模式

回到IDEA主页面,选择刚才的配置文件,点击Debug图标(快捷键Shift+F9)

如果远程调试执行成功,断点图标会发生变化,增加一个对号

此时,Console页面显示如下:

Connected to the target VM, address: '<host>:<port>', transport: 'socket'

0x04 常用知识


Zimbra使用Jetty框架作为web容器

用户在访问jsp文件时,服务器先将JVM不认识的JSP文件解析成java文件,保存路径为:/opt/zimbra/jetty_base/work/zimbra/jsp/org/apache/jsp/

每个jsp文件被成功访问后,都会注册一个JspServletWrapper实例,我们可以通过调试器查看request变量获得所有已注册的JspServletWrapper实例,也可以通过反射的方式以jsp文件的形式进行枚举

jsp文件代码示例:

<%@ 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() + "<br>"); 
    }  
%>

整个反射的逻辑来自于跟踪调试的结果,实现逻辑不唯一,枚举JspServletWrapper实例用到了ConcurrentHashMap枚举

0x05 小结


在我们搭建好Zimbra漏洞调试环境后,接下来就可以着手对漏洞和Jetty框架进行研究学习。


LEAVE A REPLY