SnakeYaml反序列化
YAML是一种可读性高,用来表达数据序列化的格式。YAML是”YAML Ain’t a Markup Language”(YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML的意思其实是:”Yet Another Markup Language”(仍是一种标记语言),但为了强调这种语言以数据为中心,而不是以标记语言为重点,而用反向缩略语重命名。
YAML基本格式要求:
- YAML大小写敏感。
- 使用缩进代表层级关系。
- 缩进只能使用空格,不能使用TAB,不要求空格个数,只需要相同层级左对齐(一般2个或4个空格)。
Java 常见用来处理 yaml 的库就是SnakeYaml,实现了对象与 yaml 格式的字符串之间的序列化和反序列化。SnakeYaml是一个完整的YAML1.1规范Processor,支持UTF-8/UTF-16,支持Java对象的序列化/反序列化,支持所有YAML定义的类型。
依赖
jdk8u66
1 | |
yaml的基本用法
SnakeYaml提供了Yaml.dump()和Yaml.load()两个函数对yaml格式的数据进行序列化和反序列化。
- Yaml.load():将yaml转换成java对象
- Yaml.dump():将一个对象转化为yaml
先写一个User类
1 | |
然后测试类
1 | |
运行的结果:

说明在yaml序列化的时候,即调用yaml.dump方法的时候,会调用目标类的getter方法。
然后在yaml反序列化的时候,即调用yaml.load方法的时候,会调用目标类的setter方法。
序列化的结果前面的!!是用于强制类型转化,强制转换为!!后指定的类型,其实这个和Fastjson的@type有着异曲同工之妙,用于指定反序列化的全类名。
所以yaml利用链的点跟fastjson很像,都是会调用指定类setter方法导致安全隐患。
JdbcRowSetImpl利用链
这里和fastjson的触发一致,都是触发setAutoCommit方法,调用connect函数,然后触发InitialContext.lookup(dataSourceName),而dataSourceName可以通过setDataSourceName方法可控。
详细链子分析可以看我之前的fastjson反序列化的分析文章。
payload:
1 | |

Spring PropertyPathFactoryBean利用链
这个链子需要springframework依赖
1 | |
注意setBeanFactory方法:

这里可以调用到任意类的getBean()方法,这里调用的是org.springframework.jndi.support.SimpleJndiBeanFactory#getBean()触发JNDI注入。
这里需要调用到getBean()方法,
1、要满足propertyPath属性不能为空,利用setPropertyPath方法设置一个就行。
2、要满足isSingleton(this.targetBeanName)返回值为true,

只需要利用setShareableResources方法,把rmi://127.0.0.1:1099/Exploit作为数组传进去就行了。
最后利用setTargetBeanName方法来添加我们的目标类地址rmi://127.0.0.1:1099/Exploit。
看看getBean方法:

再次调用了isSingleton方法这里会返回ture,进入if,调用doGetSingleton方法,这里进行了jndi查询。

payload:
1 | |

C3P0利用链
跟利用fastjson一样,还是setloginTimeout->inner->dereference这条利用链,具体请看上一篇C3P0分析文章。
payload:
1 | |
还有c3p0的hex链也是可以的。
ScriptEngineManager利用链
该漏洞基于SPI机制,关于SPI机制可以参考深入理解 Java 中 SPI 机制
SPI ,全称为 Service Provider Interface,是一种服务发现机制。JDK通过java.util.ServiceLoder动态装载实现模块,在META-INF/services目录下的配置文件寻找实现类的类名,通过Class.forName加载进来,newInstance()反射创建对象,并存到缓存和列表里面。也就是动态为某个接口寻找服务实现。
因此控制这个类的静态代码块就有机会执行任意代码了,这部分代码实现可以参考https://github.com/artsploit/yaml-payload/,
那么SPI和SnakeYaml如何联系起来呢,这里需要知道一个类javax.script.ScriptEngineManager,它的底层就利用了SPI机制https://www.runoob.com/manual/jdk11api/java.scripting/javax/script/ScriptEngineManager.html
ScriptEngineManager(ClassLoader loader) :此构造函数使用服务提供程序机制加载给定ClassLoader可见的ScriptEngineFactory的实现。 如果loader是null ,则加载与平台捆绑在一起的脚本引擎工厂
可以给定一个UrlClassLoader ,并使用SPI机制 (ServiceLoader 来提供) ,来加载远程的ScriptEngineFactory的实现类,那么就可以在远程服务器下,创建META-INF/services/javax.script.ScriptEngineFactory 文件,文件内容指定接口的实现类。
payload
1 | |
这里yaml都是会自动调用这三个类的对应参数的构造方法。

参考文章: