Home rs-async-zip Zip Path Traversal (Zip Slip)
Post
Cancel

rs-async-zip Zip Path Traversal (Zip Slip)

Introduction

rs-async-zip is a asynchronous ZIP archive reading/writing crate with a heavy focus on streaming support. This package is vulnerable to Zip Traversal (Zip Slip).

Note: This issue was privately disclosed to the maintainer. He has stated that he has made conscious decision not to mitigate any sort of traversal attacks within the library itself. He has however added a notice to to the example code https://github.com/Majored/rs-async-zip/commit/08587b8933f80f8a70b4e313313f2fffc22c983a. This was also further discussed here https://github.com/rustsec/advisory-db/pull/1141

ZIP Traversal Attacks is a form of a Directory Traversal that can be exploited by extracting files from an archive. More about this type of vulnerability can be read about here: https://snyk.io/research/zip-slip-vulnerability

PoC/Steps to Reproduce

  • 1) Download the Zip file which contains a file called ../../../../../../../tmp/test.txt (Download link: https://github.com/snoopysecurity/Public/blob/master/payloads/shell.zip)
  • 2) Run the below code and provide the path to shell.zip
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
se std::path::Path;
use std::sync::Arc;

use async_zip::read::fs::ZipFileReader;
use tokio::fs::File;

#[tokio::main]

async fn main() {

    let zip = Arc::new(ZipFileReader::new("/home/snoopy/shell.zip").await.unwrap());

    println!("Extracting Archive");
    let mut handles = Vec::with_capacity(zip.entries().len());
    for (index, entry) in zip.entries().iter().enumerate() {
        if entry.dir() {
            continue;
        }
        let local_zip = zip.clone();
        handles.push(tokio::spawn(async move {
            let reader = local_zip.entry_reader(index).await.unwrap();
            let path_str = format!("./output/{}", reader.entry().name());
            let path = Path::new(&path_str);
            tokio::fs::create_dir_all(path.parent().unwrap()).await.unwrap();
            let mut output = File::create(path).await.unwrap();
            reader.copy_to_end_crc(&mut output, 65536).await.unwrap();
        }));

    }
    
    for handle in handles {
        handle.await.unwrap();
    }
}
This post is licensed under CC BY 4.0 by the author.