
前言
上篇文章主要说一下CB链的利用流程,这次继续分享各位师傅都玩烂的CC1链,这个链子我之前看了一些分析文章,大部分都是分析yso的cc1链,我看部分文章还有CC1链的另一种利用方式,虽然关键的利用点都一样,但我的学习目的也是打基础,所以能多看就多看,CC1链在利用链里还是至关重要的,之后的链子其实也是不断拆解拼接。我这里是分成两篇文章来分析两种利用方式,话不多说,我们开始分析。
一、利用链流程
老规矩,画了一张流程图,供大家参考。如图所示,这里我将从下往上分为三部分来讲解利用链流程
Transformer接口->制作链式调用恶意方法
InvokerTransformer/任意调用
ConstantTransformer/获取对象
ChainedTransformer/封装链式
TransformedMap->套娃触发ChainedTransformer.transform
AnnotationInvocationHandler->readObject触发TransformedMap
二、Transformer接口
这里需要说Transformer三个实现类,InvokerTransformer、ConstantTransformer、ChainedTransformer。
我不太想脱离分析流程按照顺序讲解三个类的原理在拼接。我为了更好的梳理思路,我们进行potato链式讲解(自定义)。
我们首先来看一下Transformer接口。
接口没什么特别的,做了个transform方法。我们看一下接口的实现类。这个InvokerTransformer就是我们这条利用链的触发点,我们进入这个类看一看。
1.InvokerTransformer
首先我们跟进transform方法,我们可以看到这个方法将传入的对象反射方法,然后执行方法,这就是个任意方法调用了。
我们看上图可以知道,transform可以进行任意方法调用,我们看一下iMethodName、iParamTypes、iArgs是怎么赋值的,我们跟进构造函数。
OK,参数全部可控,这样我们就可以进行直接写个任意方法执行了。
Runtime类分析
我想了想,还是说一嘴Runtime的问题,师傅们别嫌我啰嗦哈。
首先我们知道我们一般执行命令是通过Runtime.getRuntime().exec("command");执行命令的,而Runtime是一个单例模式,我们是没办法直接创建的,所以我们都是通过getRuntime去获取然后执行exec方法。
所以我们这里想要实现InvokerTranformer,通过getRuntime获取就可以了。
我们知道Runtime是无法序列化的,但是InvokerTransformer可以任意执行方法,我们只需要将反射的反射通过InvokerTransformer的格式去调用就OK了,
2.ChainedTransformer
我们根据上面InvokerTransformer可以看出,这个相当于InvokerTransformer一层一层的调用,也就是链式调用,所以这就引出了我们这里说的Transformer接口的第二个实现类ChainedTransformer,我们跟进去这个类看一看。
我们看到它写了个循环,应该也叫递归吧,他的transform就是一层一层的调用,然后我们在通过Runtime.class触发就可以了。我们接下来看一下它的构造函数。
chainedTransformer.transform(Runtime.class);
这里我们就明白了,我们只需要将需要执行的方法通过链式的形式写到Transformer里面就可以了,其实就是个链式调用。但是我们触发的话还需要传一个Runtime.class,当然你将传入transform(Runtime.classs)的链在放一个里面也行,还有更美观的一个方法,就是Transformer接口的第三个实现类ConstantTransformer。
3.ConstantTransformer
其实用这个实现类的目的就是将Runtime.class返回放到chainedTransformer的链子里面,其实这个不是利用链的关键。我们跟进这个类看一看吧
可以这个实现类将我们传入的对象通过transform原封不动的返回了,这样我们就可以和InvokerTransformer一起封装到ChainTransformer链里面了。
至此为止我们Transformer接口分析结束,简单总结一下就是通过InvokerTransformer制作runtime类的反射,ConstantTransformer传入runtime.class制作链的触发,chainTransformer将链封装起来。
三、TransformedMap
我们现在已经封装好了利用的chainTransformer链子,接下来我们看看都谁调用了Transformer,我们定位到了TransformedMap方法。
我们跟进checkSetValue()方法,protected权限,我们进行跟进看看valueTransformer如何设置
跟进TransformedMap()构造方法,protected权限,继续向上跟进
我们可以看到decorate方法最后将valueTransformer传到下面,且参数可控。
根据上面的分析,我们得知valueTransformer可控,我们只需要通过调用decorate方法传入封装好的chainTransformer就ok了,我们回到刚才的checkSetValue()方法,看看都谁调用了checkSetValue()
跟进AbstractInputCheckedMapDecorator下面的静态类MapEntry的setValue()方法。我们可以看到parent为可控数据。通过传入的parent调用checkSetValue方法。
这里我们需要注意一下,TransformedMap是继承于AbstractInputCheckedMapDecorator的,这里之后会用到。
继续查看谁调用了setValue方法。最终定位到了AnnotationInvocationHandler的readobject方法。
四、AnnotationInvocationHandler
上面我定位到了AnnotationInvocationHandler的readObject方法,我们跟进分析一下。
我们可以看到readObject方法调用了setValue方法,setValue方法是通过memberValue调用的,通过memberValues.entrySet返回了映射,我们看看memberValues是怎么设置。
查看构造函数,可以看到我们其实是可以控制type、memberValues,memberValues是我们传入的可控Map,这下就明白了,但是这里我提示一个坑点,我们重新看一下readObject方法,
回到readObject,我们看代码可以知道他需要成员变量不为空,且这块你的键值需要对应你注释的参数,不然还是找不到。
由于这个类是Default类,所以我们这块通过反射构造器传入参数,传一个有参注释和一个TransformedMap(也就是TransformedMap.decorate的chaintransformer链)
接下来就清晰明了了,我们传入的TransformedMap触发了父类AbstractInputCheckedMapDecorator的setValue再触发了TransformedMap的checkSetValue,最终触发了ChainedTransformer.transform,我们跟着走一遍流程
五、断点调试利用链
首先我们传入一个有参注释和一个TransformedMap(也就是TransformedMap.decorate的chaintransformer链)
跳转到TransformedMap的父类AbstractInputCheckedMapDecorator的setValue,触发checkSetValue
接着跳转到了TransformedMap的checkSetValue,触发transform
继续向下,跳转到了ChainedTransformer的transform
开始递归InvokerTransformer,最终触发Runtime.getRuntime().exec(command)
可爱小尾巴~~~
我只是个基础很差 技术很菜 脚本小子里面的小菜鸡,文章里面有什么写的不对的地方,望师傅们多加指正,我肯定狂奔加小跑的学。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)