# Tabby心得

Table of Contents

Tabby环境配置

工具简介:Tabby 是一款用于分析 Java 项目的静态分析工具,旨在结合图数据库和静态程序分析技术完成常见漏洞的挖掘。安全研究员可以使用 Tabby 快速检索 Java 项目中可能存在的安全风险,也可以使用 Tabby 完成特定类、函数、调用关系等内容的快速定位。

tabyy 2.0 本地环境 JDK17

首先把以下三个文件下好

建好工作目录(从tabby-core里面复制必要目录):

Terminal window
$ tree
.
├── cases # 用于放置待分析的项目,可以是单个文件,也可以是目录
└── commons-collections-3.2.1.jar
├── config # 用于放置配置文件
├── db.properties # 配置数据库相关内容
└── settings.properties # 配置待分析项目、污点分析等内容
├── output # 用于放置生成后的csv文件
└── dev
├── rules # 规则文件夹
├── basicClasses.json
├── commonJars.json # 用于排除无需分析的三方jar
├── cyphers.yml # 用于 tabby-vul-finder 自动化检索
├── sinks.json # 用于配置 sink 函数
├── system.json # 用于配置专家规则
└── tags.json # 用于配置source点识别
├── temp # v2.0 版本开始将临时文件都生成到同级temp目录下
├── run.bat
├── tabby-vul-finder.jar # 用于导入和自动化查询的 jar
└── tabby.jar # 核心jar,用于生成图数据
Terminal window
@echo off
if "%1"=="build" (
java -Xmx16g -jar tabby.jar
) else if "%1"=="load" (
java -jar tabby-vul-finder.jar --load %2
) else if "%1"=="query" (
java -jar tabby-vul-finder.jar --query %2
) else if "%1"=="pack" (
tar -czvf output.tar.gz .\output\*.csv
) else (
echo Usage: %0 [build^|load^|query^|pack] [argument]
echo build - Run tabby.jar with 16GB memory
echo load - Load data using second argument
echo query - Query data using second argument
echo pack - Create tar.gz archive of CSV files
)

neo4j配置

下载好neo4j社区版(这里我不推荐下载desktop,插件会有问题)+ apoc插件

连同之前下好的tabby-path-finder一起放到neo4j的plugin目录里。

image-20250808102339260

然后在conf目录下:

image-20250808102056197

apoc.conf

apoc.import.file.enabled=true
apoc.import.file.use_neo4j_config=false

neo4j.conf 修改

# A comma separated list of procedures and user defined functions that are allowed
# full access to the database through unsupported/insecure internal APIs.
dbms.security.procedures.unrestricted=my.extensions.example,my.procedures.*,jwt.security.*,apoc.*,tabby.*
# A comma separated list of procedures to be loaded by default.
# Leaving this unconfigured will load all procedures found.
dbms.security.procedures.allowlist=apoc.*,tabby.*

初始化数据库

CREATE CONSTRAINT c1 IF NOT EXISTS FOR (c:Class) REQUIRE c.ID IS UNIQUE;
CREATE CONSTRAINT c2 IF NOT EXISTS FOR (c:Class) REQUIRE c.NAME IS UNIQUE;
CREATE CONSTRAINT c3 IF NOT EXISTS FOR (m:Method) REQUIRE m.ID IS UNIQUE;
CREATE CONSTRAINT c4 IF NOT EXISTS FOR (m:Method) REQUIRE m.SIGNATURE IS UNIQUE;
CREATE INDEX index1 IF NOT EXISTS FOR (m:Method) ON (m.NAME);
CREATE INDEX index2 IF NOT EXISTS FOR (m:Method) ON (m.CLASSNAME);
CREATE INDEX index3 IF NOT EXISTS FOR (m:Method) ON (m.NAME, m.CLASSNAME);
CREATE INDEX index4 IF NOT EXISTS FOR (m:Method) ON (m.NAME, m.NAME0);
CREATE INDEX index5 IF NOT EXISTS FOR (m:Method) ON (m.SIGNATURE);
CREATE INDEX index6 IF NOT EXISTS FOR (m:Method) ON (m.NAME0);
CREATE INDEX index7 IF NOT EXISTS FOR (m:Method) ON (m.NAME0, m.CLASSNAME);
:schema //查看表库
:sysinfo //查看数据库信息
image-20250808102736979
CALL apoc.help('all')
CALL tabby.help('tabby')

这两个命令不报错就是成功

IDEA插件

直接看文档 https://www.yuque.com/wh1t3p1g/tp0c1t/mxgt8v7yhguwmi0g

配置文件

具体根据不同场景修改请看原文:https://www.yuque.com/wh1t3p1g/tp0c1t/mgihyvp3vgscgt63

