2025L3HCTF-tellmewhy详解
字数 1994 2025-09-01 11:26:10

Fastjson高版本动态代理绕过黑名单利用分析

背景介绍

在Fastjson 2.0.26及之前版本,存在一条仅依赖Fastjson的原生反序列化链,其核心是利用JsonArray类的toString方法。该方法会遍历调用其元素的任意公开getter方法,从而可以触发TemplatesImpl#getOutputProperties方法,加载恶意字节码实现代码执行。

但在Fastjson 2.0.27版本后,TemplatesImpl类被加入了黑名单,同时黑名单中的类不会被调用getter方法,导致该利用链无法直接使用。

绕过原理

虽然TemplatesImpl被禁用,但它实现了Templates接口,而该接口也定义了getOutputProperties方法。关键发现是:

  1. Fastjson的黑名单仅拦截TemplatesImpl类的方法调用
  2. 对代理Templates接口的代理类无限制
  3. 代理对象的方法调用不会被拦截

因此可以通过动态代理创建一个代理对象,通过InvocationHandler将方法调用转发到被黑名单限制的TemplatesImpl实例上,间接触发TemplatesImpl#getOutputProperties方法。

反序列化触发toString链

触发JsonArray.toString的几种方式:

  1. Xstring链HotSwappableTargetSource#equals
  2. BadAttributeValueExpException
  3. EventListenerList
  4. TextAndMnemonicHashMap

在题目环境中,BadAttributeValueExpExceptionEventListenerListTextAndMnemonicHashMap类都被过滤,因此选择Xstring链作为调用JsonArray.toString的起点。

动态代理实现

题目提供了MyProxy代理类和MyObject接口,其作用与ObjectFactoryDelegatingInvocationHandler类似:

// MyProxy代理类类似于ObjectFactoryDelegatingInvocationHandler
// MyObject接口类似于ObjectFactory接口

关键点在于MyProxyinvoke方法:

  • 如果方法名不是equalshashCodetoString
  • 会尝试使用objectFactory.getObject()方法获取对象
  • 然后通过反射method.invoke调用该对象的方法

完整利用链

  1. 通过Xstring链触发JsonArray.toString
  2. toString方法遍历调用元素的getter方法
  3. 遇到代理对象时,调用其getOutputProperties方法
  4. 代理对象将调用转发到实际的TemplatesImpl实例
  5. 触发TemplatesImpl#getOutputProperties加载恶意字节码

EXP编写要点

由于环境不出网,需要针对Solon框架打入内存马。关键步骤:

  1. 创建恶意TemplatesImpl
  2. 构建代理对象包装TemplatesImpl
  3. 构造触发链的JSON数据
  4. 处理反序列化前的条件绕过:
    • if条件绕过
    • X-Real-Ip: localhost请求头伪造

JSON解析差异利用

题目使用org.json.JSONObject而非Fastjson解析JSON,但可以利用其与Map解析的差异:

  1. org.json.JSONObject处理逗号和分号的方式相同
  2. 可以利用@type进行绕过
  3. JSONObject.length实际上是调用map.size

替代toString触发方式

另一种触发toString的链子:

AlignmentAction.writeObject -> putValue -> firePropertyChange -> JSONArray.toString

关键步骤:

  1. alignmentAction初始化时,构造函数链会调用AbstractAction.putValue
  2. 将恶意键值存入arrayTable
  3. 序列化时写入键值对数量
  4. 反序列化时读取并putValue
  5. 通过修改字节码使键冲突,确保oldValuenewValue都传入firePropertyChange
  6. 反射修改changeSupport不为null
  7. 最终触发JSONArray.toString

调用栈分析

JSONArray.toString -> 元素getter调用 -> 代理对象方法调用 -> InvocationHandler.invoke -> 
TemplatesImpl.getOutputProperties -> 字节码加载执行

防御建议

  1. 升级到最新Fastjson版本
  2. 严格限制反序列化的类白名单
  3. 对动态代理的使用进行监控
  4. 检查所有实现了Templates接口的类调用

总结

