CVE-2023-6908: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') (CWE-22)
value: A vulnerability, which was classified as problematic, was found in DFIRKuiper Kuiper 2.3.4. This affects the function unzip_file of the file kuiper/app/controllers/case_management.py of the component TAR Archive Handler. The manipulation of the argument dst_path leads to path traversal. It is possible to initiate the attack remotely. The complexity of an attack is rather high. The exploitability is told to be difficult. Upgrading to version 2.3.5 is able to address this issue. The identifier of the patch is 94fa135153002f651f5526c55a7240e083db8d73. It is recommended to upgrade the affected component. The identifier VDB-248277 was assigned to this vulnerability.
CWE description: The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
CVSS v3 base score: 5.9
Published: 2023-12-18T04:15Z
Repository: https://github.com/DFIRKuiper/Kuiper
Language: Python
Files changed: kuiper/app/controllers/case_management.py
Commit date: 2023-07-04 15:25:10 +0200
Commit message: Fix path traversal vulnerability when extracting tar files

Unlike zipfile, tarfile's extractall does not check if a member
is going to be written outside of the specified destination path,
so it needs to be checked manually.

Diff: diff --git a/kuiper/app/controllers/case_management.py b/kuiper/app/controllers/case_management.py
index 99d94f7..3d26457 100755
--- a/kuiper/app/controllers/case_management.py
+++ b/kuiper/app/controllers/case_management.py
@@ -120,15 +120,38 @@ def decompress_file(archive_path,dst_path):
 def unzip_file(zip_path, dst_path):
     with zipfile.ZipFile(zip_path , mode='r') as zfile:
         zfile.extractall(path=dst_path)
 
 
+# ================================ is within directory
+# check if target is within a given directory
+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
+
+
+# ================================ safe tar extraction
+# Safe extraction of tar file to avoid path traversal vulnerability (CVE-2007-4559)
+# Patch taken from https://github.com/dbt-labs/dbt-core/pull/5981/files
+def safe_tar_extract(tar, dst_path):
+    for member in tar.getmembers():
+        member_path = os.path.join(dst_path, member.name)
+        if not is_within_directory(directory=dst_path, target=member_path):
+            raise Exception("Attempted Path Traversal in Tar File")
+
+    tar.extractall(path=dst_path)
+
+
 # ================================ untar file
 # untar the provided file to the dst_path
 def untar_file(tar_path, dst_path):
     with tarfile.open(tar_path , mode='r') as tfile:
-        tfile.extractall(path=dst_path)
+        safe_tar_extract(tfile, dst_path)
 
 
 # ================================ list zip file content
 # list zip file content
 def list_zip_file(zip_path):

Vulnerable code:         tfile.extractall(path=dst_path)
Fixed code: # ================================ is within directory
# check if target is within a given directory
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


# ================================ safe tar extraction
# Safe extraction of tar file to avoid path traversal vulnerability (CVE-2007-4559)
# Patch taken from https://github.com/dbt-labs/dbt-core/pull/5981/files
def safe_tar_extract(tar, dst_path):
    for member in tar.getmembers():
        member_path = os.path.join(dst_path, member.name)
        if not is_within_directory(directory=dst_path, target=member_path):
            raise Exception("Attempted Path Traversal in Tar File")

    tar.extractall(path=dst_path)


        safe_tar_extract(tfile, dst_path)