一些坑

  1. 如果你要自己编译vul-finder和path-finder的化可以用j11 + mvn3.9,实测不会报错。

  2. neo4j企业版才能新建数据库,直接用默认的neo4j database就好了

  3. IDEA插件想要成功跳转要把lib添加到项目库里面

    image-20250808103118820
  4. 设置onlyJDK分析后下一次想要改版本需要把工作目录下的jre_libs删除

  5. 若要使用tabby-vul-finder记得把其仓库里面的rulescopy到自己本地的rules里面,正确语句

Terminal window
.\run.bat query .\rules\cc-cb.yml

总体流程

先build出csv数据,然后load到你的neo4j数据库里面。接下来就开查。

Cypher & tabby-path-finder

Cypher 是 Neo4j 的声明式图查询语言。

其查询语句为返回子句

match (movie:Movie) where movie.rating > 7 return movie.title

这也反映了其特征

(nodes)-[:CONNECT_TO]→(otherNodes)。圆括号用于圆形节点,-[:ARROWS]→ 用于关系。

基本概念例子

// 节点用圆括号表示
(n) // 一个节点,变量名为n
(person) // 一个节点,变量名为person
(:Person) // 一个带标签Person的节点,没有变量名
(p:Person) // 一个带标签Person的节点,变量名为p
// 关系用方括号表示,在两个节点之间
-[r]-> // 有向关系,变量名为r
-[:KNOWS]-> // 有向关系,类型为KNOWS
-[k:KNOWS]-> // 有向关系,类型为KNOWS,变量名为k
-[]- // 无向关系
// 基本匹配
MATCH (n:Person) // 找所有Person标签的节点
MATCH (p:Person {name: "Alice"}) // 找name属性为Alice的Person节点
MATCH (p:Person)-[:KNOWS]->(f) // 找Person认识的所有人
//where 条件过滤
MATCH (p:Person)
WHERE p.age > 30 // 年龄大于30
WHERE p.name =~ "A.*" // 名字以A开头(正则表达式)
WHERE p.age IN [25, 30, 35] // 年龄在指定列表中
//with传递结果过
MATCH (p:Person)
WITH p, p.age * 2 AS doubleAge // 计算后传递给下一部分
WHERE doubleAge > 60
RETURN p.name
//collect聚合收集
MATCH (p:Person)-[:KNOWS]->(f)
WITH p, collect(f) AS friends // 将所有朋友收集到数组中
RETURN p.name, friends
//call调用过程
CALL db.labels() YIELD label // 调用系统过程
RETURN label
// 调用自定义过程
CALL my.procedure(param1, param2) YIELD result
RETURN result
//正则表达式
WHERE p.name =~ ".*Smith" // 以Smith结尾
WHERE p.email =~ ".*@gmail\\.com" // Gmail邮箱
WHERE p.code =~ "org\\.apache\\..*" // 以org.apache.开头

YIELD告诉Neo4j”我要从这个存储过程的返回结果中提取哪些字段”。

来分析一个tabby-path-finder的payload

match (source:Method {NAME:"toString"})
where source.CLASSNAME=~"org.apache.commons.collections.*"
match (sink:Method {NAME:"get", CLASSNAME:"java.util.Map"})
where sink.PARAMETER_SIZE=1
call tabby.algo.findJavaGadget(source, ">"sink, 5, false) yield path
// 黑名单
//where none(n in nodes(path) where
// n.CLASSNAME in [
// "java.io.ObjectInputStream",
// "java.util.concurrent.ConcurrentHashMap"
// ])
return path

最常用的函数就是 tabby.algo.findJavaGadget 其他函数参考文章:https://www.yuque.com/wh1t3p1g/tp0c1t/ta9ldsycan538ndf

其签名:

source: 源节点

>:分析方向

sinks: 目标节点数组

5: maxNodeLength - 最大路径长度为5个节点

false: isDepthFirst - 使用广度优先搜索(而非深度优先)

那这个payload其实就是首先起始点为:cc依赖下的toString方法 然后再找Map接口的get方法作为sink点,然后过滤一下黑名单(如果有的话

这里我分析的jar是commons-collections-3.2.2.jar

可以看到当长度调成4的时候,一共有5条链子

image-20250808114043019
  1. org.apache.commons.collections.DefaultMapBag#toString ->getCount ->getInteger->getNumber->map.get()

  2. com.sun.xml.internal.ws.client.Stub#toString->getStringId-> this.getRequestContext().get(“javax.xml.ws.service.endpoint.address”);

  3. sun.security.x509.AlgorithmId#toString->getName-> Map<ObjectIdentifier, String> nameTable.get()

  4. org.apache.commons.collections.bag.AbstractMapBag#toString -> getCount -> map.get

  5. org.apache.commons.collections.keyvalue.TiedMapEntry#toString -> getValue -> map.get

通过分析,链子2没有实现Serializable。其他都可以走。

如果长度设置为3就只有我们熟悉的TiedMap和AbstractMap了

My avatar

感谢阅读我的博客


More Posts

Comments