“ 作者:blckder02”
前言
该漏洞由浅蓝研究发现,可在特定条件下绕过 AutoType 关闭限制加载远程对象进行反序列化。
影响版本: 特定依赖存在下影响 ≤1.2.80。
漏洞公告:
https://github.com/alibaba/fastjson/wiki/security_update_20220523
Groovy 命令执行
Fastjson
1
环
境
搭建
1. Fastjson 1.2.80
2. Groovy 3.0.8
3. JDK 8u12
在 pom.xml中导入依赖:
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.80version>
dependency>
<dependency>
<groupId>org.codehaus.groovygroupId>
<artifactId>groovy-allartifactId>
<version>3.0.8version>
dependency>
漏
洞
复现
构造恶意类,要有@GroovyASTTransformation注解,并且实现ASTTransformation接口;
起一个服务端,把恶意类的 class 文件放到根目录下,再创建一个META-INF/services/org.codehaus.groovy.transform.ASTTransformation文件,在文件中写入恶意类的名称;
python -m http.server 8081
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016465.png)
POC,classpathList为远程服务端地址;
命令执行成功;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/10-1665016468.png)
POC 调试
在parseObject()中获取到第一个@type字段中的类名,带入checkAutoType();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016468.png)
从mapping中获取到了 clazz,然后返回java.lang.Exception;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016469.png)
因为java.lang.Exception是继承 Throwable 类的,所以获取到的是ThrowableDeserializer类型的deserializer;
这里目的是要利用ThrowableDeserializer.deserializer()中调用的checkAutoType()方法中第二个参数不为 null ,和 1.2.68 版本的绕过原理一样;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/5-1665016469.png)
跟进deserialze(),获取到第二个@type字段中的类名,带入checkAutoType();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/1-1665016471.png)
跟进,expectClass参数值为Throwable.class,所以expectClassFlag赋为 true;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016472.png)
然后进行黑名单校验,CompilationFailedException不在黑名单中,能顺利通过校验;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/7-1665016472.png)
因为expectClassFlag为 true, 所以在1185 行加载了CompilationFailedException,可以绕过后面对 AutoType 的校验,并且 1190 行把它添加进了 mapping;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/8-1665016473.png)
跟进到ThrowableDeserializer.deserialze(),调用了cast(),成员变量类型是ProcessingUnit;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016473.png)
跟进TypeUtils.cast(),调用castToJavaBean();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/10-1665016474.png)
获取到JavaBeanDeserializer类型的deserializer;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/2-1665016475.png)
获取到deserializer之后,把org.codehaus.groovy.control.ProcessingUnit put 进了this.deserializers,这是后面绕过 AutoType 校验的关键!
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016475.png)
1195 行进行实例化,实例化的结果是 null ;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/7-1665016476.png)
返回 null 值,调用setValue()进行赋值,由于值为 null ,抛出异常;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/8-1665016477.png)
然后进入 POC 的 catch 分支,反序列化 poc2。
获取到第一个@type字段,带入checkAutoType();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/7-1665016478.png)
因为前面 把ProcessingUnit put 进this.deserializers了,所以这里可以直接从this.deserializers中找到ProcessingUnit,返回 clazz;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/2-1665016479.png)
获取到JavaBeanDeserializer类型的deserializer,调用deserialze();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016479.png)
ref是第二个@type值JavaStubCompilationUnit,expectClass是ProcessingUnit类,带入checkAutoType();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016480.png)
跟进,expectClassFlag为true,在 1185 行加载JavaStubCompilationUnit,并且将它添加进 mapping;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016481.png)
调用JavaBeanDeserializer.deserialze();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/9-1665016482.png)
跟进调用了parseField();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/5-1665016483.png)
跟进调用了deserialze(),返回的value是 CompilerConfiguration 类型,并且把传入的远程地址赋给了classpath;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/10-1665016483.png)
117 行又把整个 CompilerConfiguration 对象赋给JavaStubCompilationUnit的config参数;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/5-1665016485.png)
在 982 行的 for 循环中,从fieldValues中获取参数值存入params[]中,因为我们只给config传了值,所以params[]只有一个参数值;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016486.png)
1044 行 new 了一个JavaStubCompilationUnit对象;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/7-1665016487.png)
JavaStubCompilationUnit 的构造方法有三个参数,第一个参数是我们自定义的,第二个参数是调用setClassLoader()获取的,第三个参数是 null;
setClassLoader()中 new 了 GroovyClassLoader 对象;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/5-1665016488.png)
跟到GroovyClassLoader的构造方法,从config中获取classpath添加进GroovyClassLoader对象;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016489.png)
返回到CompilationUnit构造方法,184 行调用了addPhaseOperations(),跟进再调用了ASTTransformationVisitor.addPhaseOperations() ;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/7-1665016490.png)
跟进addGlobalTransforms() -> doAddGlobalTransforms(),transformLoader是从JavaStubCompilationUnit对象中获取到的GroovyClassLoader;
使用getResource()从加载器中获取META-INF/services/org.codehaus.groovy.transform.ASTTransformation文件下的资源
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/5-1665016491.png)
跟进getResource(),可以看到,加载资源遵循双亲委派型,会首先委托父类加载器,委托到启动类加载器时,会从 Bootstrap classpath 对应的 jar 包或目录中加载资源;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016491.png)
getBootstrapClassPath()最终获取到的是bcp字段的值,也就是说从bcp中的 jar 包中加载资源;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016492.png)
然后调用findResources(),跟进,再调用ucp的findResources(),ucp是 URLClassPath 类型,一共会调用三次ucp.findResources(),每次的ucp都不一样;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016493.png)
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016494.png)
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/8-1665016495.png)
因为每次的类加载器不一样,所以 ucp 不一样,第三次使用的是GroovyClassLoader,而GroovyClassLoader中含有指定的classpath http://127.0.0.1:8081/,所以会从远程地址加载资源;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016496.png)
资源加载进来后,就开始逐行读取每个资源的内容,把不以#开头的行放到transformNames中;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016498.png)
循环到第三次globalServices时,transformNames中已经有四个值了;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/8-1665016499.png)
接着探测远程地址的资源,跟进hasMoreElements() -> next() -> 第二次的hasMoreElements() -> next() -> e.hasMoreElements() -> next();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/7-1665016501.png)
跟进findResource(),创建了与远程地址资源的 http 连接,设置请求头为HEAD,对远程资源进行探测;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016502.png)
然后读取远程资源,使用了URLStreams.openUncachedStream();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/1-1665016502.png)
跟进可以看到调用getInputStream(),向远程资源发起了 http 请求;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016503.png)
命令行中可以看到两次请求的记录;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/1-1665016503.png)
然后也是将远程资源中的内容读到transformNames中,这样就获取到恶意类的名称;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/10-1665016504.png)
接着下面调用addPhaseOperationsForGlobalTransforms();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016505.png)
跟进,在该方法中依次加载并实例化了transformNames中的所有类;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/1-1665016505.png)
校验了加载的类上是否含有@GroovyASTTransformation注解,所以在构造恶意类时要加上注解;
并且得实现或继承ASTTransformation接口,所以恶意类要实现ASTTransformation,然后实例化触发命令执行。
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016506.png)
jython+spring-context+postgresql 命令
Fastjson
2
环
境
搭建
1. Fastjson 1.2.80
2. jython 1.1
3. spring-context 5.0.2.RELEASE
4. postgresql 42.3.0 (42.3.0 < 版本 < 42.3.2)
在 pom.xml中添加如下依赖:
漏
洞
复现
利用org.springframework.context.support.ClassPathXmlApplicationContext来加载远程指定的 XML 配置文件,在配置文件中定义一个 bean ,bean 中通过使用 Spring EL 表达式来调用java.lang.ProcessBuilder的start()方法来执行命令。
构造 bean 文件spel.xml:
起一个服务端,把 bean 文件放在根目录下;
构造POC:
ParseException继承Exception的子类,有一个PyObject类型参数type;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016510.png)
PyConnection继承PyObject,有一个Connection类型的参数connection;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/1-1665016511.png)
PgConnection实现了Connection的子接口,构造函数中有的五个参数,连接了数据库。
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016511.png)
host、port、user、database参数值可以随便传,不影响命令执行;
socketFactory得是ClassPathXmlApplicationContext,socketFactoryArg是远程 bean 文件地址。
POC 调试
首先对a进行反序列化,原理作用和 Groovy 链一样;
获取到第一个@type的值java.lang.Exception,带入checkAutoType();
从 mapping 中获取并返回 clazz;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/5-1665016512.png)
Exception继承了Throwable,所以下面调用ThrowableDeserializer.deserialze,接着获取到第二个@type的值,带入checkAutoType(),第二个参数值不为 null;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/9-1665016513.png)
expectClassFlag为 true ,加载ParseException类并返回;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016514.png)
获取了type参数的类型,调用cast();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016514.png)
跟进到castToJavaBean(),把PyObject类型 put 进了this.deserializer,为后面绕过 AutoType 检测做准备;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016515.png)
返回的value不为 null,所以下面调用setValue()不会报错,所以不用像 Groovy 链那样使用try-catch。
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/7-1665016516.png)
然后接着反序列化b,获取到第一个@type值带入checkAutoType(),能直接从this.deserializer获取到clazz;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016517.png)
PyObject对应的deserializer类型是FastjsonASMDeserializer_1_PyObject,但还是调用的JavaBeanDeserializer.deserialze();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016517.png)
获取到第二个@type的值带入checkAutoType(),第二个参数不为 null;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/10-1665016518.png)
加载并返回PyConnection;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/2-1665016519.png)
跟进JavaBeanDeserializer.deserialze() -> DefaultFieldDeserializer.parseField() -> getFieldValueDeserilizer(),返回JavaBeanDeserializer类型;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/9-1665016519.png)
调用deserialze(),经过一堆循环,获取了下一个@type的值,带入checkAutoType(),第二个参数不为null;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/5-1665016520.png)
加载并返回PgConnection;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016521.png)
调用deserialze(),遍历到hostSpecs参数时,逐步调用到getFieldValueDeserilizer(),返回一个ObjectArrayCode类型;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/9-1665016521.png)
然后调用ObjectArrayCode.deserialze();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/8-1665016522.png)
跟进parserArray(),调用deserialze();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016523.png)
获取host和port参数值,实例化了一个HostSpec对象并返回;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/7-1665016524.png)
把HostSpec对象转换为数组类型,赋给hostSpecs参数;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016525.png)
接着调用paseField() ,跟进到 MapDeserializer.deserialze(),调用了parseObject();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016526.png)
在parseObject()中把socketFactory和socketFactoryArg的存入了 map 中;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/9-1665016527.png)
然后将info放入了fieldValues,另外几个参数赋值都差不多;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016528.png)
参数全部赋值完毕后,实例化一个PgConnection对象;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016529.png)
跟进到PgConnection的构造函数,调用了ConnectionFactory.openConnection();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/7-1665016530.png)
逐步跟进到getSocketFactory(),调用了ObjectFactory.instantiate();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016531.png)
反射获取了ClassPathXmlApplicationContext类和构造函数,最后实例化ClassPathXmlApplicationContext对象;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016532.png)
加载配置文件,实例化文件中的恶意对象。
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/2-1665016533.png)
aspectjtools 读文件
Fastjson
3
环
境
搭建
1. Fastjson 1.2.80
2. aspectj 1.8.6
在pom.xml中导入依赖:
漏
洞
复现
直接来看看网上普遍使用的POC,要分三次打:
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016535.png)
由于SourceTypeCollisionException的newAnnotationProcessorUnits参数是接口类型;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/8-1665016536.png)
会在TypeUtils.castToJavaBean()中返回一个代理对象,并不会像前两条链一样将ICompilationUnit put 进this.deserializer;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016537.png)
所以 jsonStr1 中不添加newAnnotationProcessorUnits参数,它的作用是把SourceTypeCollisionException添加进mapping,以便后面使用。
MiscCodec.deserialze()中调用了toJavaObject(),可以把 JSON对象转换成 Java 对象,然后把该参数类型 put 进this.deserializer;
MapDeserializer.deserialze()可以把传入的各参数的值赋给对应的对象;
jsonStr2 中 各类对应的deserializer如下:
Class |
deserializer |
java.lang.Class |
MiscCodec |
java.lang.String |
StringCode |
java.util.Locale |
MiscCodec |
com.alibaba.fastjson.JSONObject |
MapDeserializer |
jsonStr2 的作用就是将org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit类型 put 进this.deserializer;
同时构造 json 语法错误,使之抛出异常,进入下一个反序列化。
jsonStr3 的作用就是利用BasicCompilationUnit类中的getContents()方法来读取文件内容;
“x”:{}的作用是将BasicCompilationUnit对象序列化为 JSON 数据,否则输出结果如下:
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/1-1665016538.png)
经过分析发现,其实 jsonStr2 简化为如下代码,同样可以实现读文件。
POC 调试
获取到第一个@type的值,带入checkAutoType(),从mapping中获取并返回Exception;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016539.png)
调用ThrowableDeserializer.deserialze(),获取到第二个@type的值,带入checkAutoType(),expectClassFlag为 true,加载并返回SourceTypeCollisionException,还把SourceTypeCollisionException添加进了mapping,这是后面绕过 AutoType 关闭限制的关键;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016540.png)
然后创建并返回一个 Exception ,结束第一个反序列化。
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/5-1665016540.png)
开始对第二个字符串进行反序列化,获取到第一个@type的值,带入checkAutoType(),从this.deserializers中获取并返回Class;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016541.png)
然后调用MiscCodec.deserialze();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/8-1665016541.png)
获取到第二个@type的值,带入checkAutoType(),从mapping中获取并返回String;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/5-1665016542.png)
接着调用StringCode.deserialze(),获取到下一个@type的值,带入checkAutoType(),从mapping中获取并返回Locale;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/8-1665016543.png)
调用MiscCodec.deserialze(),获取到下一个@type的值,直接在 310 行获取到com.alibaba.fastjson.JSONObject,不用再调用checkAutoType();
接着往下就是调用MapDeserializer.deserialze();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016544.png)
获取到java.lang.String,然后调用StringCode.deserialze(),返回@type;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/1-1665016545.png)
接着分别获取后面的两个值,存入map;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016546.png)
一直返回到MiscCodec.deserialze(),调用了toJavaObject();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/3-1665016548.png)
跟进toJavaObject() -> TypeUtils.cast() -> cast() -> castToJavaBean(),获取SourceTypeCollisionException带入checkAutoType(),从mapping中获取并返回 clazz;
然后又调用castToJavaBean();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/5-1665016549.png)
跟进createInstance(),获取到ICompilationUnit[]类型的参数newAnnotationProcessorUnits,调用parseField() -> getFieldValueDeserilizer() -> getDeserializer();
因为参数是数组类型,所以得到ObjectArrayCode类型的deserializer,然后把它 put 进this.deserializer,这里的type是带[L…;字符的;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/0-1665016551.png)
调用ObjectArrayCode.deserialize(),获取到interface org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit,带入parseArray();
跟进到getDeserializer()将ICompilationUnit接口类型的deserializer put 进this.deserializer,这里就和前面两条链的目的一样,为后续绕过 AutoType 做准备;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016552.png)
然后逐步返回,到结束反序列化时,抛出了一个异常,由于构造的 json 字符串闭合不正确;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/2-1665016553.png)
接着就进入到 catch 分支,对第三个 json 数据进行反序列化。
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/9-1665016554.png)
获取到第一个@type,带入checkAutoType(),从this.deserializer中找到并返回ICompilationUnit类;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/9-1665016555.png)
接着调用deserialize(),获取到第二个@type的值,带入checkAutoType(),第二个参数不为 null;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/7-1665016556.png)
加载并返回BasicCompilationUnit,然后调用deserialize();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/1-1665016557.png)
跟进,在deserialize()中把BasicCompilationUnit类型中不为 null 的参数放到params中,然后实例化该类;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/5-1665016561.png)
最后返回JSONObject对象,到这里还没读到文件中的内容;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/6-1665016561.png)
继续跟进println(),到MapSerializer.write(),再继续跟进,看不到调试过程了;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/2-1665016562.png)
但是一直点,会跳到BasicCompilationUnit.getContents(),这里将D:/1.txt转换为 File 对象,调用了Util.getFileCharContent();
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/10-1665016563.png)
在getFileCharContent()中创建输入流,以字符数组的形式读取文件中的内容;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016564.png)
然后就是返回、输出文件内容。
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016565.png)
补丁分析
Fastjson
4
更新到 1.2.83 版本。
checkAutoType()中,在从mapping获取到 java.lang.Execption后,添加了一个校验;
如果满足expectClass为 null 、clazz不为 null 、clazz实现或继承Throwable.class、未开启 AutoTpye,那把 clazz赋为 null;
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/7-1665016565.png)
最后只能返回一个 null。
![Fastjson 1.2.80 反序列化利用链分析 Fastjson 1.2.80 反序列化利用链分析](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2022/10/4-1665016566.png)
参考链接
https://github.com/su18/hack-fastjson-1.2.80
https://y4er.com/posts/fastjson-1.2.80
https://github.com/knownsec/KCon/blob/master/2022/Hacking%20JSON%E3%80%90KCon2022%E3%80%91.pdf
原文始发于微信公众号(中孚安全技术研究):Fastjson 1.2.80 反序列化利用链分析