JAVA-不安全的反射--RCE

简介: JAVA不安全的反射造成的RCE小案例

实际上这是一个老洞了,始于2021,今天拿出来,是因为遇到了,觉得有一定的学习价值,就拿出来分享了,大佬绕过~

废话不多说,首先存在漏洞的点位是在一个叫JobInvokeUtil的类

图片.png

接下来先对代码进行一下解读

String invokeTarget = sysJob.getInvokeTarget();

invokeTarget 调用的SysJob类里面的getInvokeTarget()方法

图片.png

紧接着,String beanName = getBeanName(invokeTarget);

将invokeTarget的值传入getBeanName()方法,该方法用来截取第一个小括号并保留小括号之前的字符串,接着利用StringUtils.substringAfterLast 方法用于获取最后一个指定分隔符之前的子字符串(这里用来获取类的路径)

图片.png

String methodName = getMethodName(invokeTarget);

与上面相似,该方法用来截取第一个小括号并保留小括号之前的字符串,接着利用StringUtils.substringAfterLast 方法用于获取最后一个指定分隔符之后的子字符串(这里用来获取类的某一个方法)

图片.png

List<Object[]> methodParams = getMethodParams(invokeTarget);

此处将invokeTarget 拆分成List<Object[]> 对象,就从invokeTarget中解析出方法的参数列表

图片.png

图片.png

if (!isValidClassName(beanName))  用来判断传入的beanName是不是合法的,他的判断方法其实就是看他有几个小数点

图片.png

这里面其实是用来判断,调用的类名是spring bean的还是lib依赖包里的,如果是spring自带的,就会利用SpringUtils.getBean(beanName)获取bean,然后利用invokeMethod()去进行实例化;

如果调用的bean是外来的,就利用Class.forName反射调用外部的类然后进行实例化操作

因为该处漏洞利用需要调用外部的类,所以这里直接走else条件分支语句


这里细说一下Object bean = Class.forName(beanName).newInstance();

Class.forName(beanName)

是Java中用于动态加载类的方法。当你传递一个类的全名(包括包名)给这个方法时,它会尝试加载该类并返回该类的 Class 对象。如果类不存在或者因为其他原因无法加载,这个方法会抛出 ClassNotFoundException。


newInstance() 是 Class 类的一个方法,它用于创建一个该类的实例。但是,它有一些限制:


1.它只能用于具有无参数构造函数的类。

2.它只能用于不是抽象的类。

3.如果类的无参数构造函数是私有的,它也会失败。


于是乎我们可以知道,想要利用这里的反射去执行恶意的类,首先这个类不能是抽象的类并且他需要具有无参构造函数的类,并且无参构造函数需要有public属性


构造函数,大家可以理解为,他的函数名字和类名字是一样的,他没有返回类型、语句;在创建类对象的时候,他会被自动调用等等,而无参构造,其实就是他是空的,函数体里面没有东西,例如下面的这个Comxxxxxxxls()无参构造函数


图片.png

invokeMethod(bean, methodName, methodParams); 这个是用来调用反射的关键方法,它使用Java的反射API来动态地调用一个对象(bean)上的方法。这个方法接受三个参数:

1.Object bean:要调用其方法的对象。

2.String methodName:要调用的方法的名称。

3.List<Object[]> methodParams:一个列表,其中每个元素都是一个对象数组,表示要传递给方法的参数。

图片.png

使用StringUtils.isNotNull(methodParams)检查methodParams是否为非空。

如果methodParams非空且大小大于0,说明有参数需要传递给方法。由于我们需要利用不安全的反射,所以我们传入的参数一定不能是空的所以直接进入到if判断里面

Method method = bean.getClass().getDeclaredMethod(methodName, getMethodParamsType(methodParams));

这里可以更写为

Class.forName(“类名”).getDeclaredMethod(“方法名”, “方法参数”);

为了更加直观,笔者在这里写了一下二者之间的对比代码

图片.png

method.invoke(bean, getMethodParamsValue(methodParams));

该代码为实际执行的代码,

invoke 方法用于动态地调用 method 方法。它接受两个参数:第一个参数是调用该方法的对象(即 bean),第二个参数是一个对象数组,包含了调用该方法所需的参数值(即 getMethodParamsValue(methodParams) 的返回值)


最后两行代码加载一块,就是典型的反射调用

Class.forName(“类名”).getDeclaredMethod(“方法名”, “方法参数”).invoke(Class.forName(“类名”).newInstance(), “参数”);


对比完整代码如下

图片.png

图片.png

可以看到,二者几乎没有区别,那么思路正确


由于代码是扣的,所以源项目跑不起来,但是不要紧,笔者在本地魔改了一下代码,方便给大家展示节目效果

首先笔者创建了一个SysJob类,该类仅仅是为了传递invokeTarget参数

图片.png

