tabby从入门到新链挖掘
字数 4282 2025-09-23 19:27:46

Tabby从入门到新链挖掘教学文档

一、前言

Tabby是一款基于代码属性图(CPG)和Neo4j图数据库的静态代码分析工具,主要用于Java反序列化利用链(Gadget Chain)的挖掘与分析。本文档系统介绍Tabby的安装、基础语法、实战老链复现与新链挖掘方法。


二、Tabby安装

推荐参考详细安装教程:
👉 Tabby安装指南

安装步骤概要:

  1. 安装JDK 11+、Maven、Neo4j 4.x。
  2. 克隆Tabby项目并编译。
  3. 配置Neo4j数据库并导入CPG数据。
  4. 启动Neo4j并访问Web界面进行查询。

三、语法学习

1. 基础语法

模式匹配与节点匹配

  • 使用MATCH进行模式匹配(类似SQL的SELECT)。
  • 节点类型:
    • (c:Class):类节点
    • (m:Method):方法节点
    • (f:Field):字段节点

示例:

MATCH (m:Method {NAME:"exec"})

等价于:

MATCH (m:Method) WHERE m.NAME = "exec"

节点属性

字段名 说明
SIGNATURE 方法签名(类全名+方法名+参数类型)
NAME 方法名(如readObject
CLASSNAME 类全限定名(如java.util.HashMap
IS_SINK 是否为危险方法(Sink)
IS_SOURCE 是否为入口方法(Source)
INTERFACES 实现的接口列表
SUPERCLASS 父类全限定名

字符串匹配操作符

操作符 说明 示例
= 精确匹配 m.NAME = "readObject"
CONTAINS 包含子串 m.CLASSNAME CONTAINS "Map"
STARTS WITH 前缀匹配 m.NAME STARTS WITH "get"
ENDS WITH 后缀匹配 m.CLASSNAME ENDS WITH "Impl"
=~ 正则匹配 m.NAME =~ "read.*"
IN 集合匹配 m.NAME IN ["readObject", "toString"]

2. 关系匹配

基本关系类型

关系类型 说明
:CALL 方法调用关系
:ALIAS 别名关系(同一对象引用)
:EXTENDS 类继承关系
:HAS 类包含字段或方法
:INTERFACE 接口实现关系

语法示例

  • 单向调用关系:
    (source:Method)-[:CALL]->(sink:Method)
    
  • 双向关系(不指定方向):
    (a)-[:CALL]-(b)
    
  • 多关系类型与可变路径长度:
    (a)-[:CALL|ALIAS*1..4]->(b)
    

3. 函数语法

APOC插件常用函数

函数名 说明 示例
apoc.algo.allSimplePaths 查找所有简单路径 CALL apoc.algo.allSimplePaths(a, b, "CALL", 5)
apoc.path.expand 自定义遍历路径 CALL apoc.path.expand(a, "CALL>", null, 0, 5)
apoc.path.subgraphAll 获取子图(所有节点和关系) CALL apoc.path.subgraphAll(a, {maxLevel:3})
apoc.path.spanningTree 最小生成树遍历 CALL apoc.path.spanningTree(a, {maxLevel:5})

Tabby内置函数

函数名 参数说明 返回值
tabby.algo.findPath source, direct, sink, maxNodeLength, isDepthFirst path, weight
tabby.algo.findPathWithState 同上,增加sinkState(污点条件) path, weight
tabby.algo.findJavaGadget 同上 path, weight
tabby.algo.findJavaGadgetWithState 同上,增加sinkState path, weight

四、老链练手(以Commons Collections为例)

1. 找到目标方法(Sink)

常见终点方法:

  • TiedMapEntry#toString / hashCode / equals
  • TransformedMap#transform
  • InvokerTransformer#transform

2. 使用Tabby进行查询

方法一:逐节点查找(可靠但繁琐)

示例:查找BadAttributeValueExpException#readObjectTiedMapEntry#toString

MATCH (source:Method {NAME:"readObject", CLASSNAME:"javax.management.BadAttributeValueExpException"})
MATCH (sink:Method {NAME:"toString", CLASSNAME:"org.apache.commons.collections.keyvalue.TiedMapEntry"})
CALL tabby.algo.findJavaGadget(source, true, sink, 10, true) YIELD path RETURN path

方法二:直接起点到终点(高效但可能含噪声)

示例:查找HotSwappableTargetSourceTiedMapEntry#equals

MATCH (source:Method {CLASSNAME:"org.apache.commons.proxy.HotSwappableTargetSource"})
MATCH (sink:Method {NAME:"equals", CLASSNAME:"org.apache.commons.collections.keyvalue.TiedMapEntry"})
CALL tabby.algo.findJavaGadget(source, true, sink, 10, true) YIELD path RETURN path

五、新链挖掘实战案例

案例:Transform方法触发toString

挖掘过程:

  1. 使用模糊查询寻找调用toString的方法:
    MATCH (m:Method) WHERE m.NAME CONTAINS "transform" AND m.CLASSNAME CONTAINS "Transform"
    MATCH (sink:Method {NAME:"toString"})
    CALL tabby.algo.findJavaGadget(m, true, sink, 5, true) YIELD path RETURN path
    
  2. 发现某Transform类中的valueOf方法调用了toString,且参数可控。
  3. 构造Payload触发计算器。

漏洞代码片段:

public Object transform(Object input) {
    return String.valueOf(input); // 触发input.toString()
}

利用条件:

  • 可控输入传入transform方法。
  • 触发链最终调用到toString方法。

六、总结与建议

  1. 熟练Cypher语法:尤其是路径查询与条件过滤。
  2. 理解Java反射与反序列化机制:有助于识别关键Sink点。
  3. 结合代码审计:Tabby辅助发现链段,人工分析确认可行性。
  4. 关注新组件:新库或版本更新可能引入新链。

如有错误或补充,欢迎指出!
👉 原文作者:follycat
👉 来源:先知社区(2025-09-09)


此文档已过滤无关内容,保留核心知识点与操作步骤,适合初学者系统学习与实战参考。

Tabby从入门到新链挖掘教学文档 一、前言 Tabby是一款基于代码属性图(CPG)和Neo4j图数据库的静态代码分析工具,主要用于Java反序列化利用链(Gadget Chain)的挖掘与分析。本文档系统介绍Tabby的安装、基础语法、实战老链复现与新链挖掘方法。 二、Tabby安装 推荐参考详细安装教程: 👉 Tabby安装指南 安装步骤概要: 安装JDK 11+、Maven、Neo4j 4.x。 克隆Tabby项目并编译。 配置Neo4j数据库并导入CPG数据。 启动Neo4j并访问Web界面进行查询。 三、语法学习 1. 基础语法 模式匹配与节点匹配 使用 MATCH 进行模式匹配(类似SQL的 SELECT )。 节点类型: (c:Class) :类节点 (m:Method) :方法节点 (f:Field) :字段节点 示例: 等价于: 节点属性 | 字段名 | 说明 | |---------------|----------------------------------------------------------------------| | SIGNATURE | 方法签名(类全名+方法名+参数类型) | | NAME | 方法名(如 readObject ) | | CLASSNAME | 类全限定名(如 java.util.HashMap ) | | IS_SINK | 是否为危险方法(Sink) | | IS_SOURCE | 是否为入口方法(Source) | | INTERFACES | 实现的接口列表 | | SUPERCLASS | 父类全限定名 | 字符串匹配操作符 | 操作符 | 说明 | 示例 | |----------------|------------------|-------------------------------------------| | = | 精确匹配 | m.NAME = "readObject" | | CONTAINS | 包含子串 | m.CLASSNAME CONTAINS "Map" | | STARTS WITH | 前缀匹配 | m.NAME STARTS WITH "get" | | ENDS WITH | 后缀匹配 | m.CLASSNAME ENDS WITH "Impl" | | =~ | 正则匹配 | m.NAME =~ "read.*" | | IN | 集合匹配 | m.NAME IN ["readObject", "toString"] | 2. 关系匹配 基本关系类型 | 关系类型 | 说明 | |-----------------|--------------------------| | :CALL | 方法调用关系 | | :ALIAS | 别名关系(同一对象引用) | | :EXTENDS | 类继承关系 | | :HAS | 类包含字段或方法 | | :INTERFACE | 接口实现关系 | 语法示例 单向调用关系: 双向关系(不指定方向): 多关系类型与可变路径长度: 3. 函数语法 APOC插件常用函数 | 函数名 | 说明 | 示例 | |----------------------------|--------------------------------|-------------------------------------------| | apoc.algo.allSimplePaths | 查找所有简单路径 | CALL apoc.algo.allSimplePaths(a, b, "CALL", 5) | | apoc.path.expand | 自定义遍历路径 | CALL apoc.path.expand(a, "CALL>", null, 0, 5) | | apoc.path.subgraphAll | 获取子图(所有节点和关系) | CALL apoc.path.subgraphAll(a, {maxLevel:3}) | | apoc.path.spanningTree | 最小生成树遍历 | CALL apoc.path.spanningTree(a, {maxLevel:5}) | Tabby内置函数 | 函数名 | 参数说明 | 返回值 | |--------------------------------------|--------------------------------------------------------------------------|---------------------| | tabby.algo.findPath | source , direct , sink , maxNodeLength , isDepthFirst | path , weight | | tabby.algo.findPathWithState | 同上,增加 sinkState (污点条件) | path , weight | | tabby.algo.findJavaGadget | 同上 | path , weight | | tabby.algo.findJavaGadgetWithState | 同上,增加 sinkState | path , weight | 四、老链练手(以Commons Collections为例) 1. 找到目标方法(Sink) 常见终点方法: TiedMapEntry#toString / hashCode / equals TransformedMap#transform InvokerTransformer#transform 2. 使用Tabby进行查询 方法一:逐节点查找(可靠但繁琐) 示例:查找 BadAttributeValueExpException#readObject → TiedMapEntry#toString 方法二:直接起点到终点(高效但可能含噪声) 示例:查找 HotSwappableTargetSource → TiedMapEntry#equals 五、新链挖掘实战案例 案例:Transform方法触发toString 挖掘过程: 使用模糊查询寻找调用 toString 的方法: 发现某Transform类中的 valueOf 方法调用了 toString ,且参数可控。 构造Payload触发计算器。 漏洞代码片段: 利用条件: 可控输入传入 transform 方法。 触发链最终调用到 toString 方法。 六、总结与建议 熟练Cypher语法 :尤其是路径查询与条件过滤。 理解Java反射与反序列化机制 :有助于识别关键Sink点。 结合代码审计 :Tabby辅助发现链段,人工分析确认可行性。 关注新组件 :新库或版本更新可能引入新链。 如有错误或补充,欢迎指出! 👉 原文作者:follycat 👉 来源:先知社区(2025-09-09) 此文档已过滤无关内容,保留核心知识点与操作步骤,适合初学者系统学习与实战参考。