CommonsCollections1

CommonsCollections1

摘要:CC1

0x01 链子

注意点

  • java版本需要用jdk8u71以下,我自己调试用的是jdk1.7u80
  • commons-collections:3.1

前置知识

ConstantTransformer类:用于包装类;

InvokerTransformer类:用于调用任意方法,源码见下:

CC1

ChainedTransformer类:用于装载上面两个类实现任意命令的执行,源码如下:

CC12

可见是将Transformer数组中前一个Transformer对象作为后一个Transformer对象Transform方法的参数。

Java对象代理:

Proxy.newProxyInstance(一个ClassLorder, 需要代理的Class的数组, 用于处理代理的handler)

可以这样理解,使用了对象代理后,被代理任意类执行任意方法的控制流都会被劫持到handler的invoke方法中做处理。至于为什么要这么做,可能就需要深入理解Java的代理机制了。

正式调试

我是直接在ysoserial的GeneratePayload.java的源码中加入了调试代码:

CC15

1、sun.reflect.annotation.AnnotationInvocationHandler#readObject()先被触发;CC13

2、而后在readObject的352行触发到entrySet();

3、由于LazyMap事先被代理,控制流被导向AnnotationInvocationHandler#invoke

CC14

4、而后在invoke的78行调用lazyMap#get()触发LazyMap利用链,到此分析完毕。

0x02 ysoserial源码分析

这次比较有意思的点是ysoserial中对代理对象生成,和handler生成的方法做了一个包装,使得方法更为通用了。

比如生成代理,直接调用是

1
Map proxyMap = Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] { Map.class }, new AnnocationInvocationHandler(Override.class, LazyMap) )

而ysoserial的做法是将其包装为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()这个方法中:

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

iface.cast方法直接返回iface这个对象,亦即被代理的类。


评论