From fcec7d1b51a03cf21a4ea67c00048cb30bbc8341 Mon Sep 17 00:00:00 2001 From: TrellixVulnTeam Date: Fri, 9 Dec 2022 08:45:35 +0000 Subject: [PATCH] Adding tarfile member sanitization to extractall() --- Scripts/extras/archive_downloader.py | 21 ++++++++++++++++++++- Scripts/extras/package_downloader.py | 21 ++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/Scripts/extras/archive_downloader.py b/Scripts/extras/archive_downloader.py index 3cfb19ae..7e04a3e6 100644 --- a/Scripts/extras/archive_downloader.py +++ b/Scripts/extras/archive_downloader.py @@ -122,7 +122,26 @@ def extract_package(src_package_file: str, target_folder:str): elif package_ext in ARCHIVE_EXTS_TAR: import tarfile with tarfile.open(str(src_package_file_path.resolve())) as tar_file: - tarfile.extractall(destination_path) + def is_within_directory(directory, target): + + abs_directory = os.path.abspath(directory) + abs_target = os.path.abspath(target) + + prefix = os.path.commonprefix([abs_directory, abs_target]) + + return prefix == abs_directory + + def safe_extract(tar, path=".", members=None, *, numeric_owner=False): + + for member in tar.getmembers(): + member_path = os.path.join(path, member.name) + if not is_within_directory(path, member_path): + raise Exception("Attempted Path Traversal in Tar File") + + tar.extractall(path, members, numeric_owner=numeric_owner) + + + safe_extract(tarfile, destination_path) elif package_ext in ARCHIVE_EXTS_7ZIP: try: os.makedirs(destination_path, exist_ok=True) diff --git a/Scripts/extras/package_downloader.py b/Scripts/extras/package_downloader.py index fb01bb3e..1caa5b9b 100644 --- a/Scripts/extras/package_downloader.py +++ b/Scripts/extras/package_downloader.py @@ -177,7 +177,26 @@ def DownloadAndUnpackPackage(package_name, package_hash, folder_target): package_unpack_folder.mkdir(parents=True, exist_ok=True) with tarfile.open(package_download_name) as archive_file: print(" - unpacking package...") - archive_file.extractall(package_unpack_folder) + def is_within_directory(directory, target): + + abs_directory = os.path.abspath(directory) + abs_target = os.path.abspath(target) + + prefix = os.path.commonprefix([abs_directory, abs_target]) + + return prefix == abs_directory + + def safe_extract(tar, path=".", members=None, *, numeric_owner=False): + + for member in tar.getmembers(): + member_path = os.path.join(path, member.name) + if not is_within_directory(path, member_path): + raise Exception("Attempted Path Traversal in Tar File") + + tar.extractall(path, members, numeric_owner=numeric_owner) + + + safe_extract(archive_file, package_unpack_folder) print(f"Downloaded successfuly to {os.path.realpath(package_unpack_folder)}") return True except (OSError, tarfile.TarError) as e: