Skip to content

Latest commit

 

History

History
120 lines (88 loc) · 9.96 KB

File metadata and controls

120 lines (88 loc) · 9.96 KB

生成tomcat-docbase需要的字节码(Docbase)

  • 类别bytecode 别名:— 优先级:—
  • 作者:—
  • 依赖:无声明依赖(构建期依赖 javassist;运行期由目标环境提供 Tomcat + fastjson)
  • 实现Gadget(无基类)

作用

一句话:把内层 gadget 产出的类字节码改写其父类为 java.lang.Exception,再交给上游写文件 gadget 落地到 Tomcat 的 docbase 目录,配合 fastjson 双 @type 技巧(CVE-2022-25845 类漏洞)加载并实例化该恶意类,实现 RCE。

Docbase 本身不产生攻击字节码,也不写文件不发起加载;它是链条中间的一个「字节码后处理」环,唯一职责是给类打上 extends java.lang.Exception 的标记,以满足 fastjson autoType 加载时的类型校验约束。

链接标签

  • 入口 tagsBytecodeDocbaseTag —— 表示本 gadget 能承接「nextTags 声明为 BytecodeDocbaseTag」的上一环。在本知识库中该上一环即 fastjson 写文件类 gadget(见下「关联」),它们把 Docbase 的输出写入 docbase 路径。
  • 衔接 nextTagsBytecodeConvertTag —— 表示 Docbase 之后(doCreate 取到的内层)必须是一个标记了 BytecodeConvertTag 的 gadget,即 BytecodeConvert。BytecodeConvert 负责把最内层字节码 sink 的产物改名为攻击者指定的类名、按需混淆,然后交给 Docbase 改父类。
  • excludes:无。

标签方向要点:按知识库约定,外层 gadget 的 nextTags 必须匹配内层 gadget 的 tags。因此实际链条(配置顺序,外→内)为:

[ Fastjson写文件Gadget , Docbase , BytecodeConvert , <字节码 sink,如 Exec> ]
   tags=FastjsonPayload      tags=BytecodeDocbaseTag   tags=BytecodeConvertTag   tags=Bytecode/END
   nextTags=BytecodeDocbaseTag  nextTags=BytecodeConvertTag  nextTags=Bytecode

执行方向相反(内→外,见 BUILD-SPEC 第 3 节):字节码 sink 先产出攻击字节码 → BytecodeConvert 改名/混淆 → Docbase 改父类为 Exception → Fastjson 写文件 gadget 把结果写盘并生成 fastjson 触发 payload。

源码剖析

Docbase 是一个极简的字节码处理 gadget,全部逻辑集中在 getObjectinvoke 两个方法:

@GadgetTags(tags={"BytecodeDocbaseTag"}, nextTags={"BytecodeConvertTag"})
@GadgetAnnotation(name="生成tomcat-docbase需要的字节码", description="参考 …CVE-2022-25845-In-Spring…")
public class Docbase implements Gadget {

    public byte[] getObject(byte[] bytes) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
        CtClass cc = pool.makeClass((InputStream)bis);        // 从传入字节码重建 CtClass
        CtClass exceptionClass = pool.get("java.lang.Exception");
        cc.setSuperclass(exceptionClass);                     // 关键:把父类强改为 java.lang.Exception
        return cc.toBytecode();                               // 重新导出字节码
    }

    @Override
    public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
        byte[] bytecode = (byte[])chain.doCreate(context);    // 取内层(BytecodeConvert)产出的字节码
        return this.getObject(bytecode);
    }
}

逐段解释:

  • invokechain.doCreate(context):链由内向外构建。doCreate 触发内层 BytecodeConvert,得到一段已改名/可选混淆的类字节码(byte[])。这段类内部通常带有攻击载荷——例如最内层为 Exec 时,类的静态代码块/构造逻辑会执行 ProcessBuilder 命令。

  • pool.makeClass(bis):用 javassist 的 ClassPool 从字节数组重建一个可编辑的 CtClass 对象。

  • cc.setSuperclass(pool.get("java.lang.Exception")):这是本 gadget 的唯一实质操作,也是整条 docbase 利用的命门。fastjson 的 autoType 触发点使用双 @type 写法:

    {
      "@type":"java.lang.Exception",
      "@type":"org.example.Exception"
    }

    第一个 @type 让 fastjson 把 expectClass 设为 java.lang.Exception(异常类在很多黑名单/开关下仍被允许自动加载,因为反序列化异常本是常见需求);第二个 @type 给出真正要加载的类名 org.example.Exception。fastjson 在加载后会用类似 expectClass.isAssignableFrom(loadedClass) 的类型校验来「放行」——只有当目标类确实是 java.lang.Exception 的子类时才会被实例化。Docbase 的 setSuperclass 正是为了让攻击者自造的类满足这一「必须继承 Exception」约束,否则加载会因类型不匹配被拒。

  • cc.toBytecode():导出改写后的字节码,返回给上层(fastjson 写文件 gadget),后者将其写入形如 /tmp/tomcat-docbase.<随机后缀>/WEB-INF/classes/org/example/Exception.class 的路径。

文件路径必须与类名一致(description 明示):因为最终由 Tomcat webapp 的 WebappClassLoader 按全限定类名去 docbase 的 WEB-INF/classes 下按目录结构定位 .class 文件。若类名为 org.example.Exception,则文件须落在 WEB-INF/classes/org/example/Exception.class

参数(@Param)

本 gadget 无任何 @Paramparams 为空数组),不接受用户配置。目标类名、写入路径、fastjson 版本等参数由链上其它 gadget 提供:

需要的配置 由谁提供
攻击载荷(命令/字节码逻辑) 最内层字节码 sink,如 Exec
目标类名(改名) BytecodeConvert
落地路径 DestPath / fastjson 版本 / Writer 上游 fastjson 写文件 gadget,如 FastjsonCmonsio

适用版本与原理要点

  • 利用背景:description 指向 https://github.com/luelueking/CVE-2022-25845-In-Spring。CVE-2022-25845 是 fastjson 1.2.80 及之前 autoType 在「期望类型为异常类」等特定条件下可加载攻击者指定类的问题;当 Tomcat 的 docbase 目录可写(存在文件写入原语)时,把恶意类写进 webapp 的 classpath 再触发加载即可 RCE。
  • 两个前置能力缺一不可
    1. 文件写入原语:能把 .class 写到 Tomcat docbase 的 WEB-INF/classes 下。本工具用 fastjson + commons-io 的写文件链实现(FastjsonCmonsioFastjsonWriteFileJDK11),其 DestPath 默认即 /tmp/tomcat_docbasexxx/WEB-INF/classes/xxx.class
    2. 类加载触发:fastjson autoType 用双 @typeWebappClassLoader 加载并实例化刚写入的类,触发其静态块/构造逻辑。
  • 为什么必须继承 java.lang.Exception:这是绕过 fastjson 期望类型校验的硬约束——@type:"java.lang.Exception" 使加载被限定为 Exception 子类,Docbase 的 setSuperclass 就是把任意攻击类「伪装成」异常子类。若跳过 Docbase 直接写普通类,fastjson 会因类型不匹配拒绝实例化。
  • 环境要求:目标运行 Tomcat 且已知/可控 docbase 临时目录(Spring Boot 内嵌 Tomcat 部署 war/解压场景常见);fastjson 版本落在受影响区间;WebappClassLoader 能从 WEB-INF/classes 加载。
  • javassist 依赖:Docbase 在构建 payload 的一方(java-chains 运行端)使用 javassist 改父类,目标机不需要 javassist。反编译头部 Could not load the following classes: javassist.ClassPool / javassist.CtClass 属正常(CFR 缺该第三方依赖),不影响逻辑分析。

所属预设链

usedInChains 为空——自由构件,未直接出现在 51 条预设链中。它需与 fastjson 写文件 gadget、BytecodeConvert 及字节码 sink 手工组合成 docbase 利用链。

关联

  • 上游(外层,nextTags=BytecodeDocbaseTag:fastjson 写文件 gadget——FastjsonCmonsioFastjsonWriteFileJDK11。它们把 Docbase 输出的类字节码写入 docbase 路径并生成 fastjson 触发 payload。
  • 下游(内层,tags=BytecodeConvertTagBytecodeConvert——把最内层字节码 sink 的产物改名为目标类名并按需混淆。
  • 最内层字节码 sinkExec 等(tagsBytecode/END),提供实际 RCE 载荷。

防御与检测

  • 检测特征
    • 文件系统监控 Tomcat docbase / 临时工作目录(如 catalina.hometomcat-docbase.*/tmp/tomcat_docbase*)中 WEB-INF/classes/**/*.class运行时新增/写入——正常应用不会在运行期动态往 docbase 写 class。
    • 恶意类的父类为 java.lang.Exception 却带静态块/异常构造中执行命令,是本技术的强指纹:审计落盘 class 的常量池是否 super=java/lang/Exception 且方法体引用 java/lang/ProcessBuilderRuntime
    • 流量层:请求体出现双 @type 且首个 @typejava.lang.Exception(或 java.lang.AutoCloseablejava.io.InputStream 等被工具替换的期望类型),以及 org.apache.commons.io.output.LockableFileWriter / WriterOutputStream / BOMInputStream 等 commons-io 写文件类名。
  • 加固建议
    • 升级 fastjson 至已修复版本并关闭 autoTypesafeMode),从根本上阻断双 @type 加载。
    • 收敛 docbase / webapp 临时目录写权限,禁止应用运行用户对 WEB-INF/classes 可写;隔离/只读挂载。
    • Web 层禁用不必要的 commons-io 反序列化目标类;对 fastjson 输入做白名单类型校验。
    • 运行期启用 WebappClassLoader 加载审计,对从 docbase 动态加载的类告警。

参考

  • 反编译源码:
  • 机器可读元数据:../../index/gadgets.json
  • CVE-2022-25845(fastjson autoType)与 docbase 利用:https://github.com/luelueking/CVE-2022-25845-In-Spring