42CRUNCH BLOG


Lessons learned from the Spring4Shell vulnerability


Recently we published an article on the log4shell vulnerability targeting log4j, in which we explained how APIs can be protected against injection attacks with a positive security model, and how 42Crunch easily enables such a model. Now, it’s time for the Spring4Shell (CVE-2022-22965) vulnerability, targeting the Spring framework, commonly used to build APIs. What can we learn from this vulnerability?

Diving into Spring4Shell

The Spring team has published an article explaining the preconditions necessary for exploitation, and a workaround to prevent exploitation when upgrading the framework to 5.3.18 or 5.2.20 is not an option.

The conditions they list for exploitation are the following :

  • JDK 9 or higher
  • Apache Tomcat as the Servlet container
  • Packaged as a traditional WAR (in contrast to a Spring Boot executable jar)
  • 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

So the first thing to notice is that this attack relies a lot on the execution environment. But what is this vulnerability about? Let’s have a look at the workaround the Spring team give:

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

It seems the field names are the attack vector. Indeed this code snippet is a signature-based attack detection, in which the field names received by the Spring framework that look like « class.* », « Class.* », « *.class.* », or « *.Class.* » are rejected. What is harmful about fields being named like this?

It all boils down to the DataBinder. A DataBinder is an object that is used to set properties onto a target object. Spring uses a WebDataBinder, a child class of DataBinder, that binds web request parameters to JavaBean objects. Now, if we look at the Spring documentation for the DataBinder object:

“..Note that there are potential security implications in failing to set an array of allowed fields. In the case of HTTP form POST data for example, malicious clients can attempt to subvert an application by supplying values for fields or properties that do not exist on the form. In some cases this could lead to illegal data being set on command objects or their nested objects. For this reason, it is highly recommended to specify the allowedFields property on the DataBinder..”

It all comes together — the vulnerability is about modifying the name of a field used in a request to point to a specific class name, In order to modify properties of this class. In the case of this specific spring4shell exploit, the mechanism is the same as the previous CVE-2014-0094. Using crafted field names that designate the Tomcat logger class – hence, the need for a Tomcat environment – an attacker is able to modify the settings of the class. When something is logged, a JSP file is written on the root directory of the application instead, allowing code execution.

This attack only works because contrary to what is “highly recommended” by the Spring documentation for DataBinders, the field names received by the WebDataBinder from the client are not constrained to a finite list of allowed names. 

Conclusion

At 42Crunch we strongly agree with the DataBinder documentation: security should be implemented at design time, by strictly defining what is allowed and denying everything else. If the field names were restricted to only listed allowed names, this attack would never work.

This is what a positive security model is about and this is exactly what 42Crunch enables you to implement. Our API Security audit would have asked to define the allowed field names. Our API Conformance Scan service would then have made sure that only the defined field names were allowed by the API implementation.

Finally, to protect the API before it even reaches the Spring framework, our API firewall would have denied any request with a field name not explicitly allowed. If you want to read more about how this works when dealing with a vulnerability, you can read our previous article on log4shell.