Goal Reached Thanks to every supporter — we hit 100%!

Goal: 1000 CNY · Raised: 1000 CNY

100.0%

CVE-2018-1002201 PoC — zt-zip 路径遍历漏洞

Source
Associated Vulnerability
Title:zt-zip 路径遍历漏洞 (CVE-2018-1002201)
Description:zt-zip是一个用于压缩/解压缩的库。 zt-zip 1.13之前版本中存在目录遍历漏洞。攻击者可借助带有目录遍历名称的特制的zip归档文件利用该漏洞写入任意文件。
Readme
ZIP - convenience methods
=========================

### Continuous Integration 
[![Build Status](https://travis-ci.org/zeroturnaround/zt-zip.png)](https://travis-ci.org/zeroturnaround/zt-zip)

### Quick Overview

The project was started and coded by Rein Raudjärv when he needed to process a large set of large ZIP archives for
LiveRebel internals. Soon after we started using the utility in other projects because of the ease of use and it
*just worked*.

The project is built using java.util.zip.* packages for stream based access. Most convenience methods for filesystem
usage is also supported.

### Installation
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.zeroturnaround/zt-zip/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.zeroturnaround/zt-zip)

The project artifacts are available in [Maven Central Repository](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22zt-zip%22).
To include it in your maven project then you have to specify the dependency.

```xml
...
<dependency>
    <groupId>org.zeroturnaround</groupId>
    <artifactId>zt-zip</artifactId>
    <version>1.11</version>
    <type>jar</type>
</dependency>
...
```

Notice that [1.8](https://oss.sonatype.org/content/repositories/releases/org/zeroturnaround/zt-zip/1.8/) is the last Java 1.4 compatible release. 
Since then Java 1.5 is required.

## Background

We had the following functional requirements:

1. pack and unpack directories recursively
  1. include/exclude entries
  2. rename entries
  3. packing/unpacking in place - ZIP becomes directory and vice versa
2. iterate through ZIP entries
3. add or replace entries from files or byte arrays
4. transform ZIP entries
5. compare two archives - compare all entries ignoring time stamps

and these non-functional requirements:

1. use existing APIs as much as possible
2. be simple to use
3. be effective to use - do not traverse an entire ZIP file if only a single entry is needed
4. be safe to use - do not enable user to leave streams open and keep files locked
5. do not declare exceptions
6. be compatible with Java 1.5

## Examples

### Unpacking

#### Check if an entry exists in a ZIP archive
```java
boolean exists = ZipUtil.containsEntry(new File("/tmp/demo.zip"), "foo.txt");
```

#### Extract an entry from a ZIP archive into a byte array
```java
byte[] bytes = ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt");
```

#### Extract an entry from a ZIP archive with a specific Charset into a byte array
```java
byte[] bytes = ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt", Charset.forName("IBM437"));
```

#### Extract an entry from a ZIP archive into file system
```java
ZipUtil.unpackEntry(new File("/tmp/demo.zip"), "foo.txt", new File("/tmp/bar.txt"));
```

#### Extract a ZIP archive
```java
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"));
```

#### Extract a ZIP archive which becomes a directory
```java
ZipUtil.explode(new File("/tmp/demo.zip"));
```

#### Extract a directory from a ZIP archive including the directory name
```java
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
  public String map(String name) {
    return name.startsWith("doc/") ? name : null;
  }
});
```

#### Extract a directory from a ZIP archive excluding the directory name
```java
final String prefix = "doc/"; 
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
  public String map(String name) {
    return name.startsWith(prefix) ? name.substring(prefix.length()) : name;
  }
});
```

#### Extract files from a ZIP archive that match a name pattern
```java
ZipUtil.unpack(new File("/tmp/demo.zip"), new File("/tmp/demo"), new NameMapper() {
  public String map(String name) {
    if (name.contains("/doc")) {
      return name;
    }
    else {
      // returning null from the map method will disregard the entry
      return null;
    }
  }
});
```

#### Print .class entry names in a ZIP archive
```java
ZipUtil.iterate(new File("/tmp/demo.zip"), new ZipInfoCallback() {
  public void process(ZipEntry zipEntry) throws IOException {
    if (zipEntry.getName().endsWith(".class"))
      System.out.println("Found " + zipEntry.getName());
  }
});
```

#### Print .txt entries in a ZIP archive (uses IoUtils from Commons IO)
```java
ZipUtil.iterate(new File("/tmp/demo.zip"), new ZipEntryCallback() {
  public void process(InputStream in, ZipEntry zipEntry) throws IOException {
    if (zipEntry.getName().endsWith(".txt")) {
      System.out.println("Found " + zipEntry.getName());
      IOUtils.copy(in, System.out);
    }
  }
});
```

### Packing

#### Compress a directory into a ZIP archive
```java
ZipUtil.pack(new File("/tmp/demo"), new File("/tmp/demo.zip"));
```

#### Compress a directory which becomes a ZIP archive
```java
ZipUtil.unexplode(new File("/tmp/demo.zip"));
```

#### Compress a directory into a ZIP archive with a parent directory
```java
ZipUtil.pack(new File("/tmp/demo"), new File("/tmp/demo.zip"), new NameMapper() {
  public String map(String name) {
    return "foo/" + name;
  }
});
```

#### Add an entry from file to a ZIP archive
```java
ZipUtil.addEntry(new File("/tmp/demo.zip"), "doc/readme.txt", new File("f/tmp/oo.txt"), new File("/tmp/new.zip"));
```

#### Add an entry from byte array to a ZIP archive
```java
ZipUtil.addEntry(new File("/tmp/demo.zip"), "doc/readme.txt", "bar".getBytes(), new File("/tmp/new.zip"));
```

#### Add an entry from file and from byte array to a ZIP archive
```java
ZipEntrySource[] entries = new ZipEntrySource[] {
    new FileSource("doc/readme.txt", new File("foo.txt")),
    new ByteSource("sample.txt", "bar".getBytes())
};
ZipUtil.addEntries(new File("/tmp/demo.zip"), entries, new File("/tmp/new.zip"));
```

#### Add an entry from file and from byte array to a output stream
```java
ZipEntrySource[] entries = new ZipEntrySource[] {
    new FileSource("doc/readme.txt", new File("foo.txt")),
    new ByteSource("sample.txt", "bar".getBytes())
};
OutputStream out = null;
try {
  out = new BufferedOutputStream(new FileOutputStream(new File("/tmp/new.zip")));
  ZipUtil.addEntries(new File("/tmp/demo.zip"), entries, out);
}
finally {
  IOUtils.closeQuietly(out);
}
```

#### Replace a ZIP archive entry from file 
```java
boolean replaced = ZipUtil.replaceEntry(new File("/tmp/demo.zip"), "doc/readme.txt", new File("/tmp/foo.txt"), new File("/tmp/new.zip"));
```

#### Replace a ZIP archive entry from byte array 
```java
boolean replaced = ZipUtil.replaceEntry(new File("/tmp/demo.zip"), "doc/readme.txt", "bar".getBytes(), new File("/tmp/new.zip"));
```

#### Replace a ZIP archive entry from file and byte array 
```java
ZipEntrySource[] entries = new ZipEntrySource[] {
    new FileSource("doc/readme.txt", new File("foo.txt")),
    new ByteSource("sample.txt", "bar".getBytes())
};
boolean replaced = ZipUtil.replaceEntries(new File("/tmp/demo.zip"), entries, new File("/tmp/new.zip"));
```

#### Add or replace entries in a ZIP archive
```java
ZipEntrySource[] addedEntries = new ZipEntrySource[] {
        new FileSource("/path/in/zip/File1.txt", new File("/tmp/file1.txt")),
        new FileSource("/path/in/zip/File2.txt", new File("/tmp/file2.txt")),
        new FileSource("/path/in/zip/File3.txt", new File("/tmp/file2.txt")),
    };
ZipUtil.addOrReplaceEntries(new File("/tmp/demo.zip"), addedEntries);
```

### Transforming

#### Transform a ZIP archive entry into uppercase
```java
boolean transformed = ZipUtil.transformEntry(new File("/tmp/demo"), "sample.txt", new StringZipEntryTransformer() {
    protected String transform(ZipEntry zipEntry, String input) throws IOException {
        return input.toUpperCase();
    }
}, new File("/tmp/demo.zip"));
```

### Comparison

#### Compare two ZIP archives (ignoring timestamps of the entries) 
```java
boolean equals = ZipUtil.archiveEquals(new File("/tmp/demo1.zip"), new File("/tmp/demo2.zip"));
```

#### Compare two ZIP archive entries with same name (ignoring timestamps of the entries) 
```java
boolean equals = ZipUtil.entryEquals(new File("/tmp/demo1.zip"), new File("/tmp/demo2.zip"), "foo.txt");
```

#### Compare two ZIP archive entries with different names (ignoring timestamps of the entries) 
```java
boolean equals = ZipUtil.entryEquals(new File("/tmp/demo1.zip"), new File("/tmp/demo2.zip"), "foo1.txt", "foo2.txt");
```

## Debugging

The library is using the [slf4j-api](http://www.slf4j.org/) logging framework. All the log statements are either **DEBUG** or **TRACE** level. Depending on the logging framework you are using a simple ```-Dorg.slf4j.simpleLogger.defaultLogLevel=debug``` or ```System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug");``` will do the trick of showing log statements from the **zt-zip** library. You can further fine tune the levels and inclusion of log messages per package with your logging framework.
File Snapshot

[4.0K] /data/pocs/2744a0d7582a9ba864e13cf2d509f288a939c992 ├── [1.3K] Changelog.txt ├── [2.5K] get_release_commands.sh ├── [ 11K] LICENSE ├── [ 752] NOTICE ├── [ 722] oss-release.sh ├── [5.7K] pom.xml ├── [8.7K] README.md └── [4.0K] src ├── [4.0K] main │   └── [4.0K] java │   └── [4.0K] org │   └── [4.0K] zeroturnaround │   └── [4.0K] zip │   ├── [2.4K] ByteSource.java │   ├── [1.0K] CloseShieldInputStream.java │   ├── [4.0K] commons │   │   ├── [1.7K] FileExistsException.java │   │   ├── [8.6K] FilenameUtils.java │   │   ├── [2.3K] FileUtils.java │   │   ├── [ 39K] FileUtilsV2_2.java │   │   ├── [ 16K] IOUtils.java │   │   └── [4.6K] StringBuilderWriter.java │   ├── [4.0K] extra │   │   ├── [ 10K] AsiExtraField.java │   │   ├── [5.6K] ExtraFieldUtils.java │   │   ├── [4.5K] UnrecognizedExtraField.java │   │   ├── [2.1K] ZipConstants.java │   │   ├── [2.8K] ZipExtraField.java │   │   ├── [5.4K] ZipLong.java │   │   └── [4.4K] ZipShort.java │   ├── [2.7K] FileSource.java │   ├── [1.0K] IdentityNameMapper.java │   ├── [2.7K] Java6FileApiPermissionsStrategy.java │   ├── [6.0K] Java7Nio2ApiPermissionsStrategy.java │   ├── [1.1K] NameMapper.java │   ├── [4.0K] timestamps │   │   ├── [1.5K] Java8TimestampStrategy.java │   │   ├── [1.0K] PreJava8TimestampStrategy.java │   │   ├── [1.6K] TimestampStrategyFactory.java │   │   └── [ 963] TimestampStrategy.java │   ├── [4.0K] transform │   │   ├── [1.8K] ByteArrayZipEntryTransformer.java │   │   ├── [2.1K] FileZipEntryTransformer.java │   │   ├── [1.3K] StreamZipEntryTransformer.java │   │   ├── [1.4K] StringZipEntryTransformer.java │   │   ├── [1.1K] ZipEntrySourceZipEntryTransformer.java │   │   ├── [ 603] ZipEntryTransformerEntry.java │   │   └── [ 804] ZipEntryTransformer.java │   ├── [ 264] ZipBreakException.java │   ├── [1.2K] ZipEntryCallback.java │   ├── [1014] ZipEntryOrInfoAdapter.java │   ├── [1.3K] ZipEntrySource.java │   ├── [6.4K] ZipEntryUtil.java │   ├── [ 281] ZipException.java │   ├── [ 242] ZipExceptionUtil.java │   ├── [4.9K] ZipFileUtil.java │   ├── [1.2K] ZipInfoCallback.java │   ├── [ 22K] Zips.java │   ├── [ 95K] ZipUtil.java │   ├── [2.0K] ZTFilePermissions.java │   ├── [ 686] ZTFilePermissionsStrategy.java │   ├── [3.9K] ZTFilePermissionsUtil.java │   ├── [1.9K] ZTFileUtil.java │   └── [1.1K] ZTZipReflectionUtil.java └── [4.0K] test ├── [4.0K] java │   ├── [4.0K] example │   │   ├── [ 625] AddOrReplaceEntries.java │   │   ├── [1.2K] PackEntryExample.java │   │   ├── [1.2K] PackExample.java │   │   ├── [ 728] ReplaceEntryExample.java │   │   ├── [ 993] UnpackEntryExample.java │   │   └── [1.5K] UnpackExample.java │   └── [4.0K] org │   └── [4.0K] zeroturnaround │   └── [4.0K] zip │   ├── [5.6K] CharsetTest.java │   ├── [6.1K] FilePermissionsTest.java │   ├── [2.3K] FileSourceTest.java │   ├── [7.0K] MainExamplesTest.java │   ├── [ 730] SkipIfZipEntryFileTimeNotAvailableRule.java │   ├── [1.3K] ZipEntryUtilTest.java │   ├── [3.3K] ZipPreserveTimeStampJava8Test.java │   ├── [2.7K] ZipPreserveTimeStampTest.java │   ├── [ 24K] ZipsTest.java │   ├── [9.0K] ZipTransformTest.java │   ├── [1.5K] ZipUtilDirTest.java │   ├── [4.4K] ZipUtilInPlaceTest.java │   ├── [ 31K] ZipUtilTest.java │   └── [2.2K] ZTFileUtilTest.java └── [4.0K] resources ├── [ 430] backSlashTest.zip ├── [ 657] demo-copy-II.zip ├── [ 657] demo-copy.zip ├── [1.0K] demo-dirs-only.zip ├── [1.6K] demo-dirs.zip ├── [ 266] demo-keep-entries-state.zip ├── [ 154] demo-single-empty-root-dir.zip ├── [ 732] demo-single-root-dir.zip ├── [ 657] demo.zip ├── [ 214] duplicate.zip ├── [ 900] log4j.properties ├── [4.0K] testDirectory │   ├── [ 8] testfileInTestDirectory.txt │   └── [4.0K] testSubdirectory │   └── [ 8] testFileInTestSubdirectory.txt ├── [ 103] TestFile-II.txt ├── [ 108] TestFile.txt ├── [ 936] umlauts-öäš.zip └── [ 356] windows-compressed.zip 19 directories, 91 files
Shenlong Bot has cached this for you
Remarks
    1. It is advised to access via the original source first.
    2. If the original source is unavailable, please email f.jinxu#gmail.com for a local snapshot (replace # with @).
    3. Shenlong has snapshotted the POC code for you. To support long-term maintenance, please consider donating. Thank you for your support.