通过动态代理技术,可以绕过Fastjson高版本对特定类的黑名单限制,关键在于理解Fastjson黑名单的实现机制和动态代理的工作方式。这种利用方式展示了Java反序列化漏洞的复杂性和灵活性,也提醒开发者需要全面考虑各种可能的绕过方式。

Fastjson高版本动态代理绕过黑名单利用分析 背景介绍 在Fastjson 2.0.26及之前版本,存在一条仅依赖Fastjson的原生反序列化链,其核心是利用 JsonArray 类的 toString 方法。该方法会遍历调用其元素的任意公开getter方法,从而可以触发 TemplatesImpl#getOutputProperties 方法,加载恶意字节码实现代码执行。 但在Fastjson 2.0.27版本后, TemplatesImpl 类被加入了黑名单,同时黑名单中的类不会被调用getter方法,导致该利用链无法直接使用。 绕过原理 虽然 TemplatesImpl 被禁用,但它实现了 Templates 接口,而该接口也定义了 getOutputProperties 方法。关键发现是: Fastjson的黑名单仅拦截 TemplatesImpl 类的方法调用 对代理 Templates 接口的代理类无限制 代理对象的方法调用不会被拦截 因此可以通过动态代理创建一个代理对象,通过 InvocationHandler 将方法调用转发到被黑名单限制的 TemplatesImpl 实例上,间接触发 TemplatesImpl#getOutputProperties 方法。 反序列化触发toString链 触发 JsonArray.toString 的几种方式: Xstring链 或 HotSwappableTargetSource#equals 链 BadAttributeValueExpException 链 EventListenerList 链 TextAndMnemonicHashMap 链 在题目环境中, BadAttributeValueExpException 、 EventListenerList 和 TextAndMnemonicHashMap 类都被过滤,因此选择 Xstring链 作为调用 JsonArray.toString 的起点。 动态代理实现 题目提供了 MyProxy 代理类和 MyObject 接口,其作用与 ObjectFactoryDelegatingInvocationHandler 类似: 关键点在于 MyProxy 的 invoke 方法: 如果方法名不是 equals 、 hashCode 、 toString 会尝试使用 objectFactory.getObject() 方法获取对象 然后通过反射 method.invoke 调用该对象的方法 完整利用链 通过Xstring链触发 JsonArray.toString toString 方法遍历调用元素的getter方法 遇到代理对象时,调用其 getOutputProperties 方法 代理对象将调用转发到实际的 TemplatesImpl 实例 触发 TemplatesImpl#getOutputProperties 加载恶意字节码 EXP编写要点 由于环境不出网,需要针对Solon框架打入内存马。关键步骤: 创建恶意 TemplatesImpl 类 构建代理对象包装 TemplatesImpl 构造触发链的JSON数据 处理反序列化前的条件绕过: if条件绕过 X-Real-Ip: localhost 请求头伪造 JSON解析差异利用 题目使用 org.json.JSONObject 而非Fastjson解析JSON,但可以利用其与Map解析的差异: org.json.JSONObject 处理逗号和分号的方式相同 可以利用 @type 进行绕过 JSONObject.length实际上是调用map.size 替代toString触发方式 另一种触发toString的链子: 关键步骤: 在 alignmentAction 初始化时,构造函数链会调用 AbstractAction.putValue 将恶意键值存入 arrayTable 序列化时写入键值对数量 反序列化时读取并 putValue 通过修改字节码使键冲突,确保 oldValue 和 newValue 都传入 firePropertyChange 反射修改 changeSupport 不为null 最终触发 JSONArray.toString 调用栈分析 防御建议 升级到最新Fastjson版本 严格限制反序列化的类白名单 对动态代理的使用进行监控 检查所有实现了 Templates 接口的类调用 总结 通过动态代理技术,可以绕过Fastjson高版本对特定类的黑名单限制,关键在于理解Fastjson黑名单的实现机制和动态代理的工作方式。这种利用方式展示了Java反序列化漏洞的复杂性和灵活性,也提醒开发者需要全面考虑各种可能的绕过方式。