10. java json 反序列化之殇

看雪编辑按:随着REST  API的流行,Json的使用也越来越多,但是其中存在的安全问题却不容忽视,特别是由于反序列化导致的远程代码执行更是威力十足。虽然此类漏洞出来已有一段时间了,并且前期的一些防御方案也随着时间的推移不再有效,但其传播仍然很广泛。在此次看雪峰会演讲中,绿盟科技网络安全攻防实验室安全研究员廖新喜为大家阐述了由Java  Json库的反序列化特性导致的RCE,议题内容涉及Gson,Jackson和Fastjson这三个最常用的Json库的序列化和反序列化讨论,并分析了这里面的安全机制,再从安全机制上发现其潜在的安全漏洞。另外,讲师还公布了部分未公开的反序列化payload。以上内容为廖新喜演讲实录,由看雪学院(微信公众号:ikanxue)整理。



廖新喜 


廖新喜(xxlegend),绿盟科技网络安全攻防实验室安全研究员,擅长代码审计,Web漏洞挖掘,拥有丰富的代码审计经验,曾在Pycon 2015 China大会上分享Python安全编码。安全行业从业六年,做过三年开发,先后担任绿盟科技极光扫描器的开发和开发代表。目前专注于Web漏洞挖掘、Java反序列化漏洞挖掘。曾向RedHat、Apache、Amazon和Oracle提交多份漏洞报告。2016年网络安全周接受央视专访。《谁动了我的VIP账号?》



廖新喜:这两年这个影响非常广,主持人也介绍了。我主要讲java json,也讲到Java防御。我来自绿盟科技,我叫廖新喜。首先介绍一下json,再介绍一下json安全特性,接着会介绍一下Fastjson,还会介绍一下Java反序列化防御。


主流 JSON 库



json是什么东西,就是一个大的结构,有一些键值。



Gson是谷歌公司发布的一个开源代码的json库。这是GSON的事例,讲一个对象转化为JSON,有这样一个字符串。将这个对象转换为这个字符串。



Fastjson是由阿里巴巴开发,号称速度非常快。这是一个事例。


JSON 安全特性


再看一下它的安全特性,首先我们看一下GSON,主要是用了默认的构造函数,如果没有找到的话会调用sun.misc.Unsafe生成一个实例,如果这个之内就需要程序员自己实现,需要这个基本类型就是需要反射执行调用,这一块应该不存在安全问题的,也是推荐使用的。



jackson的安全特性,无参默认构造方法,不会序列化非Public属性。这一块其实还有很多绕过,我们看一下Jackson阶层,序列化和反序列化非常相似,也需要一个无参的默认方法,也有Jackson特有的属性,它也有一个@type可以打开序列化以及反序列化的结构。



我们可以看一下json的阶层,这个阶层提供的方法就是parserconfig,主要保存这个Java一些配置,我们可以看到他在实现由javabean等等。还有parserconfig实现这个解析上下文,这就用到反序列化,反序列化实现又有几部分,我们主要应用这个Javabean。


Fastjson PoC


Fastjson PoC,一个是基于Templatelmpl,还有基于JNDI。



简单解说一下一些方法来触发,field类型是不需要的,也在那个上面放了一个Demo。构造一个Templatelmpl,各个方法里面我们实现了一个计算器,复写几个方法,看一下PoC,主要是前面加入了黑名单。



这些辅助代码,如果这些辅助代码不会触发,从这个情况下可以触发我们的恶意情况。如果说你解析的时候比如说调用fastjson,需要打开……(英文),这个其他下可以触发我们的漏洞。



为什么会触发,就涉及到fastjson会调用…首先我的这个应用调层Fastjson会实体化,会调用slmpl的方法,或者打开了之后就不需要了,最后会调用json方法。



这是整个调用栈,这个调用栈还是挺简单的。



基于JNDI,之前的时候也讲到了,对于json这一块没有想到还会可以利用起来,可以看到JNDI是什么东西,是提供两种基本方法,我们可以看一下它的图,JNDI提供一个外部接口,主要是包括MI或者IDE。如果那个里面内容是我们可以控制的,直接可以切入。比如说可以切换参数,比如说切换我们自己控制的途径,切换到SDP自己控制的服务器。



RMI的这个服务端的代码,我会创建1099的一个服务,然后把那个放到外部服务器里面,通过RMI指向那个服务,指向那个STV服务,加载那个回来,会在RMI client上执行,基本上大部分都是这样的方式。



攻击流程:首先攻击者准备Rmi服务和wed服务,攻击者将Rmi绝对路径注入Lookup方法中,受害者JNDI接口会指想空寂者控制的RMI服务器,JNDI接口向执行构造函数,把那个加载进来进行识别化,识别化的过程中就会执行我们的恶意代码。



这是另外一种类型,比如说基于Field的类型,不适用setter方法,利用hashset,比如说阶层这个序列化的机制触发的,Fastjson默认处理Set类型都是通过hashset来实现,通过equals方法触发。一般通过Pieid类型都是利用Collecton来加载的。



这是调用栈。


首先Pastjson,一个类别加入到会叫做hashset.add,最后跑到putval,再到这个加载的equals方法。我们认为那个抵制我们可以控制,可以远程加载那个类别,然后来执行。这是他们的区别。这是它的调动站。


简单来说还是很相似的,首先是parse反序列化,通过这个get的方法,然后调到Lookup再调多远程加载的机动器。这是其他的POC。这是基于springpropertypathfactoy可以把这个加载进来。这个也是C3P0的结构。这个调用站,我们前面介绍的,所有的基于GDR都是类似的结构。


