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都是会自动调用这三个类的对应参数的构造方法。
参考文章: