Skip to main content
  1. Posts/

CWE-22: Improper Limitation of a Pathname to a Restricted Directory

Sven Ruppert
Author
Sven Ruppert
20+ years of Java, specialised in Security, Vaadin and Developer Relations. When not coding, you’ll find me in the woods with an axe.
Table of Contents

CWE-22, commonly called “Path Traversal,” is a vulnerability when an application fails to appropriately limit the paths users can access through a user-provided input. This can allow attackers to access directories and files outside the intended directory, leading to unauthorised access and potential system compromise. This vulnerability is particularly significant in Java applications due to the ubiquitous use of file handling and web resources. This document will delve into the nature of CWE-22, its implications, exploitation methods, and, most importantly, strategies to mitigate such vulnerabilities in Java applications.

  1. Understanding CWE-22
  2. Implications of CWE-22
  3. Exploitation Techniques
  4. Mitigation Strategies in Java
  5. Case Study: A Vulnerable Java Application
    1. Vulnerable Code
    2. Secure Code
  6. What Java Libraries are Helping against CWE-22
    1. Apache Commons IO
    2. OWASP Java Encoder
    3. Apache Shiro
    4. Spring Security
    5. Tika
    6. ESAPI (Enterprise Security API)
    7. Java NIO (New I/O)
    8. Hibernate Validator
  7. What CVEs are based on CWE-22
    1. CVE-2020-9484
    2. CVE-2019-0232
    3. CVE-2018-11784

Understanding CWE-22
#

CWE-22 is categorised under “Improper Limitation of a Pathname to a Restricted Directory (‘Path Traversal’).” This occurs when an application constructs a path using user input without proper validation or sanitisation, allowing the user to specify paths that traverse outside the intended directory. Sequences such as ../ can be used to move up the directory structure.

For example, consider the following Java code snippet that reads a file based on user input:

String fileName = request.getParameter("file");
File file = new File("/var/www/uploads/" + fileName);
FileInputStream fis = new FileInputStream(file);

If the fileName parameter is not properly validated, an attacker can manipulate it to access files outside the /var/www/uploads/ directory, such as /etc/passwd, by using a path traversal sequence (../../etc/passwd).

Implications of CWE-22
#

The implications of CWE-22 can be severe, ranging from unauthorised access to sensitive files to full system compromise. Some of the potential impacts include:

Exposure of Sensitive Information : Attackers can access sensitive files such as configuration files, passwords, and personal data.

Data Integrity Compromise : Attackers can modify files, potentially leading to data corruption or alteration of critical application files.

Denial of Service (DoS) : Attackers can disrupt normal operations by accessing and modifying system files.

Execution of Arbitrary Code : In extreme cases, attackers might execute arbitrary code if they gain access to executable files or scripts.

Exploitation Techniques
#

To exploit a path traversal vulnerability, an attacker typically uses special characters and patterns in the input to navigate the file system. Here are some standard techniques:

Dot-Dot-Slash (../) : The most common method where the attacker uses ../ to move up the directory structure.

Encoded Characters : Attackers may use URL encoding (%2e%2e%2f) or other encoding schemes to bypass simple input filters.

Null Byte Injection : Sometimes, null bytes (%00) are used to terminate strings early, effectively ignoring any appended extensions or path components.

Mitigation Strategies in Java
#

Mitigating CWE-22 in Java involves a combination of secure coding practices, input validation, and proper use of APIs. Here are some detailed strategies:

Canonicalisation and Normalization :

Ensure that the file paths are normalised before use. Java provides methods to normalise paths, which can help mitigate traversal attacks.

   import java.nio.file.Paths;
   import java.nio.file.Path;
   public File getFile(String fileName) throws IOException {
       Path basePath = Paths.get("/var/www/uploads/");
       Path filePath = basePath.resolve(fileName).normalize();
       if (!filePath.startsWith(basePath)) {
           throw new SecurityException("Attempted path traversal attack detected");
       }
       return filePath.toFile();
   }

Input Validation and Sanitization :

Perform strict validation on user inputs. Reject any input that contains potentially malicious patterns such as ../, URL-encoded sequences, or other traversal patterns.

public String sanitizeFileName(String fileName) {
       if (fileName == null || fileName.contains("..") 
                            || fileName.contains("/") 
                            || fileName.contains("\\")) {
           throw new IllegalArgumentException("Invalid file name");
       }
       return fileName;
   }

Whitelist Approach :

Use a whitelist approach to validate filenames against a set of allowed values or patterns. This can be more effective than blacklisting known destructive patterns.

public boolean isValidFileName(String fileName) {
       return fileName.matches("[a-zA-Z0-9._-]+");
}

File Access Controls :

Restrict file permissions on the server to limit access only to necessary files and directories. This reduces the impact of potential exploits.

