加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 服务器 > 安全 > 正文

如何进行Fastjson 1.2.24反序列化漏洞分析

发布时间:2021-12-16 17:35:25 所属栏目:安全 来源:互联网
导读:这期内容当中小编将会给大家带来有关怎样进行Fastjson 1.2.24反序列化漏洞分析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。 0x00 fastjson fastjson是一个非常流行的库,可以将数据在JSON和Java Object之间互相转
这期内容当中小编将会给大家带来有关怎样进行Fastjson 1.2.24反序列化漏洞分析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
 
0x00 fastjson
fastjson是一个非常流行的库,可以将数据在JSON和Java Object之间互相转换,但是在2017年官方主动爆出了fastjson的反序列化漏洞以及升级公告,这次我们就学习一下这个漏洞。
 
最终的payload会放到我的GitHub上。
 
这次使用的fastjson是1.2.23版本:
 
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.23</version></dependency>
在分析漏洞之前,我们先看下这个库都有什么样的功能,我们先创建一个User对象:
 
class User {    private int age;    public String username;    private String secret;    public int getAge() {        return age;
    }    public void setAge(int age) {        this.age = age;
    }    public String getUsername() {        return username;
    }    public void setUsername(String username) {        this.username = username;
    }    public String getSecret() {        return secret;
    }
}
我们主要关注一下从JSON还原回Object的方法,主要的API有两个,分别是JSON.parseObject和JSON.parse,最主要的区别就是前者返回的是JSONObject而后者返回的是实际类型的对象,当在没有对应类的定义的情况下,通常情况下都会使用JSON.parseObject来获取数据。
 
fastjson接受的JSON可以通过@type字段来指定该JSON应当还原成何种类型的对象,在反序列化的时候方便操作。
 
String myJSON = "{"@type":"me.lightless.fastjsonvuln.User","age":99,"username":"lightless","secret":"2333"}";
JSONObject u3 = JSON.parseObject(myJSON);
System.out.println("u3 => " + u3.get("secret"));
如果需要还原出private成员的话,还需要加上Feature.SupportNonPublicField:
 
User u3 = (User) JSON.parseObject(myJSON, User.class, Feature.SupportNonPublicField);
0x01 跟踪分析
根据官方的公告中的WAF检测方法来看,问题很有可能是因为反序列化了任意类型的class从而导致的RCE。
 
怎样进行Fastjson 1.2.24反序列化漏洞分析
 
从网上找到的payload中也能看出利用的是TemplatesImpl来执行的命令,这个在之前的JDK7u21中已经分析过了,可能还存在其他的执行命令方法,这些我们暂且不谈,主要来看fastjson的部分。
 
我们搭建一个简单的Web应用来接受用户POST过来的JSON并且进行反序列化:
 
@RestControllerpublic class IndexController {    @RequestMapping(value = "/fastjson", method = RequestMethod.GET)    public String fastjson() {        return "Hello World!";
    }    @RequestMapping(value = "/fastjson", method = RequestMethod.POST)    public JSONObject testVuln(@RequestBody String data) {
        JSONObject obj = JSON.parseObject(data, Feature.SupportNonPublicField);
        JSONObject ret = new JSONObject();
        ret.put("code", 1001);
        ret.put("data", "Hello " + obj.get("name"));        return ret;
    }
}
传入我们带有@type类型的JSON字符串并且开始调试。在JSON.parseObject处下断并开始向下跟。
 
怎样进行Fastjson 1.2.24反序列化漏洞分析
 
一开始会跟进到JSON.parse方法,并且调用了parse()方法继续进行JSON格式的匹配。继续跟进parser.parse()方法。
 
怎样进行Fastjson 1.2.24反序列化漏洞分析
 
