序言
1.自1.2.25起Autotype自动关闭
2.增加checkAutoType方法,采用黑名单与白名单机制
可以看到1.2.25多了一条checkAutoType处理,并且默认了autoTypeSupport为false。
先经过白名单判断,若在白名单中则进行loadClass加载,之后再进行一个黑名单,若在黑名单中则抛出异常。
内置白名单为空,黑名单如下
JdbcRowSetImpl在黑名单内,于是抛出异常
在后续的修复与绕过的拉扯主要就是围绕checkAutoType这个函数展开。
Fastjson 1.2.25-1.2.41
1 | package Test.Bypass; |
与1.2.24的原版Poc相比,也就是多了一个L和结尾的分号。为什么这样可以呢?
在TypeUtils#loadClass
中发现如果类名以[
开头 或者 L
开头和分号;
结尾,那么就会截取头尾后返回newClassName
1 | package Test.Bypass; |
Fastjson 1.2.42
在1.2.42中的黑名单采用的是hash形式
在TypeUtils
中存在加密方法,可碰撞出黑名单
github上的黑白名单项目 https://github.com/LeadroyaL/fastjson-blacklist
发现checkAutoType
中就有去掉头尾的操作
loadclass
还是没变化
因此可以通过双写来对付这两次过滤
1 | package Test.Bypass; |
Fastjson 1.2.43
在checkAutoType
多了一层判断,截胡了LL
开头的类名
还是可以用 [
在1.2.44也增加了 [ 的过滤。
Fastjson 1.2.45
1 | package Test.Bypass; |
本次绕过方式是针对黑名单的绕过,引用的是ibatis类,该类是黑名单的漏网之鱼。
通过maven导入org.apache.ibatis.datasource.jndi.JndiDataSourceFactory
也是利用set方法中的lookup可控达到JNDI注入
Fastjson 1.2.25 - 1.2.47 通杀
该方法可以绕过AutoTypeSupport,也就是说无论开启与否都能利用成功。
1 | { |
1 | package Test.Bypass; |
在checkAutoType
的判断条件中采用的是 &&
,如果让后面的TypeUtils.getClassFromMapping()
非空,那就跳出这条异常了。
由于这次@type指定的类是java.lang.Class,自然不会在checkAutoType被截胡
下面利用java.lang.Class的反序列化器对其进行反序列化
跟到MiscCodec#deserialze
,在231行调用parse()
方法
发现会获取我们传入的恶意类并且return返回
然后将返回的类名传给strVal
下面经过很多不等的if后,在Class.class
处进入分支,调用了TypeUtils#loadClass
进到TypeUtils#loadclass
,默认cache
为true,所以将JdbcRowSetImpl
缓存到mapping
中
然后返回到DefaultJSONParse
,再进入checkAutoType
我们这里没有LL 和 ; 所以前面的过滤没用,还是看这条判断
最后直接绕过判断跳出异常,从mapping
的缓存中获取JdbcRowSetImpl
类并返回。
后面还是invoke
反射调用set方法,不多说了。
TypeUtils#loadclass
的默认缓存cache在1.2.48中修复为默认false,无法利用。
1.2.68是目前最新版,在1.2.68引入了safemode
,打开safemode
时,@type这个specialkey完全无用,无论白名单和黑名单,都不支持autoType了。
结尾
>
参考文章
http://wjlshare.com/archives/1526#1225
https://www.cnblogs.com/nice0e3/p/14776043.html
https://github.com/LeadroyaL/fastjson-blacklist
https://p3rh4ps.top/index.php/2021/03/07/fastjson%e7%9a%84%e7%bb%95%e8%bf%87%e5%8f%b2/