验证漏洞
pom.xml添加cc1
1 | <dependency> |

CC1分析
我将整个分析过程分成两部分,一部分是构造命令执行,另一部分是触发链。
命令执行
Transformer接口类,供后续其他类重写利用

ConstantTransformer
直接返回构造函数传进来的Object

InvokerTransformer

可以看到这里 用getClass()获取了类,getMethod() 获取了方法, invoke反射执行。所以这里可以通过反射执行任意类的任意方法。
Demo1:

成功利用InvokerTransformer.transform执行命令,但是这里是手动传入Runtime.getRuntime()来执行命令的,为了在反序列化时能被触发,我们还需找另一种自动构造的方法。
ChainedTransformer

可以看到在这里的chainedTransformer.transform里是可以循环触发transform,参数可控,并且第一次的值再传递给第二次调用
因此可通过其来构造一条InvokerTransformer链子。
(new class[0] 用来告诉反射getMethod找到一个无参函数, new Object[0] 是为了根据传入参数自动获取类型,这里代替Null。这里之所以放这两个东西,主要就是类似占位符,因为反射去调用getMethod()时 ,它的构造函数要求传入两个参数。)

第一行通过ConstantTransformer.transform返回java.lang.Runtime

第二行通过InvokerTransformer.transform反射取得getRuntime()
第三行通过invoke反射取得java.lang.Runtime.getRuntime()

最后一行直接反射调用exec(),并传入命令参数

触发命令链
找在什么地方能调用到ChainedTransformer的transform
TransformerMap

在decorate()中实例化了TransformedMap
在transformValue()和checkSetValue(),transformKey()有调用 transform


valueTransformer参数可控,因此可以通过TransformedMap.transformValue()来触发ChainedTransformer.transform()
再找找看什么地方有这个transformValue()的调用
在put方法中直接粗暴的就调用了

所以构造如下payload,直接Put时就执行命令

但是在反序列化漏洞环境中是从readObject()入手,所以需要另一种可以序列化构造的,在readObject()进入的payload
完整payload
接下来是通过构造红框链来触发chainedTransformer.transform()

LazyMap
LazyMap 和 TransformMap类似
只不过 TransformMap 是put方法触发,而LazyMap是get方法

看到当key不存在为空时,则会调用transform(key)方法。
将上一个payload的put改成LazyMap::get ,同样可以触发漏洞


AnnotationInvocationHandler
在D:\Java\Java1.7\JDK\jre\lib\rt.jar!\sun\reflect\annotation\AnnotationInvocationHandler.class 中 利用 AnnotationInvocationHandler组件,它是用来处理注解的其构造函数有两个参数,一个是Annotation(Target.class == 元注解类) 另一个为Map (TransformedMap)。
(JDK中,所以的注解类型都继承自这个Annotation)

重点看起readObject()

var1为传入的反序列化流,var2为该类构造函数传入的第一个Annotation值,var4为我们封装的Map链.enrtySet().iterator()



所以 最后Map链.enrtySet().iterator() 会返回AbstractInputCheckedMapDecorator.java 对象给var4,并将 Map链对象放进 parent.
要注意 如何才能保证var7不为空,从而进入if分支

已知var2为传入的注解类,var7为Map链。
从 var5 var6 var7 var4 可知 要满足var7非空得满足以下2个条件:
1.传入的var2 也就是注解类得有 member Type元素(也就是为什么传入Target.class的原因)

2.put 进map的 key值 要与 memberTypes中的Key值相同

var5是AbstractInputCheckedMapDecorator中MapEntry类,所以最后 var5.setValue相当于调用了 AbstractInputCheckedMapDecorator.MapEntry.setValue()


这里的parent即是TransformedMap,相当于TransformedMap->checkSetValue()
TransformedMap中的valueTransformer又等于chainedTrasformer链

至此,就将readObject()和前面的链联系起来了
最后模拟服务端通过 readObject 接收反序列化数据 直接RCE

1 | package CC1; |
CC1链实际中用的不多,因为有限制。
AnnotationInvocationHandler的readObject()复写这个地方在高版本是进行了改动。