Logging and Monitoring :

Implement comprehensive logging and monitoring to detect and respond to suspicious activities. Logs should capture sufficient details to trace potential exploitation attempts.

import java.util.logging.Logger;
   public class FileAccessLogger {
       private static final Logger LOGGER = Logger.getLogger(FileAccessLogger.class.getName());
       public void logAccessAttempt(String fileName) {
           LOGGER.warning("Attempted access to file: " + fileName);
       }
   }

Case Study: A Vulnerable Java Application
#

Let’s consider a hypothetical case study to illustrate the application of these mitigation strategies. Suppose we have a simple Java web application that allows users to download files from the server.

Vulnerable Code
#

@WebServlet("/download")
public class FileDownloadServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String fileName = request.getParameter("file");
        File file = new File("/var/www/uploads/" + fileName);
        if (file.exists()) {
            FileInputStream fis = new FileInputStream(file);
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                response.getOutputStream().write(buffer, 0, bytesRead);
            }
            fis.close();
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }
}

This servlet reads the file parameter from the request and constructs a File object. Without proper validation, an attacker can exploit this to download arbitrary files from the server.

Secure Code
#

@WebServlet("/download")
public class FileDownloadServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String fileName = sanitizeFileName(request.getParameter("file"));
        Path basePath = Paths.get("/var/www/uploads/");
        Path filePath = basePath.resolve(fileName).normalize();
        if (!filePath.startsWith(basePath)) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid file path");
            return;
        }
        File file = filePath.toFile();
        if (file.exists()) {
            FileInputStream fis = new FileInputStream(file);
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                response.getOutputStream().write(buffer, 0, bytesRead);
            }
            fis.close();
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }
    private String sanitizeFileName(String fileName) {
        if (fileName == null || fileName.contains("..") || fileName.contains("/") || fileName.contains("\\")) {
            throw new IllegalArgumentException("Invalid file name");
        }
        return fileName;
    }
}

In the secure version, the sanitizeFileName method ensures the file name is free from traversal sequences, and the path is normalised and checked to prevent directory traversal.

CWE-22, or path traversal, is a critical vulnerability that can have severe consequences if not adequately mitigated. In Java applications, it is essential to employ a combination of secure coding practices, input validation, canonicalisation, and access controls to safeguard against this threat. By understanding the nature of CWE-22 and implementing robust security measures, developers can significantly reduce the risk of unauthorised file access and protect their applications from potential exploitation.

What Java Libraries are Helping against CWE-22
#

Several Java libraries and tools can help developers prevent CWE-22 (Path Traversal) vulnerabilities by providing robust input validation, path normalisation, and security mechanisms. Here are some of the most notable ones:

Apache Commons IO
#

Apache Commons IO provides a variety of utilities for working with the file system, which can help prevent path traversal vulnerabilities.

FilenameUtils : This class contains methods for normalising and validating file paths.

import org.apache.commons.io.FilenameUtils;
  String basePath = "/var/www/uploads/";
  String fileName = FilenameUtils.normalize(request.getParameter("file"));
  if (!FilenameUtils.directoryContains(basePath, basePath + fileName)) {
      throw new SecurityException("Attempted path traversal attack detected");
  }

OWASP Java Encoder
#

The OWASP Java Encoder library encodes untrusted input to help protect against injection attacks, including those involving path traversal.

Encoder : Provides methods to encode user input for various contexts, including filenames, safely.

import org.owasp.encoder.Encode;
  String safeFileName = Encode.forJava(request.getParameter("file"));

Apache Shiro
#

Apache Shiro is a powerful security framework that provides robust access control mechanisms for enforcing file access policies.

Path Permissions : Shiro allows you to define fine-grained access control policies related to file access.

