Spring4Shell: Spring Confirmed the RCE in Spring Framework, Advisory Released

Spring Framework RCE, Patch has been released

 

Spring4Shell RCE Exploit

Update: 
  • Apache Tomcat releases versions 10.0.20, 9.0.62, and 8.5.78 as part of the mitigation effort.
  • Manual Workarounds for Apache Tomcat upgrades and Java 8 downgrades
After more than 24 hours of the disclosure of the vulnerability, remote code execution in Sproing core aka Spring4Shell, finally, we have a statement from the Spring side and now vulnerability can be tracked as CVE-2022-22965.

Just now Spring team has published a blog post acknowledging an RCE vulnerability in the Spring Framework, that does not have a CVE id yet with CVE-2022-22965. The spring team wrote that the vulnerability was reported on Tuesday evening to VMware by codeplutos, meizjm3i of AntGroup FG. After getting notification of the issue, the Spring Security team started the investigation, analysis, identifying a fix, and testing for the emergency releases. 

"In the meantime also on Wednesday, the vulnerability was leaked in full detail online, which is why we are providing this update ahead of the releases and the CVE report.- they wrote"

Vulnerability Details and Prerequisites

The vulnerability impacts Spring MVC and Spring WebFlux applications running on JDK 9+. The specific exploit requires the application to be packaged as a WAR and deployed to Apache Tomcat. This does mean the exploit does not work for Spring Boot with embedded Tomcat. However, the nature of the vulnerability is more general, and there may be other ways to exploit it.

You may want to read this post :

Regarding the prerequisites to exploit the vulnerability, we have already reported. These are the requirements for the specific scenario from the report:

  • JDK 9 or higher
  • Apache Tomcat as the Servlet container
  • Packaged as WAR
  • spring-webmvc or spring-webflux dependency
  • Spring Framework versions 5.3.0 to 5.3.17, 5.2.0 to 5.2.19, and older versions.

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

Mitigation to fix the Vulnerability

Currently, Spring Framework 5.3.18 and 5.2.20 have already been released. The corresponding Spring Boot releases are in progress and the spring team has noted that the fix will get released in a few hours.

After a couple of hours of the initial post, just now Spring team has released the latest versions Spring Boot 2.6.6 and 2.5.12 that depend on Spring Framework 5.3.18 to patch the vulnerability.

To upgrade with Maven the Spring Framework version in a Boot application:

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

To upgrade with Gradle

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

According to the leaked reports, the mitigation that we have already reported, recommends setting disallowedFields  on WebDataBinder through an @ControllerAdvice:

@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
public class BinderControllerAdvice {

    @InitBinder
    public void setAllowedFields(WebDataBinder dataBinder) {
         String[] denylist = new String[]{"class.*", "Class.*", "*.class.*", "*.Class.*"};
         dataBinder.setDisallowedFields(denylist);
    }

}

The spring team says the above setting does work to fix the issue but as a centrally applied workaround fix, may leave some loopholes, in particular, if a controller sets disallowedFields locally through its own @InitBinder method, which overrides the global setting. 

To apply the workaround in a more fail-safe way, 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).

package car.app;

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 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 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;
				}
			};
		}
	}
}

The Spring security team noted-

For Spring MVC without Spring Boot, an application can switch from @EnableWebMvc to extending DelegatingWebMvcConfiguration directly as described in the Advanced Config section of the documentation, then overriding the createRequestMappingHandlerAdapter method.

Apache Tomcat releases udate as part of the mitigation effort

After the release of the Spring Framework RCE vulnerability CVE-2022-22965, listing Apache Tomcat as one of several preconditions. The Apache Tomcat team has since released versions 10.0.20, 9.0.62, and 8.5.78 all of which close the attack vector on Tomcat’s side. While the vulnerability is not in Tomcat itself, in real-world situations, it is important to be able to choose among multiple upgrade paths that in turn provide flexibility and layered protection.

Upgrading to Spring Framework 5.3.18+ or 5.2.20+ continues to be our main recommendation not only because it addresses the root cause and prevents other possible attack vectors, but also because it adds protection for other CVEs addressed since the current version in use.

For older, unsupported versions of the Spring Framework, the Tomcat releases provide an adequate solution for the reported attack vector. This is only a defensive solution, users should still be to upgrade to a currently supported Spring Framework version as soon as possible.

It’s worth mentioning that downgrading to Java 8 provides another viable workaround, which may be another defensive solution option.

Workarounds for Apache Tomcat upgrades and Java 8 downgrades

As we have mentioned that updating to Spring Framework 5.3.18 and 5.2.20 or greater is our main recommendation. If you have done this, then no workarounds are necessary. However, some may be in a position where upgrading is not possible to do quickly. For that reason, we have provided some workarounds below.

  • Upgrading Tomcat
  • Downgrading to Java 8
  • Disallowed Fields

Please note that workarounds are not necessarily mutually exclusive since security is best done “in-depth”.

Upgrading Tomcat

For older, unsupported Spring Framework versions, upgrading to Apache Tomcat 10.0.20, 9.0.62, or 8.5.78, provides adequate protection. However, this should be seen as a tactical solution, and the main goal should be to upgrade to a currently supported Spring Framework version as soon as possible. If you take this approach, you should consider setting Disallowed Fields as well for a defense-in-depth approach.

Downgrading to Java 8

Downgrading to Java 8 is a viable workaround if you can neither upgrade the Spring Framework nor upgrade Apache Tomcat.

Disallowed Fields

Another viable workaround is to disable binding to particular fields by setting disallowedFields on WebDataBinder globally:

@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
public class BinderControllerAdvice {

    @InitBinder
    public void setAllowedFields(WebDataBinder dataBinder) {
         String[] denylist = new String[]{"class.*", "Class.*", "*.class.*", "*.Class.*"};
         dataBinder.setDisallowedFields(denylist);
    }

}

Confusion with Spring Cloud Function Vulnerability.

As we have reported earlier, there are huge misconceptions going around the social media and post comments section about the Spring Cloud Function Vulnerability and Spring Framework RCE. Both of these vulnerabilities are different, Spring Cloud Function Vulnerability is been tracked as CVE-2022-22963, which is a Spring Expression Resource Access Vulnerability. Whereas Spring Framework RCE bug is another one and now can be tracked as CVE-2022-22965 that doesn't have CVE id at this time and vulnerability impacts Spring MVC and Spring WebFlux applications running on JDK 9+.

Post a Comment