【Java反序列化之tabby半自动化挖掘新URLDNS链】

一、半自动化挖掘反序列化



二、原理介绍

传统的静态代码分析有三种形式

1、AST(抽象语法树)语法层面分析

AST 是源代码的树状结构表示,由编译器在语法分析阶段生成。它去除了源代码中的无关字符(空格、注释、括号等),保留了程序的语法结构。

树形结构:每个节点代表一个语法结构

层次分明:反映代码的嵌套关系

无控制流信息:只关注语法,不关注执行顺序

2、CFG(控制流图) 控制流层面分析

CFG 是有向图,表示程序执行过程中所有可能的控制流路径。它以基本块为节点,以跳转关系为边。

基本块:

一段连续的代码,只有一个入口和一个出口

内部没有分支或跳转

3、PDG(程序依赖图) 数据依赖层面分析

PDG 结合了数据依赖和控制依赖,表示程序中语句之间的依赖关系。它是比 CFG 更精细的分析。

数据依赖:

定义-使用链:一个变量的定义如何影响另一个变量的使用

流依赖:先定义后使用

反依赖:先使用后定义

输出依赖:两次定义同一变量

控制依赖:

一个语句的执行是否依赖于另一个语句的条件

复制代码
if (cond) {    // 节点A
    x = 10;    // 节点B:控制依赖于A
}

tabby 的页面里可以很明显的看到起点和终点,而tabby的作用就是将调用链自动找出来,前提是我们得知道起点和终点

在java中代码会被转化成下面这样的图

图中的两个核心节点代表 Java 程序的两大基本元素:

橙色圆 (Class):代表一个 类。

紫色圆 (Method):代表一个 方法。

连接它们的箭头代表了在 CPG 中建立的不同类型的边,这些边是静态分析得出的关键关系:

这是 Tabby 工具的核心代码转化机制示意图。Tabby 是一个专门用于分析 Java 反序列化漏洞的静态代码分析工具,它通过构建一个增强版的 代码属性图(Code Property Graph, CPG)​ 来建模程序。

这张图清晰地展示了 Tabby 如何将 Java 代码中的关键元素(类和方法)以及它们之间的复杂关系,转化为一个可以进行高效查询和分析的图结构。

图释解析与 Tabby 的转化过程

图中的两个核心节点代表 Java 程序的两大基本元素:

橙色圆 (Class):代表一个 类。

紫色圆 (Method):代表一个 方法。

连接它们的箭头代表了在 CPG 中建立的不同类型的 边,这些边是静态分析得出的关键关系:

1. 节点间的核心关系 (HAS)

Class--HAS--> Method

含义:一个类 拥有​ 其内部定义的方法。

在 Tabby 中的作用:这是最基础的结构关系。通过遍历所有类并建立此边,Tabby 构建了程序的完整骨架,知道每个方法属于哪个类。

2. 围绕 Method(紫色圆) 的关系

这些关系描述了方法的行为和交互。

CALL

含义:一个方法 调用​ 另一个方法。

在 Tabby 中的作用:这是构建调用图(Call Graph)​ 的基础。Tabby 通过分析方法的字节码或 AST,识别出所有方法调用指令(如 invokevirtual, invokestatic等),并建立 CALL边。这是追踪程序执行流和漏洞利用链(Gadget Chain)最关键的路径

ALIAS

含义:两个方法可能是 别名​ 关系,即它们可能指向同一个实际的方法实现。

在 Tabby 中的作用:这通常是通过复杂的指针分析(Pointer Analysis)​ 或类层次分析(Class Hierarchy Analysis)​ 得出的。例如,在分析虚方法调用(如 object.toString())时,Tabby 需要解析 object的实际类型,来确定它具体调用的是哪个子类的 toString方法。ALIAS边将调用点与所有可能的目标方法连接起来,确保了分析的完备性,是解决多态调用的关键。

3. 围绕 Class(橙色圆) 的关系

这些关系描述了类的结构和类型系统。

EXTENDS

含义:一个类 继承​ 自另一个类(父类)。

在 Tabby 中的作用:建立类的继承层次结构。这对于方法解析至关重要(例如,子类可能重写父类方法),也是计算类转换(cast)是否合法的基础。

INTERFACE

含义:一个类 实现​ 了某个接口。

在 Tabby 中的作用:与 EXTENDS类似,用于完善类型层次结构。在 Java 中,接口也是寻找可利用方法(如 readObject、compare等)的重要来源。

