​YsoserialCC1利用链构造分析

Apache Commons Collections主要提供了两个类,TransformedMapLazyMap类,其可以修饰一个Map数据,当对该Map数据进行具体操作时就会触发transform过程。Apache Commons Collections反序列化的CC链主要使用的是TransformedMap类,而Ysoserial CC1链主要使用的是LazyMap类。

TransoformedMap类的关键点在checkSetValue()方法,我们构造好的含有利用代码的ChainedTransformer利用链即transformers数组会循环进入此处。

而Ysoserial CC1链使用的LazyMap类关键点在其get( )方法,会触发transform过程。

在不看CC1链具体代码之前,我们不妨先尝试构造一下这个利用链。

要想触发transform过程,此时this.factory的值就需为我们构造好的利用代码即ChainedTransformer利用链,当调用LazyMap对象的get方法时就会触发命令执行。

this.factory参数是否是可控的?

LazyMap的构造函数是受保护protected的,只有他自身或者继承他的类可以用,我们不能通过构造函数传参。但其有一个decorate()方法,其参数2为Transformer类型,因此可以利用这个方法创建一个LazyMap对象,相关代码如下:但要利用此漏洞,就需要通过网络传输payload,在服务端对我们传过去的payload进行反序列时执行代码,而该POC的关键依赖于调用lazyMap.get()方法,而这完全不可控。
因此就需要寻找一个特定的可序列化类,该类重写了readObject( )方法,并且在readObject( )中调用了lazyMapget()方法。需要注意的是,在java中如果重写了某个类的方法,就会优先调用经过修改后的方法。
Ysoserial CC1链中利用的还是在上篇文章中分析过的AnnotationInvocationHandler类,该类重写了readObject( )方法,但其并没有明确的调用get()方法,此时就使用到了动态代理。

AnnotationInvocationHandler类实现了InvocationHandler接口,其invoke( )方法,代码如下:

如上代码所示,其主要作用是当代理的对象调用toStringhashCodeannotationType时,就返回相应的结果,如果调用了其他方法,就会去执行Object var6= this.memberValues.get(var4)

那如果this.memberValues是可控的,且其为Map类型,就可以达到我们的目的,查看其构造函数,this.memberValues正好是Map类型。


目前只要可以调用AnnotationInvocationHandler实例对象的invoke方法就可以触发攻击链,导致代码执行。

前文提到每一个proxy代理实例都有一个关联的调用处理程序InvocationHandler,而invoke方法就是代理对象调用方法时的调用处理程序。

因此我们需要构造一个动态代理的对象,让其调用方法,从而触发invoke方法。

接着看AnnotationInvocationHandlerreadObject方法。


this.memberValues是可控的,当其是一个AnnotationInvocationHandler类生成的动态代理对象时,在调用entrySet()方法时,会自动去调用invoke方法,而由于其调用的不是toStringhashCode等方法,就会执行Object var6 = this.memberValues.get(var4),从而完成攻击链条,导致代码执行。
攻击链条:

反序列化数据流
执行redObject()方法
执行this.memberValues.entrySet()方法
触发InvocationHandler的invoke方法
执行invoke方法里的this.memberValues.get()
调用LayzMap的get()方法
执行get方法里的this.factory.transformer()
调用chainedTransformer的transform方法
循环调用InvokerTransformer的transform方法构造Runtime对象
执行Runtime对象的exec方法