到了这里之后,开始依次进行JSON的解析,我们传入的第一个字符是{,所以进入LBRACE这个分支中,并继续进入parseObject(object, fieldName)方法来解析对象。
 
怎样进行Fastjson 1.2.24反序列化漏洞分析
 
这个时候lexer所在的字符为",会进入下面这个分支继续解析JSON字符串,通过scanSymbol方法获取到双引号之间的字符串也就是@type
 
怎样进行Fastjson 1.2.24反序列化漏洞分析
 
之后会获取@type字段的值,并且尝试获取这个类的Class,经过一系列的判断后,调用了deserializer.deserialize(this, clazz, fieldName)方法进行反序列化。
 
怎样进行Fastjson 1.2.24反序列化漏洞分析
 
一开始没找到sortedFieldDeserializers是在什么地方生成的,想仔细跟一下代码,于是就从头到尾的看了下getDeserializer(clazz)的部分,发现是在这里生成的。这个函数的目的是获取一个可以反序列化我们通过@type指定的类的deserializer,由于预定于的列表中没有,于是会继续调用createJavaBeanDeserializer()来生成一个,实际上是调用了ParseConfig.build()方法,其中会通过反射机制获取我们指定类的一些信息,通过对method进行一些过滤,猜测出getter和setter并推出一些可能存在的field。
 
具体的猜测规则这里不展开说明了,感兴趣的话可以自行跟一下
 
紧接着就依次处理JSON字符串中的各个字段,当匹配到payload中的_tfactory字段的时候,由于我们传入的JSON字符串中是一个空的对象,进入parseField方法后,继续向下跟就会调用到JavaBeanDeserializer.deserialize()方法,在这里会为_factory创建一个TransformerFactoryImpl对象并赋值。
 
同样的,_outputProperties字段我们也是传入了一个空对象,会进入和上面相同的流程,仔细分析一下这段代码,这里是触发命令执行的关键部分。
 
怎样进行Fastjson 1.2.24反序列化漏洞分析
 
首先依然会进入parseField方法
 
怎样进行Fastjson 1.2.24反序列化漏洞分析
 
进入之后会调用smartMatch(key)方法,这个方法的主要作用是进行一些『智能匹配』,方便后续获取对应变量的getter和setter。调用后这个方法会去掉字符串中的-、删除开头的下划线等,所以当我们传入了_outputProperties的时候,实际上就给处理成了outputProperties,并返回对应的FieldDeserializer对象,之后就会调用该对象的parseField方法。进入该方法后,就会调用setValue(object, value)方法,继续跟进。
 
怎样进行Fastjson 1.2.24反序列化漏洞分析
 
跟进之后显而易见,getOutputProperties被调用了:
 
怎样进行Fastjson 1.2.24反序列化漏洞分析
 
然后就会执行我们在_bytecodes构造的恶意字节码,造成命令执行。
 
0x02 一些疑问
根据上面的流程,我们应该已经可以写出PoC了,这里就不占用篇幅展示了,直接放到了我的GitHub上。
 
一开始在构造的时候发现字节码中存在许多的不可显字符,网上公开的PoC中使用了base64来编码,感觉非常神奇,为什么fastjson会帮我们解码呢?于是构造了数组传入之后,发现fastjson在处理[B类型的数组时,会调用lexer.bytesValue(),其中的lexer就是JSONScanner,这个bytesValue()方法会自动帮我们执行一次base64解码,所以我们构造payload的时候只需要传入base64编码后的内容即可。
 
怎样进行Fastjson 1.2.24反序列化漏洞分析怎样进行Fastjson 1.2.24反序列化漏洞分析
 
至此,其实整个流程已经走完了,但是还有一点令我们非常难受,就是我们的demo中,在接收JSON的时候设置了Feature.SupportNonPublicField。默认情况下fastjson只会反序列化public的方法和属性,而我们构造的PoC中有private的成员变量_bytecodes和_name,为了给这些变量赋值,则必须要假设服务端开启了SupportNonPublicField功能。
 
而现实情况下,大部分都是parse(json)和parseObject(json)一把梭,使用这个功能的情况不是很多,这样一来就导致我们的PoC没有了良好的通用性,那么有没有解决方案呢?答案当然是有的,那就是不使用TemplatesImpl,换一种RCE的触发方式即可。在网上经过一番搜索,发现了一些可以利用的方法
 
主要是利用JNDI+RMI方法,这个可以参考之前的spring-tx.jar的反序列化问题,当时就是采用这种方式来触发的。但是调用链不太好找,这个PPT中给出了多个利用链,这里的调用链后续再进行分析,这里暂且不做验证。
 
这样一来,只要是开发同学在编写代码时,直接反序列化了用户传入的JSON,就有可能造成RCE,而攻击者也无需关心SupportNonPublicField是否开启了,危害提高了许多。
 
0x03 修复措施
在fastjson的官方补丁中,将loadClass(typeName, config.getDefaultClassLoader())替换为了config.checkAutoType(typeName),并且扩充了黑名单列表,将传入的类名与黑名单一一比较,如果发现了相同开头的类就停止反序列化。
 
// 新增的黑名单
bsh
com.mchange
com.sun.
java.lang.Thread
java.net.Socket
java.rmi
javax.xml
org.apache.bcel
org.apache.commons.beanutils
org.apache.commons.collections.Transformer
org.apache.commons.collections.functors
org.apache.commons.collections4.comparators
org.apache.commons.fileupload
org.apache.myfaces.context.servlet
org.apache.tomcat
org.apache.wicket.util
org.codehaus.groovy.runtime
org.hibernate
org.jboss
org.mozilla.javascript
org.python.core
org.springframework
可以看到绝大部分常用的类都已经被加进来了,但是如果不经常维护此名单,一旦后面出现了新的可以利用的类,很容易就绕过这个限制。
 
上述就是小编为大家分享的怎样进行Fastjson 1.2.24反序列化漏洞分析了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读