CC链的小笔记

CC链的小笔记

本文字数:1807  阅读时长:4分钟

访客数:加载中... | 阅读量:加载中...

CC 链的小笔记

CC1

java
TransformedMap.put()
->TransformedMap.transformValue()
->ChainedTransformer.transform()
->ConstantTransformer.transform()
->InvokerTransformer.transform()

CC1 是最简单的也是最基本的利用链,原理是用 TransformedMap 对 ChainedTransformer 进行修饰,利用 TransformedMap.put () 进入 TransformedMap.transformValue () 触发 valueTransformer.transform (object)【即 ChainedTransformer.transform ()】

CC1x

java
AnnotationInvocationHandler.readObject()
->TransformedMap.setvalue()
->ChainedTransformer.transform()
->ConstantTransformer.transform()
->InvokerTransformer.transform()

CC1x 实现了让反序列化链子在服务端执行,将代码中手动 put 元素触发改为了利用 AnnotationInvocationHandler.readObject () 里面的 setvalue () 方法进行自动触发,实现数据在服务端反序列化时能自动执行链子

CC1xx

java
AnnotationInvocationHandler.readObject()
->mapProxy.entrySet().iterator()
->AnnotationInvocationHandler.invoke()
->LazyMap.get()
->ChainedTransformer.transform()
->ConstantTransformer.transform()
->InvokerTransformer.transform()

CC1xx 使用了代理,为了解决高版本 jdk 的 AnnotationInvocationHandler.readObject () 里面移除了 setvalue【好像具体原因不是这个,不过这个应该也算比较直观的部分原因】,改用 mapProxy 使用动态代理,而代理对象调用任意方法,代理的 invoke 方法都会执行。而在代理的 AnnotationInvocationHandler.invoke () 内部可以触发 this.memberValues.get (var4);【即 LazyMap.get () 内含 transform 代码】从而触发整条调用链

CC2

java
PriorityQueue.readObject()
->PriorityQueue.heapify()
->PriorityQueue.siftDown()
->PriorityQueue.siftDownUsingComparator()
->TransformingComparator.compare()
->ChainedTransformer.transform()
->ConstantTransformer.transform()
->InvokerTransformer.transform()

CC2 使用了 PriorityQueue ,在 PriorityQueue.readObject() 里按序执行方法进入 PriorityQueue.siftDownUsingComparator() 会调用进行 comparator 比较,触发 TransformingComparator.compare() 里面的 this.transformer.transform(obj1); 【即 ChainedTransformer.transform() 】触发利用

java
ObjectInputStream.readObject()
->PriorityQueue.readObject()
->PriorityQueue.heapify()
->PriorityQueue.siftDown()
->PriorityQueue.siftDownUsingComparator()
->TransformingComparator.compare()
->InvokerTransformer.transform()
->TemplatesImpl.newTransformer()
->TemplatesImpl.getTransletInstance()[进入内含加载恶意类]
->(动态创建的类)cc2.newInstance()[加载恶意类]
->Runtime.exec()

还有一种 CC2 就是将 ChainedTransformer 替换成了 InvokerTransformer 去执行 TemplatesImpl.getTransletInstance() 去加载恶意类,从而实现调用

CC3

java
AnnotationInvocationHandler.readobject()
->(proxy)lazyMap.entrySet()
->AnnotationInvocationHandler.invoke()
->lazyMap.get()
->ChainedTransformer.transform()
->ConstantTransformer.transform()
->InstantiateTransformer.transform
->TrAXFilter(构造方法)()
->TemplatesImpl.newTransformer[和CC2类似只是换了触发方法]()
->TemplatesImpl.getTransletInstance()
->TemplatesImpl.defineTransletClasses()
->(动态创建的类)cc3.newInstance()->Runtime.exec()

而 CC3 链,将上述 CC2 内 POC 里面直接反射获取 TemplatesImpl.newTransformer() ,改成了利用 InstantiateTransformertransform 方法会去使用反射实例化一个对象并且返回。而 TrAXFilter 的构造方法调用了传入参数的 newTransformer() 方法,从而达成执行 TemplatesImpl.newTransformer() 方法。

CC4

java
getTransletInstancePriorityQueue.readObject()->PriorityQueue.heapify()
->PriorityQueue.siftDown()->PriorityQueue.siftDownUsingComparator()
->TransformingComparator.compare()->ChainedTransformer.transform()
->TrAXFilter(构造方法)->TemplatesImpl.newTransformer()
->TemplatesImpl.getTransletInstance()->TemplatesImpl.defineTransletClasses()
->(动态创建的类)cc4.newInstance()->Runtime.exec()