看完了Fastjson PoC。我们主要讲这个json反序列化防御和Java反序列化防御,这一块对于开发者来说是最需要的。


JSON 反序列化防御


GSON基本无安全风险。



Jackson支持这个格式转换。有一个方法可以在所有地方使用了,如果说替代方案是什么,在具体类上加上jsonTypelnfo注解,这样子类也生效,在反序列化的时候,就不存在着这样的问题。


Fastjson不起用Autotype就没问题。其他的json库,因为是非主流,还是不建议使用,里面的问题更多。



这是对于json的想法,因为现在都是堵RCE的漏洞,堵远程代码执行的漏洞,但是对于DOS或者一些其他漏洞可能不是太关注,像json或者Fastjson里面有很多的漏洞,但是没有精力关注。像实现类和自动串以及二进制结构会存在这样或者那样的风险。


Java 反序列化防御


主要从三个方面来讲:1、过时的建议。2、错误的建议。3、正确的建议。



这是反序列化利用时序图,整个反序列化利用的过程。


首先我们解释一下Java应用,这一块就会实现类的实现化。像我们现在的主流机制,阻止这种方案都是在这一块实行的,其实他有很多这样的接口,这个接口的话还包括resolveproxyclas。据说很多接口都会利用到那个一些接口,很多方法都会利用到。这个时候就返回,返回之后强制转换,这个时候其实相对来说已经过时了。因为前面已经去完成了我的反序列化了。最后,会有一个垃圾回收机制。


我们也可以看到Gadget还是非常多的,如果要防御的话怎么防御呢?首先是在实地化之前可能把类别阻拦,另外实地化之后,如果说这个Gadget是第三方库要以来依赖于,把这个一些方法之前加上白名单或者黑名单的控制,这样可以实现第三方库以及自己一些黑名单的控制,这是整个反序列化利用过程主流方案,目前也是如此。


过时的建议都是我从网上抄下来的,这个过时的建议当时是2015年,现在有两年多的时间了,大家当时都是按照这样方法做的防御,但是这种方法现在来看是过时了。


第一种方法,使用Serialkiller替代进行序列化操作的objectinputstream类。另外,建议临时删除项目库,这是我们常常用的commmons而,这是所有反序列化出现最多的,这种建议还是被大家广泛传播,也没有说改变的趋势,因为搜索引擎都收录了。



还有使用grep的方法把那个commons方法删除了,我们看一下这个方法为什么是无效的呢?因为POC出现多达29种,实在太多了。


我也跟了很多种,一起POC仅仅依赖于JDK,跟第三方没有关系。还有一些问题,第三方库Gadget和应用方在打架,这不是我的问题,应用方也说这不是我的问题。到底是谁的问题呢?自从这个漏洞爆发影响面非常广了之后,大家说这是我们的问题,我们都来干。



典型的错误方案:大厂的安全编码规范,为什么拿出来讲,因为这个厂非常大,但是安全编码规范居然是错的,可想而知,很多人到现在没有理解这个反序列化漏洞。


为什么是错的?我也是推荐通过加密实现这个反序列化的机制,但是这存在一个问题主要问题,首先是反序列化,之后再解密。解密之后再得到Gadget,也是一个反序列化的过程。在第一次反序列化的时候可能存在着问题,因为这个接口的服务不光光是开在内部,可能说我是一个服务的方式来展现了出来,这种就会存在着问题。


错就错在反序列在前,解密在后。首先的话要把数据解密,解密完了之后再反序列化,不然那个数据还是被控的。我也希望这个大厂看到之后把他们的代码规范给改了。


一些其他的建议:

不要反序列化不可信的数据,反序列建议加密、签名,我们建议的话,加密签名是在之前,反序列化之后,这样反序列化的东西才不会被用户控制。比如说缓解这个漏洞的方式,给反序列化接口添加一些认证授权,还有反序列化接口只允许舰艇在本地,没有对外开通服务或者开通相应防火墙加控制。当然了,这些都是缓解。



目前业内主流方案,采用LOOK-AHeadObject,两种解决方法:一种是serialkiller还有一种是coetrost Security Contrast-Ro0。基本上出现这样一个反序列化漏洞进行更新,如果没有跟上它的脚步,就存在着问题。


2015-2017年的时间,反序列化PoC太多了,加注了很多的黑名单进来。所以说一定要紧急更新,跟上反序列化的步伐,重新提了一下,你可以使用这个方法,但是你一定要保持随着这个更新而更新。


实现方式,其实很简单。前面已经介绍了,反序列化就是在resolveclass五之前进行控制,在判断它是不是在我的黑名单里面,如果在就直接加入到黑名单里面。




还有一些其他的建议——我们升级第三方库。


刚开始Gadget或者其他应用方都不承认是自己的问题,自从这个漏洞大了之后大家都说是自己的问题,然后推出相应更新机制。一个是Apache Commens Collections,要设置一个系统参数才可以拉动,就默认存在这个漏洞。像apache Commons Fileupload,就是默认不打开,这些漏洞可以得到缓解,还有第三方的库不承认是自己的问题,有没有修改,就不提了。


还有升级JDK,它是加的一个过滤价值,在JDK86121会加入一些黑名单,把一些常用的黑名单放在里面,你也可以添加自己的白名单,这个机制还通过MRI,就是通过的这个越权加载的问题。