// Define file access permissions in Shiro configuration
  [urls]
  /var/www/uploads/** = authc, perms["file:read"]

Spring Security
#

Spring Security is a comprehensive security framework that integrates seamlessly with Spring applications, providing mechanisms for authentication and authorisation.

Access Control : Spring Security can be configured to enforce strict access controls on file resources.

@PreAuthorize("hasPermission(#filePath, 'read')")
  public void readFile(Path filePath) {
      // read file logic
  }

Tika
#

Apache Tika is a library for detecting and extracting metadata and content from various file types. It includes utilities for working with file paths safely.

Tika IOUtils : Utility methods for safe file operations.

import org.apache.tika.io.IOUtils;

  String safeFileName = IOUtils.toString(request.getParameter("file"), StandardCharsets.UTF_8);

ESAPI (Enterprise Security API)
#

The OWASP ESAPI library provides a comprehensive set of security controls, including file-handling utilities that can help prevent path traversal attacks.

Validator : Use ESAPI’s Validator to validate filenames.

import org.owasp.esapi.ESAPI;
import org.owasp.esapi.Validator;
Validator validator = ESAPI.validator();
String safeFileName = validator.getValidInput("file name", 
                       request.getParameter("file"), 
                       "Filename", 255, false);

Java NIO (New I/O)
#

Java NIO provides modern APIs for file operations, including path manipulation and validation.

Path and Files : Use java.nio.file.Path and java.nio.file.Files for secure file operations.

import java.nio.file.Path;
  import java.nio.file.Paths;
  import java.nio.file.Files;
  Path basePath = Paths.get("/var/www/uploads/");
  Path filePath = basePath.resolve(request.getParameter("file")).normalize();
  if (!filePath.startsWith(basePath)) {
      throw new SecurityException("Attempted path traversal attack detected");
  }
  if (Files.exists(filePath)) {
      // read file logic
  }

Hibernate Validator
#

Hibernate Validator, the reference implementation of the Bean Validation API, can be used to enforce validation constraints on user inputs.

Custom Constraints : Define custom validation constraints for filenames.

import javax.validation.constraints.Pattern;
  public class FileRequest {
      @Pattern(regexp = "[a-zA-Z0-9._-]+")
      private String fileName;
      // getters and setters
  }

The Java libraries and tools provide robust mechanisms to prevent CWE-22 (Path Traversal) vulnerabilities. Using these libraries, developers can ensure that user inputs are appropriately validated, paths are normalised, and access controls are strictly enforced. This multi-layered approach significantly reduces the risk of unauthorised file access and enhances the overall security of Java applications.

What CVEs are based on CWE-22
#

Several Common Vulnerabilities and Exposures (CVEs) related to Java applications have been reported that are based on CWE-22, the Improper Limitation of a Pathname to a Restricted Directory (‘Path Traversal’). These CVEs highlight path traversal vulnerabilities’ real-world implications and impact in various Java-based systems and libraries. Here are some notable examples:

CVE-2020-9484
#

Description : Apache Tomcat HTTP/2 Request Smuggling and Path Traversal.

Affected Versions : Apache Tomcat 9.0.0.M1 to 9.0.35, 8.5.0 to 8.5.55, and 7.0.0 to 7.0.104.

Details : This vulnerability allowed an attacker to upload files to arbitrary locations via a specially crafted request. The issue was related to the improper handling of user input in file upload paths, leading to a path traversal vulnerability.

Mitigation : Upgrade to the latest versions of Apache Tomcat that include the patch for this vulnerability.

CVE-2019-0232
#

Description : Apache Tomcat Remote Code Execution via CGI Servlet.

Affected Versions : Apache Tomcat 9.0.0.M1 to 9.0.17, 8.5.0 to 8.5.39, and 7.0.0 to 7.0.93.

Details : This CVE was related to a path traversal vulnerability that allowed attackers to achieve remote code execution by manipulating the CGI Servlet configuration.

Mitigation : Disable the CGI Servlet if it is unnecessary or upgrade to a version that fixes the vulnerability.

CVE-2018-11784
#

Description : Apache JMeter Path Traversal Vulnerability.

Affected Versions : Apache JMeter 3.0 to 4.0.

Details : This vulnerability allowed attackers to access files outside the intended directories via a path traversal attack, leveraging improper file path validation in the application.

Mitigation : Upgrade to Apache JMeter 5.0 or later versions where the issue has been resolved.

These CVEs highlight the importance of addressing CWE-22 vulnerabilities in Java applications. Regularly updating libraries, frameworks, and application code is crucial to mitigating such vulnerabilities. Developers should adopt best practices for input validation, path normalisation, and robust security configurations to protect against path traversal attacks.

Related

CWE-416: Use After Free Vulnerabilities in Java

CWE-416: Use After Free # Use After Free (UAF) is a vulnerability that occurs when a program continues to use a pointer after it has been freed. This can lead to undefined behaviour, including crashes, data corruption, and security vulnerabilities. The problem arises because the memory referenced by the pointer may be reallocated for other purposes, potentially allowing attackers to exploit the situation.

CWE-787 - The Bird-Eye View for Java Developers

The term “CWE-787: Out-of-bounds Write " likely refers to a specific security vulnerability or error in software systems. Let’s break down what it means: Out-of-bounds Write : This is a type of vulnerability where a program writes data outside the boundaries of pre-allocated fixed-length buffers. This can corrupt data, crash the program, or lead to the execution of malicious code.

Mastering Secure Error Handling in Java: Best Practices and Strategies

What is ErrorHandling? # Error handling refers to the programming practice of anticipating, detecting, and responding to exceptions or errors in software during its execution. Errors may occur for various reasons, such as invalid user inputs, hardware failures, or bugs in the code. Proper error handling helps ensure that the program can handle such situations gracefully by resolving the Error, compensating for it, or failing safely.