Jackson反序列化漏洞简介(四): 防御和检测方式【系列完结】
之前有段时间在搞jackson反序列化漏洞的检测,网上看到各种各样的文章,很多抄来抄去的,真是辣鸡,虽然我不懂,但也知道他们有些人在胡扯。本系列文章系统地介绍java里的json反序列化漏洞成因、防御方式、检测方式、利用方式。因为本人接触这些不久,如有错误,还请大佬留言指正。
本文是第四篇(最后一篇),讲下如何检测和防御。
一、检测
第一个特征是关于EnableDefaultTyping 的,注意他的多个过载方法,共有4个。
1 | ObjectMapper enableDefaultTyping() |
之前介绍了前两个,第三个我不认识,第四个是规定alias 的。所以其实这4个都是有危害的,只要匹配到,就算命中了条件A。
第二个特征是在readValue 时候,指定的类本身是Object或者里面一定要包含Object类型字段或者Object类型的setter。这里也有很多过载,主要是各种输入类型,去转为指定的Java类型,随便列出几个。
1 | public <T> T readValue(String content, JavaType valueType) |
各种各样,没有一一去验证,但底层实现应该一样,所以只要匹配到这个,就需要对第二个参数进行解析,确认这个Model是否是可以被攻击的Model。如果包含了Object或者本身就是个Object,就认为命中了条件B。
第三个特征是被反序列的类里面,有被JsonTypeInfo 注解过的类,而且里面的内容是JsonTypeInfo.Id.CLASS 或 JsonTypeInfo.Id.MANIMAL_CLASS 。记做条件C。
最终结果就是 (A&&B) C。
在实际过程中会遇到一些问题,例如开发可能会包装工具类,无法判断readValue 时第二个参数的类型,而且EnableDefaultTyping 是针对某个mapper设置,变量是很容易跟丢的,如果上污点分析,会扩散的比较严重,如果不上污点分析,又会有误报,毕竟有问题的mapper不一定会去反序列化有问题的class。
最后权衡一下,个人认为,要采取严格的策略,因为误报了也没什么关系。
首先,EnableDefaultTyping 是完全可以通过优雅的代码去规避掉的,开发者懒得写代码才会去开启这个设置,所以只要调用过这个函数就认为有危险,我认为没毛病;
其次,在Model里写Object的行为我认为是可以理解的,可能业务有这样的需求(甚至我自己写的时候,懒得写泛型,也会用类型转换),所以不可以单独作为检测点。关于第三个特征,敢写JsonTypeInfo ?这不是明显搞事情么,直接禁止使用就行了,正常人怎么会有这么奇怪的需求。
所以检测起来还是很方便的,一抓一个准,除非开发者写了不可达的代码,故意坑你。
二、防御
我不懂WAF,所以这部分可能说的不对。
我建议的是,如果数据是json,存在名为 @class (或者@c/@type)这种敏感信息的,或者存在常见gadget的字符串,直接封了就行了,正常的用户怎么会写这玩意进去。。。具体能不能通过UrlEncode来绕过,就不是本文讨论的范围的。但不建议使用WAF,从WAF上做防御不如从源头上杜绝。
另一种思路是,使用一些热更新,让开发者自己写的EnableDefaultTyping 失效,虽然这样可能让运维被骂,为毛本地可以但丢到服务器上就跑不起来,但。。。。这关我屁事。。。开发自己懒得写代码,还怪我咯?
当然,最重要的防御,就是升级到最新版。因为jackson在反序列化时,会帮助我们封掉一些gadget,每个版本都会比之前的更加全一点,因为每出CVE,官方都会尽快进行一次发布,将这个gadget添加到黑名单里,一旦反序列化到黑名单的类,就直接终止,抛异常,防止发生危害。
三、总结
完结,最后再骂一下网上的某些劣质文章,自己不动手就出来瞎bb,拿个exp打成功了就算是理解了,特征也不总结,洞也不修,这种人是不适合搞安全的。