CC4 看起来就是 CC2 和 CC3 的结合,将 CC3 通过代理和 LazyMap 执行触发改成了利用 PriorityQueue 进行触发

CC5

java
BadAttributeValueExpException.readObject()->TiedMapEntry.toString()
->TiedMapEntry.getValue()
->LazyMap.get()->ChainedTransformer.transform()
->ConstantTransformer.transform()->InvokerTransformer.transform()
->Method.invoke()->Class.getMethod()
->InvokerTransformer.transform()->Method.invoke()
->Runtime.getRuntime()-> InvokerTransformer.transform()
->Method.invoke()->Runtime.exec()

CC5 通过 BadAttributeValueExpException.readObject () 内的 valObj.toString () 触发 TiedMapEntry.toString () 里面的 this.getValue () 里面的 this.map.get () 触发 LazyMap.get ()

CC6

java
HashSet.readObject()->HashMap.put()
->HashMap.hash()->TiedMapEntry.hashCode()
->TiedMapEntry.getValue()->LazyMap.get()
->ChainedTransformer.transform()->InvokerTransformer.transform()
->Runtime.exec()

CC6 和 CC5 一样目标是触发 TiedMapEntry.getValue (),通过 HashSet.readObject () 里面进入 HashMap.put () 再进入 HashMap.hash () 再进入 TiedMapEntry.hashCode () 进入 TiedMapEntry.getValue () 再进入 LazyMap.get ()

java
java.io.ObjectInputStream.readObject()
java.util.HashMap.readObject()
java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()

这是另外一条调用链直接触发 HashMap.hash () 省略了使用 HashSet 去触发,debug 有点小毛病,设定是在 putVal 执行 hash (key) 但是在 K key = (K) s.readObject (); 处就已经执行过 hash (key) 弹计算器了,导致后续触发无法绕过 LazyMap 的 key 判断

CC7

java
hashtable.readObject()->reconstitutionPut()[内含比较代码]->LazyMap.equal()[未实现,转至父类]->AbstractMapDecorator.equal()->
->Hashmap.equal()[未实现,转至父类]->AbstractMap.equal()->LazyMap.get()->factory.transform()[触发回调]

CC7 是利用 hashtable.readObject () 内执行的 reconstitutionPut (table, key, value); 里面的 e.key.equals (key) 去进入比较从而触发 LazyMap.get ()

CB1

java
[PriorityQueue类的compare为抽象方法,PriorityQueue本身并不实现compare方法而是使用你提供的比较器来进行比较]
PriorityQueue.readObject()->BeanComparator.compare()[进入代码 PropertyUtils.getProperty(o1, this.property);触发getter,当this.property=OutputProperties触发getOutputProperties()]
 TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() ->
TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass()[加载恶意类]

CB1 是通过利用 BeanComparator.compare () 执行 getter 方法,从而进行下述触发,后面步骤类似 CC2

小结

从 CC1 到 CC7 看看链子的变化,首先是最基本的链子是用 ChainedTransformer 进行串联的,每个 CC 链基本大差不差,而触发的回调 [transform] 的方法大致有以下几种

  1. 通过 TransformedMap 修饰 ChainedTransformer,利用 AnnotationInvocationHandler.readObject () 里面的 setvalue () 触发回调
  2. 通过 MapProxy 进行代理触发 AnnotationInvocationHandler.invoke () 从而触发 LazyMap.get () 里面的回调
  3. 通过 PriorityQueue 进入比较 TransformingComparator.compare (),从而触发回调
  4. 通过 BadAttributeValueExpException. 触发 TiedMapEntry.toString () 里面的 TiedMapEntry.getValue () 进入 LazyMap.get () 里面的回调
  5. 通过 Hashset 进入 Hashset.put 触发 HashMap.hash (),触发 HashMap.hashCode () 触发 TiedMapEntry.getValue ()… [后续同上]
  6. 还可以直接触发 HashMap.hash () 直接触发调用链 [后续同上]
  7. 通过 hashtable.readObject () 进入比较逐步触发 equal 方法最后进入 LazyMap.get () [后续同上]
  8. 通过 PriorityQueue 类的 compare 利用 BeanComparator.compare () 执行 getter 方法