dongtai agent分析
Yg 发表于 浙江 安全工具 474浏览 · 2025-04-23 06:12

iast实现

DongTai IAST Java Agent 是一个交互式应用安全测试工具,通过字节码插桩技术实现对Java应用的安全监控。技术原理还是基于java agent+ASM的技术;

项目代码:https://github.com/HXSecurity/DongTai-agent-java.git

项目有多个模块,

iast-agent启动模块;主要是进行项目启动加载各个引擎;

iast-core关键的插桩模块,本项目的核心;

iast-spy等其他模块,不做过多介绍说明;

启动流程简析

1io.dongtai.iast.core.AgentEngine.run() start()等生命周期控制方法,这里主要包含两部分:

a ConfigEngine.init加载iast的sink/source/propagator/http 相关规则hook点,这部分后续介绍;

bTransformEngine.start DongTai IAST Java Agent 实现字节码插桩的核心部分,它负责拦截和修改正在加载的 Java 类的字节码;这部分主要是 :inst.addTransformer(); classFileTransformer.reTransform();这两个关键方法;具体实现在下面IastClassFileTransformer内

2IastClassFileTransformer.transform 插桩的关键,采用ASM对关键方法进行hook;具体步骤可参考下文

a判断类是否需要转换(根据策略配置和类名过滤)

b构建类上下文和继承关系

c通过插件系统对类进行转换:ClassVisitor cv = plugins.initial(cw, classContext, policyManager);

d插入监控代码,用于后续的污点分析:cr.accept(cv, ClassReader.EXPAND_FRAMES);

e返回转换后的字节码

3 PluginRegister.initial - 创建处理链.

aDispatchApiCollector():针对 Spring MVC/Spring Boot 应用的插件。处理 Spring MVC 控制器和 API 端点,收集 API 信息,监控 API 的响应数据处理。

bDispatchJ2ee():处理 Java EE/Jakarta EE 相关的组件。处理 Servlet 容器和 HTTP 请求/响应。

cDispatchKafka()

dDispatchJdbc():处理 JDBC 相关操作,检测 SQL 注入的关键点,监控 SQL 语句的构造和执行;

eDispatchShiro()

fDispatchFeign()

gDispatchDubbo()

hDispatchClassPlugin()这个iast更为关键的点,上面是针对框架或者相关功能的扩展实现,本处理链是通用类插桩,加载所有相关污点分析的关键逻辑;

TransformEngine引擎

transform 方法执行流程

transform 方法是 DongTai IAST Java Agent 实现字节码插桩的核心部分,它负责拦截和修改正在加载的 Java 类的字节码。

DongTai IAST 的字节码插桩过程遵循以下流程:

1判断类是否需要转换(根据策略配置和类名过滤)

2构建类上下文和继承关系

3通过插件系统对类进行转换

4插入监控代码,用于后续的污点分析

5返回转换后的字节码

transform 方法在 IastClassFileTransformer 类中实现,作为 Java Instrumentation API 的关键方法,当 JVM 加载一个新类时会自动调用它:

1前置过滤

1特殊类处理和组件识别

2策略匹配和过滤

3类信息准备和继承关系分析

4执行字节码转换

PluginRegister链

PluginRegister的逻辑,最关键的在于最后添加的DispatchClassPlugin。负责将安全策略与字节码转换联系起来,实现精确的方法级插桩。

关键在于ClassVisit.visitMethod方法。最关键在于visitMethod中的lazyAop方法:

1 关键组件 - MethodAdapter 数组,这些适配器会在 MethodAdviceAdapter 中被使用,根据策略节点的类型选择适当的适配器进行具体的字节码插桩操作。

a SourceAdapter: 处理污点源,识别外部输入

b PropagatorAdapter: 处理污点传播,跟踪数据流动

c SinkAdapter: 处理危险方法调用点

d ValidatorAdapter: 处理验证器,检测数据是否经过安全检查

2policy.getPolicyNodesMap()获取之前规则引擎之前加载的所有服务端规则;

3 遍历每个策略节点,使用其 MethodMatcher 检查当前方法是否匹配。如果有匹配的策略节点,创建一个 MethodAdviceAdapter 实例,并标记类已被转换。

4 MethodAdviceAdapter进行MethodAdapter中不同的适配器进行处理。主要是onMethodEnter、onMethodExit方法;

5 而其中几乎所有的MethodAdviceAdapter中都有一个AbstractAdviceAdapter.trackMethod方法,而正是该方法定义了污点的处理过程,也就是漏洞的处理逻辑;而具体实现则是由SpyDispatcherImpl.collectMethod;

MethodAdviceAdapter在处理字节码时,会根据策略节点的类型,选择对应的适配器进行处理。这也就是IAST系统处理的核心;

规则加载

ConfigEngine.init()方法进行加载相关source、sink等规则点;

之后在policyManager.loadPolicy中PolicyBuilder.fetchFromServer()进行服务端请求获取相关规则,之后经过一系列的规则处理,保存到了Policy中的policyNodesMap中;

最终会在lazyAop中的Map<String, PolicyNode> policyNodesMap = this.policy.getPolicyNodesMap()中进行相关规则的获取使用;

规则实现

前文我们知道所有的MethodAdviceAdapter中都有一个AbstractAdviceAdapter.trackMethod方法进行污点处理;在这里我们看下具体的实现;

1 插桩位置

Source/Propagator/Validator: 主要在方法返回前插桩 (onMethodExit)

