Home > Spring > Spring4Shell Vulnerability – Spring Core RCE Vulnerability

Spring4Shell Vulnerability – Spring Core RCE Vulnerability

Security researchers have found a new vulnerability around Spring Core, which may cause serious damage to millions of applications over the internet. This vulnerability is been said that exists in Spring core with java version JDK9.0 and above.

The bad news is no patch has been released yet by the Spring. But there are some strategies to mitigate the attack. Which we will discuss in the article.

Vulnerability Details

The attack requires an endpoint with DataBinder enabled, in addition, it depends largely on the servlet container for the application, mentioned in the Spring company blog.

The vulnerability impacts Spring MVC and Spring WebFlux applications running on JDK 9+. The specific exploit requires the application to run on Tomcat as a WAR deployment. If the application is deployed as a Spring Boot executable jar, i.e. the default, it is not vulnerable to the exploit.

Exploitation requires an endpoint with DataBinder enabled (e.g. a POST request that decodes data from the request body automatically) and depends heavily on the servlet container for the application.

For example, when Spring is deployed to Apache Tomcat, the WebAppClassLoader is accessible, which allows an attacker to call getters and setters to ultimately write a malicious JSP file to disk. But if the Spring is deployed using the Embedded Tomcat Servlet Container the classloader is a LaunchedURLClassLoader which has limited access.

In JDK9.0 and above version of the Spring, a remote attacker can obtain the AccessLogValve object and malicious field values, through the parameter binding function, thereby triggering the pipeline mechanism and writing arbitrary fields. file in the path.

Checking the Vulnerability

Check the java version of the application, if it is less than 9.0 then it is not affected by this vulnerability.

Get the application war/jar, uncompress it and look for the spring-beans-*.jar or CachedIntrospectionResuLts.class, if any of the above is present then the application can be vulnerable.

Some points to remember-

  1. if JDK >= 9.0
  2. Apache tomcat as deployment container
  3. spring-mvc or spring-webflux
  4. Packaged as WAR

Vulnerability Fixes

Spring Framework 5.3.18 and 5.2.20 have already been released.

If you are using Spring Boot directly – upgrade to version 2.6.6

If using maven –

<properties>
    <spring-framework.version>5.3.18</spring-framework.version>
</properties>

If Using Gradle

ext['spring-framework.version'] = '5.3.18'

A fail-safe workaround by Spring official blog

Applications could extend RequestMappingHandlerAdapter to update the WebDataBinder at the end after all other initialization. In order to do that, a Spring Boot application can declare a WebMvcRegistrations bean (Spring MVC) or a WebFluxRegistrations bean (Spring WebFlux).

For Spring MVC-

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.InitBinderDataBinderFactory;
import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ServletRequestDataBinderFactory;


@SpringBootApplication
public class MyApp {


	public static void main(String[] args) {
		SpringApplication.run(CarApp.class, args);
	}


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


	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 request) throws Exception {
					
					ServletRequestDataBinder binder = super.createBinderInstance(target, name, request);
					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;
				}
			};
		}
	}
}