Spring4Shell - Zero Day Vulnerability in Spring Framework


In the days of Vulnerabilities, the famous Spring framework is the latest victim, which has quite a turns of event for the CVE identified as CVE-2022-22965. The latest Spring Vulnerabilities was to be reported on 31st March, 2022, but someone has leaked the detailed information online a day before the CVE publication.


A Zero Day Vulnerability occurs when a software package has a vulnerability that becomes public knowledge and there is no approved patch available to fix it at the time it becomes public.

CVE-2022-22965

It is Remote Code Execution(RCE) vulnerability via data binding in the Spring framework, first reported by VMWare by coeplutos, meizhm3i of AntGroup FG.

RCE or Remote Code Execution is maliciously executing some code fragments which could either harm your application or effect the data integrity of your application.

This vulnerability impacts the Spring MVC and WebFlux framework running on JDK9+. This specific exploits requires the application to be running on Apache Tomcat server as a WAR deployment. A rather good thing is that the Vulnerability doesn't effect the Spring Boot deployment with Embedded Apache Tomcat Server.


However, Spring blog has quoted:

However, the nature of the vulnerability is more general, and there may be other ways to exploit it that have not been reported yet.

Your application is impacted if it is

  • Running on JDK 9 or higher,

  • Deployed as WAR using Apache Tomcat as servlet container,

  • Have spring-mvc and spring-webflux as dependency

  • Using Spring framework versions - 5.3.0 to 5.3.17 - 5.2.0 to 5.2.19 - and older versions

Mitigation

Spring has released the fix in Spring framework versions

  • 5.3.18 and

  • 5.2.20

For Spring Boot, use the versions 2.6.6 or 2.5.12 which depends on Spring Framework v5.3.18 newly released.


Suggested Workaround

These workarounds is required, if you are restricted to not upgrade you application to above versions. If you can upgrade than this is workaround is not required.


Adding to the fix from the leaked reports, Spring has documented a more fail-safe way to implement it.

Applications can extend RequestMappingHandlerAdapter to update the WebDataBinder at the end after all other initialization. In order to do that Spring boot application can declare a WebMvcRegistration bean or a WebFluxRegistration bean.

For example, the Spring boot application has to override createDataBinderFactory() to disallow these

  • class.*

  • Class.*

  • *.class.*

  • *.Class.*

So, now in the SpringBootApplication main class, we will add the webMvcRegistrations() which returns a new static inner class ExtendedRequestMappingHandlerAdapter.

@Bean
public WebMvcRegistrations webMvcRegistrations(){
    return new WebMvcRegistrations() {
        @Override
        public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
            return new ExtendedRequestMappingHandlerAdapter();
        }
    };
}

This ExtendedRequestMappingHandlerAdapter will override the createDataBinderFactory() method to disallow the above fields. We have added the extra fields to disallow in the new data binding factory.

private static class ExtendedRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {

    @Override
    protected InitBinderDataBinderFactory createDataBinderFactory(
        List<InvocableHandlerMethod> methods){
        return new ServletRequestDataBinderFactory(methods, 
            getWebBindingInitializer()){
            @Override
            protected ServletRequestDataBinder createBinderInstance(
                    Object target, 
                    String name, 
                    NativeWebRequest req
            ) throws Exception {
                ServletRequestDataBinder binder = 
                    super.createBinderInstance(target, name, req);
                String[] fields = binder.getDisallowedFields();
                List<String> fieldList = new ArrayList<>(
                        fields!=null  
                        ? Arrays.asList(fields)
                        : Collections.emptyList()
                );
                fieldList.addAll(
                    Arrays.asList(
                        "class.*", 
                        "Class.*", 
                        "*.class.*", 
                        "*.Class.*"
                    )
                );
                binder.setDisallowedFields(
                    fieldList.toArray(new String[]{})
                );

                return binder;
            }
        };
    }
}

Similarly, for Spring MVC without Spring Boot, application can switch from @EnableWebMvc to extending DelegatingWebMvcConfiguration directly.


So when we do @EnableWebMvc, it internally calls DelegatingWebMvcConfiguration, which:

  • Provide default Spring configuration for Spring MVC applications

  • Detects and delegates to WebMvcConfigurer implementations to customize that configurations.

So, now instead of enabling the annotation, we will directly extend the DelegatingWebMvcConfiguration class like this:

@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {

    // ...
}

Now, you can have existing methods in WebConfig, and also override different implementation of WebConfigurer on the classpath.


After extending , we need to override the createRequestMappingHandlerAdapter() method.


This is the not the first time a heavily used framework was impacted by vulnerabilities. Last time it was Log4j, which took some time to come up with their latest version 2.17.2 without any vulnerabilities reported yet.


Hope you like the content of the blog. Please do suggest more content topics of your choice and share your feedback. Also subscribe and appreciate the blog if you like it.


References


135 views0 comments

Recent Posts

See All