From c7572233121f2915cbd370def7bda980ad1ab838 Mon Sep 17 00:00:00 2001 From: TrellixVulnTeam <112716341+TrellixVulnTeam@users.noreply.github.com> Date: Mon, 10 Oct 2022 19:52:30 -0500 Subject: [PATCH] CVE-2007-4559 Patch (#990) # Patching CVE-2007-4559 Hi, we are security researchers from the Advanced Research Center at [Trellix](https://www.trellix.com). We have began a campaign to patch a widespread bug named CVE-2007-4559. CVE-2007-4559 is a 15 year old bug in the Python tarfile package. By using extract() or extractall() on a tarfile object without sanitizing input, a maliciously crafted .tar file could perform a directory path traversal attack. We found at least one unsantized extractall() in your codebase and are providing a patch for you via pull request. The patch essentially checks to see if all tarfile members will be extracted safely and throws an exception otherwise. We encourage you to use this patch or your own solution to secure against CVE-2007-4559. Further technical information about the vulnerability can be found in this [blog](https://www.trellix.com/en-us/about/newsroom/stories/research/tarfile-exploiting-the-world.html). If you have further questions you may contact us through this projects lead researcher [Kasimir Schulz](mailto:kasimir.schulz@trellix.com). --- dpgen/auto_test/lib/RemoteJob.py | 21 ++++++++++++++++++++- dpgen/dispatcher/SSHContext.py | 21 ++++++++++++++++++++- dpgen/remote/RemoteJob.py | 21 ++++++++++++++++++++- 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/dpgen/auto_test/lib/RemoteJob.py b/dpgen/auto_test/lib/RemoteJob.py index d976b42532..e66df13513 100644 --- a/dpgen/auto_test/lib/RemoteJob.py +++ b/dpgen/auto_test/lib/RemoteJob.py @@ -191,7 +191,26 @@ def _get_files(self, cwd = os.getcwd() os.chdir(self.local_root) with tarfile.open(of, "r:gz") as tar: - tar.extractall() + 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(tar) os.chdir(cwd) # cleanup os.remove(to_f) diff --git a/dpgen/dispatcher/SSHContext.py b/dpgen/dispatcher/SSHContext.py index aca7d83688..7f614f31b6 100644 --- a/dpgen/dispatcher/SSHContext.py +++ b/dpgen/dispatcher/SSHContext.py @@ -333,7 +333,26 @@ def _get_files(self, cwd = os.getcwd() os.chdir(self.local_root) with tarfile.open(of, "r:gz") as tar: - tar.extractall() + 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(tar) os.chdir(cwd) # cleanup os.remove(to_f) diff --git a/dpgen/remote/RemoteJob.py b/dpgen/remote/RemoteJob.py index 4cdc76e9c6..992fb82f4d 100644 --- a/dpgen/remote/RemoteJob.py +++ b/dpgen/remote/RemoteJob.py @@ -288,7 +288,26 @@ def _get_files(self, cwd = os.getcwd() os.chdir(self.local_root) with tarfile.open(of, "r:gz") as tar: - tar.extractall() + 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(tar) os.chdir(cwd) # cleanup os.remove(to_f)