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框架进行研究学习。