Skip to content

Zip-slip during kerberos/component archive extraction (path traversal) #1203

Description

@Ku4D3

Severity: High · CWE: CWE-22 (Improper Limitation of a Pathname to a Restricted Directory)
Affected versions:v1.4.0

Summary

The chunk-check endpoint joins the request body's name field directly into a file path and returns whether that file exists and whether its size matches a caller-supplied value. Because name is not filtered, a caller can supply ../ sequences or an absolute path to probe for the existence of arbitrary files anywhere on the host and learn their exact size. The controller is marked @Deprecated and @Hidden (excluded from the Swagger UI) but is still mapped and reachable; no URI-level authorization is enforced for it.

Vulnerability chain

Stage Component Location
Source POST /chunk/check, body FileChunkCheckDTO.name / size / chunkIndex FileChunkController.java:73
Transform path = Paths.get(uploadFolder, info.getName(), chunkIndex) FileChunkController.java:77
Sink new File(file).isFile() + target.length() (boolean returned to caller) WebUploader.java:40-41

The name field is concatenated into the absolute path with no canonicalization. The controller then calls chunkCheck, which performs new File(file).isFile() and compares target.length() against the request-supplied size, returning the boolean result to the caller. A traversal in name escapes uploadFolder, so the boolean response and the size match together act as an arbitrary file-existence oracle that also reveals exact file size.

Key code

The controller is reachable even though it is deprecated/hidden (@RequestMapping("/chunk"), @Hidden, @Deprecated):

// lamp-base/lamp-base-controller/.../file/controller/FileChunkController.java:41,71
@RequestMapping("/chunk")
...
@RequestMapping(value = "/check", method = RequestMethod.POST)
@ResponseBody
public R<Boolean> chunkCheck(@RequestBody FileChunkCheckDTO info) {
    log.info("info={}", info);
    String uploadFolder = FileTypeUtil.getUploadPathPrefix(fileProperties.getLocal().getStoragePath());
    boolean chunkCheck = wu.chunkCheck(Paths.get(uploadFolder, info.getName(), String.valueOf(info.getChunkIndex())).toString(), info.getSize());
    return R.success(chunkCheck);
}

The name field is an unvalidated string:

// lamp-base/lamp-base-entity/.../file/dto/chunk/FileChunkCheckDTO.java
public class FileChunkCheckDTO {
    private Long size;
    private String name;        // unfiltered
    private Integer chunkIndex;
}

The probe itself leaks existence and size:

// lamp-base/lamp-base-controller/.../file/manager/WebUploader.java:38
public boolean chunkCheck(String file, Long size) {
    java.io.File target = new java.io.File(file);
    return target.isFile() && size == target.length();   // :41 — existence + size oracle
}

Proof of Concept

Request-level only. By adjusting size, a caller can binary-search the exact length of any probed file. The endpoint is deprecated and @Hidden but still mapped:

POST /chunk/check HTTP/1.1
Host: <lamp-host>
Content-Type: application/json

{
  "name": "../../../../../etc/passwd",
  "chunkIndex": 0,
  "size": 1234
}

A true response confirms the file exists and is exactly the supplied size; iterating size recovers the precise length of an arbitrary file.

Impact

A remote attacker who can reach /chunk/check can enumerate the existence of arbitrary files on the host and determine their exact size, enabling sensitive-file discovery and information disclosure. The endpoint is deprecated and excluded from the API documentation, which makes it easy to forget it is still deployed and reachable; it is also not covered by URI-level authorization.

Remediation

  • Canonicalize the path (Path.normalize() / getCanonicalFile()) and reject any result outside uploadFolder; reject name values containing .., path separators, or absolute paths at the controller boundary.
  • Remove the deprecated @Hidden chunkCheck endpoint, or hard-gate it behind authentication and authorization.
  • Do not reflect a boolean file-existence result for attacker-controlled paths.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions