The main goal of this article is to analyze, summarize, and summarize the historical Spring framework vulnerabilities, so as to try to find out the potential patterns, in order to learn from the past. Of course, as a Java novice, before directly analyzing the vulnerabilities, we will first learn some core concepts in Spring from the developer’s perspective, so as to lay the foundation for the subsequent understanding.
Spring was originally created in 2003 as a competitor to J2EE due to the complexity of the early J2EE specifications and the lack of community input. As the years have passed, Spring has developed a complementary relationship with JavaEE, not embracing the JavaEE platform specifications, but integrating carefully selected individual specifications from it, such as Servlet, JPA, JMS, and so on.
When we talk about Spring, we can either refer to the Spring framework project itself or to the entire family of projects based on the Spring framework, and we can see more vulnerabilities in the projects on top of the framework when we introduce specific vulnerabilities later.
The Spring Framework is a powerful Java application framework designed to provide an efficient and scalable development environment. It is also inherently modular, and applications can select the modules they need. Examples include
spring-core, a module that contains the core container, configuration model, and dependency injection mechanism,
SpEL, a scripting engine, and the Servlet-based Spring MVC Web and Spring WebFlux frameworks.
In addition to the Spring framework itself, there are other projects such as Spring Boot, Spring Security, Spring Data, Spring Cloud, Spring Batch, etc., each with its own source code repository and versioning. A complete list of projects can be found at spring.io/projects. This section focuses on the core concepts and historical vulnerabilities of Spring Framework itself, other projects will be covered separately in the following sections.
Dependency Injection and IoC
Any article that introduces the Spring framework is inseparable from IoC, which is called Inversion of Control. Many articles on the web say that IoC/Dependency Injection is the process of constructing an instance of a bean from an XML configuration file through reflection, but they don’t explain the purpose of doing so.
To understand IoC, you need to understand Dependency Injection (DI) first. In Java, dependency injection is essentially a design pattern. The basic principle of Dependency Injection is that the application component should not be responsible for finding resources or other dependent collaborative objects, but the container should be responsible for configuring the objects, and the logic of finding resources should be extracted from the application component’s code and left to the DI container.
For example, suppose class A needs to use the methods of interface B. Then you need to establish an association, or dependency, between class A and interface B. The most primitive way is to create an instance of interface B in class A, but this approach requires the developer to maintain the dependencies manually and requires refactoring and modification of the code if the dependencies change. Dependency injection was created to solve this problem. With Dependency Injection, the dependencies are managed by the DI container, and the container configuration file only needs to be modified when the dependencies change.
In short, if a bean is a dependency of another bean, this usually means that one bean is set as a property of the other bean.
The objects that form the backbone of a user’s application in Spring and are managed by the Spring IoC container are called beans, which are similar in structure to Java beans but have their lifecycle managed by the Spring IoC container, and the Spring beans and their dependencies are reflected in the configuration metadata used by the container, which can come from XML configuration metadata can come from XML configuration files or Java annotations.
org.springframework.context packages are the basis for the Spring Framework’s IoC container, where the
BeanFactory interface provides a configuration mechanism that can manage any type of object.
ApplicationContext is a sub-interface of BeanFactory that represents the Spring IoC container responsible for instantiating, configuring and assembling beans; there are several common built-in implementations of this interface. For example,
One of the core features of the Spring framework is the IoC container, and for developers, all they need to do is tell the container which beans need to be managed, which is usually the Spring configuration process. two ways of configuring the IoC container are provided in Spring, XML-based configuration and annotation-based configuration.
An example of an XML-based configuration is shown below.
Spring reads the configuration file and creates the corresponding POJO object (bean) through the IoC container, manages its lifecycle and dynamically injects the corresponding dependencies.
A similar effect can be achieved by using annotations, as shown below.
Both approaches have their advantages and disadvantages, and both Spring provides a lot of detailed configuration methods, such as setting scopes, factory classes and constructor calling rules, etc. You can refer to the official documentation for detailed configuration methods.
As a Web framework, the Spring Framework naturally includes traditional Web MVC functionality at its core. As mentioned earlier, the Spring Framework is divided into modules, and the MVC framework has been a core module in Spring since the beginning, with code in the
spring-webmvc subdirectory of github.com/spring-projects/spring-framework. Its formal name is “Spring Web MVC”, and it is often referred to as Spring MVC. Note that this is a module in the Spring Framework and not a separate project.
Servlets are one of the key standards in Java EE web servers, and applications that meet the Servlet specification can be loaded and executed by the standard Servlet container. For Spring MVC, which also embraces this standard, an important Servlet is the DispatcherServlet, and from the 6.0 source code, the DispatcherServlet inheritance chain is as follows.
Like all other Servlets, we can register and initialize the
DispatcherServlet through the
ServletContext interfaces and implement web request processing by adding controllers. spring MVC provides an annotation-based programming model. The
@RestController components use annotations to express request mapping, request input, exception handling and more. Annotated controllers have flexible method signatures, do not need to inherit from base classes, and do not need to implement specific interfaces. Here is a simple example.
The controller example above accepts a Model instance and returns a string representing the view name; it can actually support a variety of flexible method signatures, which the Spring Framework will parse appropriately. A more common example is as follows.
@RequestMapping represents a shared mapping at the class level, while
@RestController can be thought of as a combination of
@ResponseBody means that the return of the controller method is bound directly to the return body of the Web request.
The Controller method can return a single asynchronous result by returning
Callable, or multiple asynchronous results by
SseEmitter, the recent hot ChatGPT streaming response is based on SSE (Server-Sent Events).
Spring MVC for the request and response to provide a flexible processing interface, here is only a general understanding of its basic methods, later introduced when the specific vulnerability to expand the introduction.
Spring WebFlux is an emerging web framework often compared to Spring MVC, introduced in Spring Framework 5.0 with the module name
spring-webflux . It is a web framework based on the reactive technology stack, with full asynchronous support, support for Reactive Streams backpressure and more.
Backpressure: A technical term for the amount that consumers can tell producers how much they need to avoid buffer overflows or data loss caused by higher generation rates than consumption rates.
The use of Spring WebFlux is similar to Spring MVC, with the major difference being that WebFlux supports reactive types in the model, such as
io.reactivex.Single<User>, as shown in the following simple example.
Spring MVC already supports asynchronous non-blocking, so why introduce WebFlux? One of the main reasons is performance, fully asynchronous processing can reduce the number of concurrent threads. And the introduction of the asynchronous API can take advantage of the lambda expression feature introduced in Java 8 for functional programming, allowing declarative combinations of asynchronous logic, as shown below.
SpEL is the Spring Expression Language, whose syntax is similar to the standard JUEL, but provides additional features such as method invocation and string templates for rich functionality. SpEL is one of the core parts of the Spring framework and is used in the XML configuration, annotations, and MVC controllers of the Spring framework.
Use SpEL to set the properties of a bean in XML.
Set the field defaults using SpEL in the annotation.
SpEL is derived from Spring, but can be used independently, for example.
It is worth noting that the
Expression.getValue method has several overloads, some of which accept an additional parameter of type
EvaluationContext. The EvaluationContext interface is used when evaluating expressions to resolve properties, methods or fields, and helps perform type conversions. provides two implementations, namely.
StandardEvaluationContext: supports all features and configuration options of the SpEL language, which is the default value;
SimpleEvaluationContext: provides only a subset of the basic functionality and configuration options of the SpEL language, for cases where the full functionality of the SpEL language is not needed and there are restrictions on expressions;
In general, the use of the default
StandardEvaluationContext with user-controllable expressions can lead to arbitrary Java code execution, when the
SimpleEvaluationContext is typically used to restrict the expression to access only a limited number of properties. A similar vulnerability can be seen later.
This section documents and analyzes some historical vulnerabilities in the Spring Framework. Since the Spring Framework itself is the foundation of the Spring meta-universe, vulnerabilities that occur have a wide impact and deserve our focused attention. For space reasons, we won’t go too far into the analysis here, and we’ll give links to the best existing analysis articles where possible.
Spring MVC allows developers to bind business objects (beans) to HTML forms and modify them with requests such as the one below.
If the business object
User is bound, then the request will end up executing
user.firstName = "Tavis" behind the scenes. This is implemented based on the JavaBean interface.
Spring also supports the use of complex settings, for example
user.address.street=Test will be converted to the following.
Since the Bean class inherits from
Object by default and the properties of the parent class are not filtered out during introspection, an attacker can call
frmObj.getClass().getClassLoader() by means of
class.classLoader to further modify the properties in the ClassLoader and resulting in arbitrary code execution. The initial author’s suggestion was to prevent the problem by specifying stopClass through
Introspector.getBeanInfo(Person.class, Object.class), but Spring actually fixed it by blacklisting, which also laid the groundwork for the subsequent bypass.
A detailed analysis can be found at:
Spring MVC can bind requested data to Bean objects, which can be forms, XML, JSON, etc. This vulnerability is an XXE injection issue caused by parsing XML external entities when binding XML requests to Bean objects. The sample Controller is as follows.
User is defined as follows.
The fix for this type of vulnerability depends on the XML API used.
- DOM: use
DocumentBuilderFactory.setExpandEntityReferences(false);to disable external entities;
- SAX: use
XMLReader.setFeature("http://xml.org/sax/features/external-general-entities", false);to disable external entities;
- Spring OXM: DOM-like and uses Jaxb2Marshaller to specify the DOMSource;
The key fix code for this vulnerability is as follows.
Detailed information can be found below.
- Fix potential security risk when using Spring OXM [SPR-10806]
- patch: Added ‘processExternalEntities’ to JAXB2Marshaller #317
- patch: Fix potential security risk when using Spring OXM
There are also several similar external entity injection vulnerabilities, such as CVE-2013-7315, CVE-2013-6429, in addition to the bypass CVE-2014-0054 caused by the incomplete fix above, as the above only fixes the
Jaxb2CollectionHttpMessageConverter and does not fix the
Jaxb2RootElementHttpMessageConverter . In general, it is still necessary to carefully audit the XML parsing processing-related functions, and I personally believe that this is also a major problem caused by the XXE function not being disabled by default.
Spring MVC, while being an MVC framework, also supports common features in web servers, such as static resource access. For example, we can configure XML to set the static resources we need to access, here is a simple
<mvc:resources> tag indicates that the request for the URL path
/resources is mapped to a static resource to a file under the relative path
/resources in the root of the web application.
Or you can add it via Java code, see spring-showcase.
The POC for this vulnerability is relatively simple, see the demo code below.
The cause of the vulnerability lies in the static resource parsing place, and the invocation link is as follows.
The relevant code is as follows (v4.1.1.RELEASE).
The problem is that
Resource#createRelative returns a result of
file:/etc/passwd. This led to a traversal of the subdirectory restriction implementation. The fix for this vulnerability has gone through multiple commits and can be found at the following link.
- cve-2014-3625: Directory Traversal in Spring Framework
- Directory traversal with static resource handling (CVE-2014-3625) [SPR-12354] #16959
- Spring MVC cve-2014-3625 demo
Another vulnerability derived from this vulnerability is CVE-2018-1271, namely arbitrary file reading under Spring MVC Windows, because the path filtering only considers
../, not considering the case of
\ in Windows, for more details, please refer to CVE-2018-1271: Directory Traversal with Spring MVC on Windows.
This vulnerability is a Spring Messaging remote code execution vulnerability. spring Messaging is also an optional module in the Spring framework, not described earlier, whose code module directory is
spring-messaging. it provides a mechanism for messaging between applications, most typically Websocket functionality, and on top of The most typical is the Websocket functionality, as well as the STOMP (Simple Text Oriented Messaging Protocol) protocol on top of Websocket, in addition to providing a mock alternative to SockJS for cases where Websocket is not supported.
Messaging is primarily targeted at full-duplex asynchronous transfers, and therefore also uses the common publish/subscribe mechanism. Multiple clients can subscribe to the same topic waiting for messages to achieve a chat room-like effect.
Returning to the vulnerability, the PoC is as follows, with the main feature being the addition of a custom
selector header when subscribing to
The selector is retrieved on the server side and executed as a
SpEL expression, as follows.
As mentioned earlier,
expression.getValue executes the corresponding expression, and if the content of the expression is controllable, it can lead to arbitrary code execution. The fix for this class is to set the execution context
SimpleEvaluationContext to restrict the behavior of expressions. For a specific patch, see the following link.
- patch: Re-use EvaluationContext in DefaultSubscriptionRegistry
- CVE-2018-1270: Remote Code Execution with spring-messaging
As seen in this vulnerability, there are many places within the Spring framework that use SpEL to implement dynamic filtering, attribute access, and other features that could cause unintended harm if left unchecked.
This is an RFD vulnerability in Spring Framework, a new web attack technique introduced in Blackhat EU 2014. The main idea of the attack is to achieve the file download function for the target domain through the feature of certain Web interfaces returning user requests, combined with the browser automatically downloading files and the technique of forging file suffixes in the URL. For example, the following domain name adds an extra suffix through the path parameter
;, so that the browser automatically recognizes the downloaded file as
ChromeSetup.bat, and the HTTP response contains the content of the GET parameter
q, and finally executes
calc.exe through the
|| feature of Windows commands, bypassing the previous useless data.
This is only a cursory introduction, and the details of the RFD vulnerability can be found in the original author’s white paper later in this article.
Back to Spring, this vulnerability causes RFD because when returning files through Spring’s interface, RFD can be achieved if the user can control some of the returned file names. Specifically, when using the
Content-Disposition header returned by the
org.springframework.http.ContentDisposition class, a user can affect the return header by controlling the malicious filename. The following two interfaces are primarily affected:
- Reflected File Download - A New Web Attack Vector
- CVE-2020-5398: RFD Attack via “Content-Disposition” Header Sourced from Request Input by Spring MVC or Spring WebFlux Application
- issue#24220: Escape quotes in filename in ContentDisposition.Builder when charset not specified
This vulnerability is the well-known Spring4Shell vulnerability, but in terms of the principle of the vulnerability, its core is actually a bypass of
CVE-2010-1622, which was described in the previous article. As mentioned earlier, when fixing
CVE-2010-1622, developers used a blacklist to restrict the bean property name to
protectionDomain, which did solve the problem at the time. However, with the introduction of Java 9, some new properties were introduced, such as
module, so you can use this property to bypass the above restriction and modify the classLoader again to achieve RCE.
However, the PoC for this vulnerability is actually a webshell write that takes advantage of Tomcat’s log writing feature. This is because there are more restrictions on how to directly modify the classLoader. Although there are many analysis articles on the Internet, most of them only debug the PoC single step, and do not mention the core of the vulnerability. I believe that the core of the vulnerability still lies in Spring for JavaBean introspection API improper use, that is,
Introspector.getBeanInfo does not specify the stopClass caused.
The patch for this vulnerability is divided into several commits, starting with the first patch.
Restricts the types of introspective get attributes. Blacklisted attribute types include .
- Attributes named content and of type URL
- Attributes that do not have a setter and are of type blacklisted include.
Then it was enhanced again two weeks later.
Class class is further restricted to allow only the name related properties in it. It’s full of patchiness, but it works!
Subsequent code updates put blacklisted properties like classLoader into
isInvalidReadOnlyPropertyType, which is what we see now.
The referenced article is as follows:
- SpringShell (Spring4Shell) Zero-Day Vulnerability CVE-2022-22965 : All You Need To Know
- Spring Framework Data Binding Rules Vulnerability (CVE-2022-22968)
- patch: Refine CachedIntrospectionResults property introspection
- patch: Refine PropertyDescriptor filtering
This section briefly studied some of the features and functionality of Spring Framework itself, and based on this, a few randomly selected relevant vulnerabilities were analyzed to try to have a preliminary understanding of the overall structure, history of vulnerabilities and code quality of Spring Framework. It can be found that the Spring Framework, as the cornerstone of the popular Web framework, has not had many serious vulnerabilities in its history, RCE-type vulnerabilities are more often found in SpEL, and the JavaBean binding in the MVC framework can be considered a unique attack surface. As a security researcher, on the one hand, we can analyze these historical attack surfaces in depth to discover new ways to bypass them; on the other hand, we can also look for new attack surfaces, which often have a greater impact.
It is worth mentioning that the vulnerabilities introduced here are not complete due to the author’s level of knowledge, and more Spring Framework vulnerabilities can be found in the official bulletin at Spring Security Advisories - springio/security
At the same time, for researchers who want to dive deep inside the Spring framework to find new attack surfaces, it might be a better option to carefully read its official documentation and debug and analyze it in conjunction with the source code at:
- Spring Framework Documentation (Spring Framework Chinese Documentation)
The Spring project has many rich projects besides the Framework itself, such as Spring Boot, Spring Data, Spring Security, etc. Each project has a separate code repository, which is different from the modules of the Spring Framework. The list of projects can be found in: spring.io/projects.
We will continue to study some of the mainstream Spring projects when we have time, so that we can have a deeper understanding of the local design in conjunction with the overall Spring ecosystem.