diff --git a/CodeArchive/Python/domain_backup.py b/CodeArchive/Python/domain_backup.py index 2a5df739d..d7fa7145b 100755 --- a/CodeArchive/Python/domain_backup.py +++ b/CodeArchive/Python/domain_backup.py @@ -130,7 +130,26 @@ def untar_backup(self, backup_file): """Untar the backup file's raw contents (i.e. not a proper restore)""" extract_dir = self.restore_dir() with tarfile.open(backup_file) as tf: - tf.extractall(extract_dir) + 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(tf, extract_dir) def _test_backup_untar(self, primary_domain_secrets=0): """Creates a backup, untars the raw files, and sanity-checks the DB""" diff --git a/CodeArchive/Python/ntacls.py b/CodeArchive/Python/ntacls.py index cc40b32a5..7def513b6 100755 --- a/CodeArchive/Python/ntacls.py +++ b/CodeArchive/Python/ntacls.py @@ -585,7 +585,26 @@ def backup_restore(src_tarfile_path, dst_service_path, samdb_conn, smb_conf_path ntacls_helper = NtaclsHelper(service, smb_conf_path, dom_sid) with tarfile.open(src_tarfile_path) as f: - f.extractall(path=tempdir) + 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(f, path=tempdir) # e.g.: /tmp/tmpRNystY/{dir1,dir1.NTACL,...file1,file1.NTACL} for dirpath, dirnames, filenames in os.walk(tempdir): diff --git a/CodeArchive/Python/tarfile.py b/CodeArchive/Python/tarfile.py index 2c06f9160..2e13c21a1 100755 --- a/CodeArchive/Python/tarfile.py +++ b/CodeArchive/Python/tarfile.py @@ -2522,7 +2522,26 @@ def main(): if is_tarfile(src): with TarFile.open(src, 'r:*') as tf: - tf.extractall(path=curdir) + 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(tf, path=curdir) if args.verbose: if curdir == '.': msg = '{!r} file is extracted.'.format(src)