接着是第二个类,JobInvokeUtil类,该类仅仅是为了传递参数,执行反射

图片.png

我们动态调试一下,验证我们的思路

大家可以很直观的看到,beanName、methodName以及methodParams,其中methodParams是一个list object类型,里面主要有两个参数,一个是方法传递的参数,一个是方法的类型

图片.png

进入bean判断,很明显我们是调用的外部的类,所以进入到else分支

图片.png

跟进 invokeMethod方法

图片.png

首先利用getClass()方法获取字节码对象,因为bean已经被实例化了,不能直接利用 getDeclaredMethod()方法获取里面的单个方法,所以需要先getClass()获取字节码,然后再getDeclaredMethod()获取某个特定的方法;由于getDeclaredMethod()方法是java内置的方法,所以这里就省略了getMethodParamsType(methodParams)是怎么来的,getDeclaredMethod()传递两个参数,一个是方法名,一个是方法参数

图片.png

invoke 方法用于动态地调用 method 方法。它接受两个参数:第一个参数是调用该方法的对象,第二个参数是调用该方法所需的参数值

图片.png

算了,还是简单看一下getMethodParamsType(methodParams)和getMethodParamsValue(methodParams)吧

getMethodParamsType(methodParams),其实就是获取List<Object[]对象里的下标为1的参数

图片.png

getMethodParamsValue(methodParams) 其实就是获取List<Object[]对象里的下标为0的参数

图片.png

再对比下图,想必大家就明白了吧

图片.png

再给大家打印一下

图片.png

而原始代码里,其实也过滤了一下东西

图片.png

不允许调用rmi/ldap/http/https 但是他其实是调的字符串,直接用curl就行了,远程下载的地址不填http就可以,我们看一下效果

图片.png

图片.png

总结如下:

想要利用这个洞,需要找到存在危险方法的、可以传参的、存在构造函数且具备public属性的外部的类,只要输入的字符串不带http/https/rmi/ldap就行


相关文章
|
21天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
41 4
|
2月前
|
存储 Java
[Java]反射
本文详细介绍了Java反射机制的基本概念、使用方法及其注意事项。首先解释了反射的定义和类加载过程,接着通过具体示例展示了如何使用反射获取和操作类的构造方法、方法和变量。文章还讨论了反射在类加载、内部类、父类成员访问等方面的特殊行为,并提供了通过反射跳过泛型检查的示例。最后,简要介绍了字面量和符号引用的概念。全文旨在帮助读者深入理解反射机制及其应用场景。
22 0
[Java]反射
|
3月前
|
安全 Java 索引
Java——反射&枚举
本文介绍了Java反射机制及其应用,包括获取Class对象、构造方法、成员变量和成员方法。反射允许在运行时动态操作类和对象,例如创建对象、调用方法和访问字段。文章详细解释了不同方法的使用方式及其注意事项,并展示了如何通过反射获取类的各种信息。此外,还介绍了枚举类型的特点和使用方法,包括枚举的构造方法及其在反射中的特殊处理。
67 9
Java——反射&枚举
|
2月前
|
安全 Java 测试技术
🌟Java零基础-反射:从入门到精通
【10月更文挑战第4天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
26 2
|
2月前
|
安全 Java 编译器
Java 泛型深入解析:类型安全与灵活性的平衡
Java 泛型通过参数化类型实现了代码重用和类型安全,提升了代码的可读性和灵活性。本文深入探讨了泛型的基本原理、常见用法及局限性,包括泛型类、方法和接口的使用,以及上界和下界通配符等高级特性。通过理解和运用这些技巧,开发者可以编写更健壮和通用的代码。
|
3月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
3月前
|
安全 Java API
java安全特性
java安全特性
29 8
|
2月前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
17 0
|
3月前
|
安全 Java API
【性能与安全的双重飞跃】JDK 22外部函数与内存API:JNI的继任者,引领Java新潮流!
【9月更文挑战第7天】JDK 22外部函数与内存API的发布,标志着Java在性能与安全性方面实现了双重飞跃。作为JNI的继任者,这一新特性不仅简化了Java与本地代码的交互过程,还提升了程序的性能和安全性。我们有理由相信,在外部函数与内存API的引领下,Java将开启一个全新的编程时代,为开发者们带来更加高效、更加安全的编程体验。让我们共同期待Java在未来的辉煌成就!
71 11
|
3月前
|
Java 程序员 编译器
Java的反射技术reflect
Java的反射技术允许程序在运行时动态加载和操作类,基于字节码文件构建中间语言代码,进而生成机器码在JVM上执行,实现了“一次编译,到处运行”。此技术虽需更多运行时间,但广泛应用于Spring框架的持续集成、动态配置及三大特性(IOC、DI、AOP)中,支持企业级应用的迭代升级和灵活配置管理,适用于集群部署与数据同步场景。