## https://sploitus.com/exploit?id=044C59C9-7B55-579A-BC1D-890FC5EED45D
This repo is a set of samples to demonstrate the arrangements wherein applications may be vulnerable to https://spring.io/security/cve-2023-34035[CVE-2023-34035].
An application is vulnerable when all of the following are true:
Spring MVC is on the classpath
`DispatcherServlet` and at least one other servlet are mapped; one of them having a path-based servlet mapping (for example, `/path/**`)
The application uses `requestMatchers(String)` to refer to endpoints whose servlet mapping is of the form `/path/**`
== Samples
There are a set of samples that use Spring Boot and a set that do not.
The samples that contain failing tests are vulnerable to CVE-2023-34035. The samples whose tests pass are not vulnerable.
In all cases, each of these samples contains the same mitigation error from Spring Security, though note that such a mitigation is temporary in many circumstances, pending the next maintenance release.
=== `servlet:java-configuration:dispatcher-servlet-path`
https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/java-configuration/dispatcher-servlet-path[This sample] represents a vulnerable application where `DispatcherServlet` is deployed to `/mvc/*` instead of the default `/`.
It is *vulnerable* since Spring MVC is on the classpath, `DispatcherServlet` and at least one other servlet is mapped -- one of them with a non-root, path-based servlet mapping (in this case, `DispatcherServlet`), and the application uses `requestMatchers(String)` to secure those endpoints.
=== `servlet:java-configuration:jetty`
https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/java-configuration/jetty[This sample] represents a safe application where `DispatcherServlet` is deployed to `/` (the default).
It is *not vulnerable*. While Spring MVC is on the classpath and `DispatcherServlet` is in use, it is deployed to `/` and there are no non-root, path-based servlet mappings.
=== `servlet:java-configuration:other-servlets`
https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/java-configuration/other-servlets[This sample] represents a vulnerable application where `DispatcherServlet` is deployed as well as a custom servlet `MyServlet`.
It is *vulnerable* since Spring MVC is on the classpath, `DispatcherServlet` and at least one other servlet is mapped -- one of them with a non-root, path-based servlet mapping (in this case, `MyServlet`), and the application uses `requestMatchers(String)` to secure those endpoints.
=== `servlet:java-configuration:tomcat`
https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/java-configuration/tomcat[This sample] represents a safe application where `DispatcherServlet` is deployed to `/` (the default).
It is *not vulnerable*. While Spring MVC is on the classpath and `DispatcherServlet` is in use, it is deployed to `/` and there are no non-root, path-based servlet mappings.
=== `servlet:java-configuration:two-dispatcher-servlets`
https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/java-configuration/two-dispatcher-servlets[This sample] represents a vulnerable application where `DispatcherServlet` is deployed as well as a custom servlet `MyServlet`.
It is *vulnerable* since Spring MVC is on the classpath, `DispatcherServlet` and at least one other servlet is mapped -- one of them with a non-root, path-based servlet mapping (in this case, one of the two ``DispatcherServlet``s), and the application uses `requestMatchers(String)` to secure those endpoints.
=== `servlet:spring-boot:java:dispatcher-servlet-path`
https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/spring-boot/java/dispatcher-servlet-path[This sample] represents a vulnerable application where `DispatcherServlet` is deployed to `/mvc/*` instead of the default `/`.
It is *vulnerable* since Spring MVC is on the classpath, `DispatcherServlet` and at least one other servlet is mapped -- one of them with a non-root, path-based servlet mapping (in this case, `DispatcherServlet`), and the application uses `requestMatchers(String)` to secure those endpoints.
=== `servlet:spring-boot:java:jetty`
https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/spring-boot/java/jetty[This sample] represents a safe application where `DispatcherServlet` is deployed to `/` (the default).
It is *not vulnerable*. While Spring MVC is on the classpath and `DispatcherServlet` is in use, it is deployed to `/` and there are no non-root, path-based servlet mappings.
=== `servlet:spring-boot:java:other-servlets`
https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/spring-boot/java/other-servlets[This sample] represents a vulnerable application where `DispatcherServlet` is deployed as well as a custom servlet `MyServlet`.
It is *vulnerable* since Spring MVC is on the classpath, `DispatcherServlet` and at least one other servlet is mapped -- one of them with a non-root, path-based servlet mapping (in this case, `MyServlet`), and the application uses `requestMatchers(String)` to secure those endpoints.
=== `servlet:spring-boot:java:tomcat`
https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/spring-boot/java/tomcat[This sample] represents a safe application where `DispatcherServlet` is deployed to `/` (the default).
It is *not vulnerable*. While Spring MVC is on the classpath and `DispatcherServlet` is in use, it is deployed to `/` and there are no non-root, path-based servlet mappings.
=== `servlet:spring-boot:java:undertow`
https://github.com/jzheaux/cve-2023-34035-mitigations/tree/main/servlet/spring-boot/java/undertow[This sample] represents a safe application where `DispatcherServlet` is deployed to `/` (the default).
It is *not vulnerable*. While Spring MVC is on the classpath and `DispatcherServlet` is in use, it is deployed to `/` and there are no non-root, path-based servlet mappings.
== Mitigations
In the event that you get an error like the following:
.Bash
[source,bash,role="primary"]
----
This method cannot decide whether these patterns are Spring MVC patterns or not.
If this endpoint is a Spring MVC endpoint, please use `requestMatchers(MvcRequestMatcher)`;
otherwise, please use `requestMatchers(AntPathRequestMatcher)`.
----
you should follow it.
[NOTE]
The `5.8.5`, `6.0.5`, `6.1.2`, and `6.2.0-M1` versions of Spring Security have some false positives.
Now that in many cases the following is temporary, pending the release of `5.8.6`, `6.0.6`, `6.1.3`, and `6.2.0-M2`.
As alluded to by the error message, the primary mitigation is to use a complete `RequestMatcher`.
This is so that the servlet mapping can be more clearly accounted for.
For example, if an application has a servlet deployed to `/my-servlet/*` and is authorizing that traffic like so:
.Java
[source,java,role="primary"]
----
@Bean
SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/my-servlet/**").hasRole("USER")
.requestMatchers("/spring-mvc-controller/**").hasRole("USER")
.anyRequest().authenticated()
)
// ...
return http.build();
}
----
then, the application should instead do:
.Java
[source,java,role="primary"]
----
import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector);
}
@Bean
SecurityFilterChain appSecurity(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(antMatcher("/my-servlet/*")).hasRole("USER")
.requestMatchers(mvc.pattern("/spring-mvc-controller/**")).hasRole("USER")
.anyRequest().authenticated()
)
// ...
return http.build();
}
----
Or, if `DispatcherServlet` is deployed to a different path, like `/spring-mvc/*`, then instead of:
.Java
[source,java,role="primary"]
----
@Bean
SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/spring-mvc/controller/**")).hasRole("USER")
.anyRequest().authenticated()
)
// ...
return http.build();
}
----
an application should do:
.Java
[source,java,role="primary"]
----
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector).servletPath("/spring-mvc");
}
@Bean
SecurityFilterChain appSecurity(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers(mvc.pattern("/controller/**")).hasRole("USER")
.anyRequest().authenticated()
)
// ...
return http.build();
}
----
Separating the servlet path when constructing an `MvcRequestMatcher` is important to ensure that the request is correctly matched.
== Branches
In this repo, there is a branch for each minor release of Spring Security.
On that branch, there is a commit for each affected sample with the needed mitigation.
For example, on the `5.8.x` branch, there are eight commits to repair the eight samples that require mitigation.
When `5.8.6`, `6.0.6`, `6.1.3`, and `6.2.0-M2` are released, additional changes will be made to those branches so the best-practice mitigation is clear.