Sink: 主要在方法执行前插桩 (onMethodEnter)

2 收集数据

Source: 收集外部输入数据,标记为污点

Propagator: 记录数据转换和传递过程

Sink: 检查输入参数是否包含污点数据

Validator: 记录数据验证操作

3 调用方法

各适配器调用 SpyDispatcher 接口的不同方法

传递不同的参数和上下文信息

source/sink/Propagato等处理

这里首先看下在不同sink、source等位置的具体实现

SourceAdapter:

ValidatorAdapter:

PropagatorAdapter:

SinkAdapter:

ASM进行hook的AbstractAdviceAdapter.trackMethod方法;

SpyDispatcher 接口(通过 SpyDispatcherImpl 实现)是连接字节码插桩和实际污点分析的桥梁:

当插入的监控代码执行 collectMethod 时,SpyDispatcherImpl 会根据策略类型做不同处理:

1 Source 处理:将外部输入标记为污点,创建 TaintValue 对象记录污点信息

2 Propagator 处理:检查输入参数是否包含污点,如果包含,将返回值也标记为污点,并计算新污点的范围

3 Sink 处理:检查输入参数是否包含污点,如果发现污点到达危险函数,就触发安全检查

4 Validator 处理:记录数据验证操作,更新污点的安全状态

SpyDispatcherImpl.collectMethod方法

漏洞检测

具体的漏洞检测及污点跟踪可参考,讲解的很明白:https://m0d9.me/2022/10/18/DongTai-IAST-分析/

其实不同漏洞在sink点是不同的处理逻辑,这个主要是 io.dongtai.iast.core.handler.hookpoint.vulscan.dynamic.DynamicPropagatorScanner#scan 中实现;

而后面的sinkSourceHitTaintPool方法则是关于污点跟踪的实现:

上面的检测有个关键点就是污点标签系统

每种漏洞类型都有两组标签:

1 必须存在的标签:污点数据必须具有的特征(如 UNTRUSTED 表示不可信数据)

2 不应存在的标签:如果污点数据具有这些标签,则不视为漏洞(如 HTML_ENCODED 表示数据已经过 HTML 转义,不会导致 XSS)

这种设计允许做到了以下区分:

确实存在的漏洞(污点数据未经适当处理)

假阳性(污点数据经过了适当的验证或转义)

污点跟踪

在不同的solve处理逻辑中对于污点跟踪的方式主要按照下面的三个重要数据结构处理;

io.dongtai.iast.core.EngineManager:

结合上下文可以说明

TRACK_MAP:保存方法调用事件和调用关系的线程局部缓存,它记录了应用执行过程中的方法调用链信息。

存储所有被监控的方法调用事件(Source、Sink、Propagator)

根据调用ID维护方法调用之间的关系

为漏洞检测提供完整的调用链上下文

支持重构污点从源头到危险点的完整传播路径

TAINT_HASH_CODES:记录被污点标记对象哈希码的线程局部集合,用于快速判断对象是否被污染。

提供快速查找机制,判断对象是否为污点

使用哈希码而非对象引用,降低内存占用

支持高效的污点检测操作

避免重复处理同一个污点对象

TAINT_RANGES_POOL:存储污点数据详细信息的线程局部映射,记录每个污点对象的污染范围和标签。

存储污点数据的详细信息,包括污染范围和标签

支持部分污染的精细跟踪(例如,字符串中只有部分字符是污点)

维护污点数据的安全处理状态(如已转义、已验证等)

为漏洞检测提供污点特性信息

这三个数据结构协同工作,共同实现了 DongTai IAST 的完整污点跟踪和漏洞检测流程:

1、污点标记阶段(source):

source:O、P

target:O、P、R

io.dongtai.iast.core.handler.hookpoint.controller.impl.SourceImpl#solveSource

如果method return为空或者为原始类型之类的无效污染、并且如果method 为getAttrribute,那么仅允许白名单内的arg,否则推出;

*trackTarget* 方法用来将source 的returnInstance结果放入了 EngineManager.TAINT_HASH_CODES/TAINT_RANGES_POOL 污点池中:如果结果是Map、Collection、Array之类的,会进一步遍历其所有值,都加入TAINT_HASH_CODES/TAINT_RANGES_POOL

将event 加入EngineManager.TRACK_MAP 中

2、 污点数据传播阶段

PropagatorImpl#solvePropagator

source:O、P

target:O、P、R

当污点数据在应用中流动和转换时:

当存在污点链则进行传播节点处理,首先根据规则propagatorNode.getSources()判断source是否命中污点链,如果存在则标记hasTaint可以进行下一步;

命中source后执行setTarget(propagatorNode, event)判断target逻辑,将target计算hast将结果录入TAINT_HASH_CODES,并根据污点标签系统标记污点位置,并录入TAINT_RANGES_POOL



3、漏洞检测阶段

这部分可以参考前文漏洞检测部分,在sink中之处理source,因为污点到达sink就说明是触发了危险方法(当然还是要看规则完整性)

source:O、P

当污点数据到达危险方法(Sink 点)时,下面是简单分析逻辑的伪代码:





参考文章

https://su18.org/post/dongtai/#

https://m0d9.me/2022/10/18/DongTai-IAST-分析/

https://mp.weixin.qq.com/s/fq2m59L_2Piqyeufl6eZFQ

0 条评论
某人
表情
可输入 255

没有评论