对于一个class节点(下图显示的),tabby中的搜索只能对关键字搜索,不能搜索属性



下面例子中

复制代码
class A{
	foo(x){
		print(x)
	}
	main(){
		if (x<2)
			foo(x)
		else:
			y = 2 * x
		}
}

      (橙色) Class A
         /          \
        / HAS        \ HAS
       /              \
(紫色) Method foo  (紫色) Method main
                         |
                         | CALL
                         ↓
                   Method foo(再次出现,实际为同一节点)

了解了详细的原理,我们接着看下面的图,起点的readObject,终点是hashCode,首先我们确定

复制代码
match path=(source:Method {NAME:"readObject"})-[:CALL]->(m1:Method {NAME:"hash"})-[:CALL]->(m2:Method {NAME:"hashCode"})

(source:Method {NAME:"readObject"}):

这是一个节点模式,表示一个名为 readObject的 Method​ 节点。

source是该节点的变量名

-[:CALL]->:

表示要寻找一个方法

(m1:Method {NAME:"hash"}):

寻找名为 hash的方法。

连在一起就是找到 readObject调用hash方法,hash方法调用了hashCode方法的链,但实际我们并不知道中间的hash是什么,只知道起点和终点,所以就需要匹配

:CALL\*1...10\] 表示从起点到终点,中间的距离最多经过10个方法,最少经过1个方法,把所有的链路全部搜索出来 ## 三、污点传播分析 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4b3a7d098ff24bca87787c7432d09572.png) ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/dab40f255e684780938683236a118cef.png) ## 四、语法neo4j语法分析 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/83c41e62fa6d40718ec4e7f68204040c.png) [语法手册](https://neo4j.ac.cn/docs/cypher-manual/current/queries/concepts/) 输入的语法是找出所有名为 readobject 的方法 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/14432881304448b2bd3cbb2bf96b602d.png) 运行后就被找出来了 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6b8d77ba9b3a4d6b9a91ea52e21c47bf.png) 找出所有包含 readobject 方法的类 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/bdaa04ed5fef4a1095bea1dccd77c462.png) 上一次是用手工的方式找出的链路,这次用tabby自动找 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fa51dd98401049d494e04dddf67eec3e.png) 先找出hashmap类 ![hashmap是一个类,](https://i-blog.csdnimg.cn/direct/4fc29a8ed33d45c7a14145ddfaa33773.png) 找出hashmap类里所有的方法 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/056a54b5d9424088b17bcf866755b8c4.png) 也可以用HAS的方式去找 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/296ee80ad1574ccd8a7148decdfb1fda.png) 找到类里的readobject方法 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/54ff07f25d034d33b39ad21add65be0f.png) 找出readobject方法里 调用了 2-3 次的所有的方法 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/53e7a158af5846868602d7f7507d17b1.png) 因为我们知道了起点函数readobject和终点函数 getbyname 所以可以直接用匹配的方式找出所有的链接,但是tabby没有找出来 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/efcafc7c56c84444a92ecdbd16f373dc.png) 因为实际上hashcode是属于url类,不属于hashmap类所以没找出来,找出了两条链,一条是url,一条是soketPermission ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/028ba7b0ae75458a9767557b961cb54a.png) ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/39549d43725e48fdaf958043c1eacb4b.png) 就可以把新的调用链改进poc里面 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/319424b62e9248b4b9b79dddf6825ae5.png) tabb的安装可以百度

相关推荐
黄昏晓x1 小时前
C++----异常
android·java·c++
yaoxin5211232 小时前
330. Java Stream API - 处理 Optional 对象:像流一样优雅地使用 Optional
java·windows·python
aningxiaoxixi2 小时前
Android Audio 广播之 ACTION_AUDIO_BECOMING_NOISY
android·java·python
追随者永远是胜利者2 小时前
(LeetCode-Hot100)301. 删除无效的括号
java·算法·leetcode·职场和发展·go
追随者永远是胜利者2 小时前
(LeetCode-Hot100)239. 滑动窗口最大值
java·算法·leetcode·职场和发展·go
今心上2 小时前
spring中的@Autowired到底是什么
java·后端·spring
ShiJiuD6668889992 小时前
Java 异常 File
java·开发语言
lxl13072 小时前
C++算法(5)位运算
java·c++·算法
wuqingshun3141592 小时前
大致说一下程序、进程、线程
java·运维·服务器·开发语言