昨天Jenkins发布了安全公告,修复了几个漏洞,其中有一个 CVE-2019-10352,绕过了文件名的的限制,导致任意文件写入。但是需要Job/Configure权限(没啥用)。说是问题出在file parameter definition的地方。
Users with Job/Configure permission could specify a relative path escaping the base directory in the file name portion of a file parameter definition. This path would be used to store the uploaded file on the Jenkins master, resulting in an arbitrary file write vulnerability.
而且说是bypass了之前对前面的一个漏洞CVE-2018-1000406
但是我不知道这个file parameter是什么,于是google搜了一下"jenkins file parameter",找到这个youtube教程 中文的形式是这样的: 参数化构建过程=》Add Parameter=》文件参数 (这次我才明白了原来jenkins隐藏着那么多参数,需要你在对应的选项上打勾,才能显示出更多。) 这个功能的说明可以参考这个 https://wiki.jenkins.io/display/JENKINS/Parameterized+Build
File parameter allows a build to accept a file, to be submitted by the user when scheduling a new build. The file will be placed inside the workspace at the known location after the check-out/update is done, so that your build scripts can use this file.
即发起构建(build)操作的时候,将这个文件名作为参数传进去。在check-out/update步骤之后,这个文件随后会被放到公共空间的一个已知的位置,这样构建脚本就可以使用这个文件了。
这样添加了文件参数之后,果然到了断点了
刚才只是指定了文件名,我开始以为是被上传的文件。原来是上传后放在这个路径下。 打开刚才配置的那个job里,选择Build with Parameters 原来选择上传文件在这个地方 POC大概长这样 然而并没有成功 还是太Naive, 看这个文件: https://github.com/jenkinsci/jenkins/blob/dedde6195362b4aeae75f8a147cdf263b2f9854b/test/src/test/java/hudson/model/FileParameterValueTest.java 这个文件里既有对新补丁SECURITY-1424的修复验证,
@Test @Issue("SECURITY-1424") public void fileParameter_cannotCreateFile_outsideOfBuildFolder_SEC1424() throws Exception { // you can test the behavior before the correction by setting FileParameterValue.ALLOW_FOLDER_TRAVERSAL_OUTSIDE_WORKSPACE to true FilePath root = j.jenkins.getRootPath(); FreeStyleProject p = j.createFreeStyleProject(); p.addProperty(new ParametersDefinitionProperty(Collections.singletonList( new FileParameterDefinition("dir/../../../pwned", null) ))); assertThat(root.child("pwned").exists(), equalTo(false)); String uploadedContent = "test-content"; File uploadedFile = tmp.newFile(); FileUtils.write(uploadedFile, uploadedContent); FreeStyleBuild build = p.scheduleBuild2(0, new Cause.UserIdCause(), new ParametersAction( new FileParameterValue("dir/../../../pwned", uploadedFile, "uploaded-file.txt") )).get(); assertThat(build.getResult(), equalTo(Result.FAILURE)); assertThat(root.child("pwned").exists(), equalTo(false)); // ensure also the file is not reachable by request JenkinsRule.WebClient wc = j.createWebClient(); wc.getOptions().setThrowExceptionOnFailingStatusCode(false); }还有对SECURITY-1074,即CVE-2018-1000406对补丁修复之后的验证
@Test @Issue("SECURITY-1074") public void fileParameter_cannotCreateFile_outsideOfBuildFolder() throws Exception { // you can test the behavior before the correction by setting FileParameterValue.ALLOW_FOLDER_TRAVERSAL_OUTSIDE_WORKSPACE to true FilePath root = j.jenkins.getRootPath(); FreeStyleProject p = j.createFreeStyleProject(); p.addProperty(new ParametersDefinitionProperty(Collections.singletonList( new FileParameterDefinition("../../../../../root-level.txt", null) ))); assertThat(root.child("root-level.txt").exists(), equalTo(false)); String uploadedContent = "test-content"; File uploadedFile = tmp.newFile(); FileUtils.write(uploadedFile, uploadedContent); FreeStyleBuild build = p.scheduleBuild2(0, new Cause.UserIdCause(), new ParametersAction( new FileParameterValue("../../../../../root-level.txt", uploadedFile, "uploaded-file.txt") )).get(); assertThat(build.getResult(), equalTo(Result.FAILURE)); assertThat(root.child("root-level.txt").exists(), equalTo(false)); // ensure also the file is not reachable by request JenkinsRule.WebClient wc = j.createWebClient(); wc.getOptions().setThrowExceptionOnFailingStatusCode(false); checkUrlNot200AndNotContains(wc, build.getUrl() + "parameters/parameter/../../../../../root-level.txt/uploaded-file.txt", uploadedContent); // encoding dots checkUrlNot200AndNotContains(wc, build.getUrl() + "parameters/parameter/../../../../../root-level.txt/uploaded-file.txt", uploadedContent); // 16-bit encoding checkUrlNot200AndNotContains(wc, build.getUrl() + "parameters/parameter/%u002e%u002e%u2215%u002e%u002e%u2215%u002e%u002e%u2215%u002e%u002e%u2215%u002e%u002e%u2215root-level.txt/uploaded-file.txt", uploadedContent); // double encoding checkUrlNot200AndNotContains(wc, build.getUrl() + "parameters/parameter/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2froot-level.txt/uploaded-file.txt", uploadedContent); // overlong utf-8 encoding checkUrlNot200AndNotContains(wc, build.getUrl() + "parameters/parameter/