一道java web,边学边做吧。
1开局一个登录框,我最讨厌的东西,
要登陆,那就先注册,SIGN UP,发现不允许,点进去后空白,看源码得到
就算是我这种不懂的也知道这是一个接口,bp抓登陆的包,把login改成register
POST /register HTTP/1.1 Host: 94ace70a-9adf-4241-86d6-811f67d27ab0.node4.buuoj.cn:81 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0 Accept: text/plain, *:"admin"}
可以注意到这里取得的正则匹配结果是最后一个,在可以使用注释的情况下,可以构造如下payload。
{"username":"sapphire","password":"admin","role":"admin"}
登陆成功~!admin权限,那么就可以upload了,再利用任意文件读取看看upload的代码
package com.web.servlet;
import com.web.dao.Person;
import com.web.util.tools;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
@MultipartConfig
public class uploadServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String admin = "admin";
Person user = (Person)req.getSession().getAttribute("user");
System.out.println(user.getRole());
if(!admin.equals(user.getRole())) {
req.setAttribute("error", "");
req.getRequestDispatcher("../WEB-INF/error.jsp").forward(req, resp);
} else {
ArrayList fileNames = new ArrayList();
tools.findFileList(new File(System.getenv("CATALINA_HOME") + "/webapps/ROOT/WEB-INF/upload/"), fileNames);
req.setAttribute("files", fileNames);
System.out.println(fileNames);
req.getRequestDispatcher("../WEB-INF/upload.jsp").forward(req, resp);
}
req.getRequestDispatcher("../WEB-INF/upload.jsp").forward(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String admin = "admin";
Person user = (Person)req.getSession().getAttribute("user");
System.out.println(user.getRole());
if(!admin.equals(user.getRole())) {
resp.sendRedirect("/home");
} else {
if(!ServletFileUpload.isMultipartContent(req)) {
req.setAttribute("error", "");
req.getRequestDispatcher("../WEB-INF/error.jsp").forward(req, resp);
}
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(3145728);
factory.setRepository(new File(System.getProperty("java.io.tmpdir")));
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setFileSizeMax(41943040L);
upload.setSizeMax(52428800L);
String uploadPath = System.getenv("CATALINA_HOME") + "/webapps/ROOT/WEB-INF/upload/";
try {
List ex = upload.parseRequest(req);
if(ex != null && ex.size() > 0) {
Iterator var9 = ex.iterator();
while(var9.hasNext()) {
FileItem item = (FileItem)var9.next();
if(!item.isFormField()) {
String fileName = item.getName();
String ext = fileName.substring(fileName.lastIndexOf(".")).replace(".", "");
String name = fileName.replace(ext, "");
if(!checkExt(ext) && !checkContent(item.getInputStream())) {
String filePath = uploadPath + File.separator + name + ext;
File storeFile = new File(filePath);
item.write(storeFile);
req.setAttribute("error", "upload success!");
} else {
req.setAttribute("error", "upload failed");
req.getRequestDispatcher("../WEB-INF/upload.jsp").forward(req, resp);
}
}
}
}
} catch (Exception var16) {
req.setAttribute("error", "");
}
req.getRequestDispatcher("../WEB-INF/upload.jsp").forward(req, resp);
}
}
private static boolean checkExt(String ext) {
boolean flag = false;
String[] extWhiteList = new String[]{"jpg", "png", "gif", "bak", "properties", "xml", "html", "xhtml", "zip", "gz", "tar", "txt"};
if(!Arrays.asList(extWhiteList).contains(ext.toLowerCase())) {
flag = true;
}
return flag;
}
private static boolean checkContent(InputStream item) throws IOException {
boolean flag = false;
InputStreamReader input = new InputStreamReader(item);
BufferedReader bf = new BufferedReader(input);
String line = null;
StringBuilder sb = new StringBuilder();
while((line = bf.readLine()) != null) {
sb.append(line);
}
String content = sb.toString();
String[] blackList = new String[]{"Runtime", "exec", "ProcessBuilder", "jdbc", "autoCommit"};
for(int i = 0; i < blackList.length; ++i) {
if(content.contains(blackList[i])) {
flag = true;
}
}
return flag;
}
}
以下为看wp
在baseDao里有这样一段代码
public static void getConfig() throws FileNotFoundException {
HashMap map;
Object obj = new XMLDecoder(new FileInputStream(System.getenv("CATALINA_HOME") + "/webapps/ROOT/WEB-INF/db/db.xml")).readObject();
if ((obj instanceof HashMap) && (map = (HashMap) obj) != null && map.get("url") != null) {
driver = (String) map.get("driver");
url = (String) map.get("url");
username = (String) map.get("username");
password = (String) map.get("password");
}
}
其中 System.getenv(“CATALINA_HOME”) 可以使用前面的文件包含读取 /proc/self/environ 得到为 /usr/local/tomcat。因此可以尝试将 db.xml 覆盖为恶意代码后使用注册业务触发 XMLDecoder 反序列化。上传业务中还对上传的内容执行了检测。
private static boolean checkContent(InputStream item) throws IOException {
String[] blackList;
boolean flag = false;
BufferedReader bf = new BufferedReader(new InputStreamReader(item));
StringBuilder sb = new StringBuilder();
while (true) {
String line = bf.readLine();
if (line == null) {
break;
}
sb.append(line);
}
String content = sb.toString();
for (String str : new String[]{"Runtime", "exec", "ProcessBuilder", "jdbc", "autoCommit"}) {
if (content.contains(str)) {
flag = true;
}
}
return flag;
}
}
利用过程:随便传一个文件然后抓包修改如下:
因为题目提示了PrintWriter,这里就用java.io.PrintWriter
先下载冰蝎。
payload这里有两种(或者说三种),反弹shell的我就不打上来了
两种payload大同小异.
上传成功之后我们重新登录一次或者随便注册一个账号使得他触发漏洞,然后用冰蝎连接,密码默认为rebeyond,连上以后看到文件下有个readflag直接执行即可拿到flag


![每日一题 [GKCTF 2021]babycat-revenge 每日一题 [GKCTF 2021]babycat-revenge](http://www.mshxw.com/aiimages/31/439451.png)
